Skip to content

v0.4.0 — plugin parity, owned servers, per-target scoping

Choose a tag to compare

@github-actions github-actions released this 07 Jul 09:00

Everything in this release came out of one dogfooding cycle: running agentstack
against a real machine with 8 CLI harnesses, and fixing what actually broke.

Plugins: adopt once, install anywhere

  • plugins adopt lifts an installed native plugin (Claude Code or Codex)
    into the manifest. Bundled skills are copied into the central library
    with plugin provenance (source, rev) recorded — the recipe survives
    native plugin updates and uninstalls instead of path-pointing into a
    versioned plugin cache. Codex auth wiring (bearer_token_env_var,
    env_http_headers) is carried through as portable ${REF} headers.
  • Satisfied natively: the harness a recipe was adopted from is satisfied
    by its still-installed native plugin. plugins status and doctor report
    it as up to date at the adopted version + rev and surface drift when the
    native plugin moves ahead — they never suggest double-installing.
  • Generated Claude Code packages no longer reference the auto-loaded
    hooks/hooks.json path from plugin.json (Claude Code treats that as a
    duplicate-hooks error that breaks the whole plugin); hook-less recipes ship
    no hooks file at all.

Servers: scoping, native keys, and app-owned config

  • Per-server targets[servers.X] targets = ["claude-code"] scopes the
    fan-out like instructions and hooks already could; targets = [] opts a
    server out entirely (how adopted plugin servers are stored, so the same
    server is never configured twice on a harness its plugin already serves).
  • Per-target extras[servers.X.extra.codex] startup_timeout_sec = 20
    passes native keys the manifest schema doesn't model through to one
    adapter, verbatim. init and adopt lift unknown config keys back into
    extras, so hand-tuned settings survive apply --write round trips.
  • Owned servers[servers.X] owner = "codex" makes the owning app's
    config the source of truth. When the app rewrites its own entry (a
    self-update), every plan refreshes the manifest from disk and fans the
    fresh values to the other CLIs — instead of proposing a downgrade.
    ${REF} values stay manifest-canonical so secrets never leak back into
    the manifest, and valid trust is re-pinned across the machine-derived
    rewrite.

Secrets & reporting

  • Secret refs are strict ${IDENTIFIER}s: shell fallback syntax
    (${VAR:-fallback}) and prompt-style placeholders (${input:key}) pass
    through verbatim and are no longer misread as manifest secrets.
  • One keychain read per ref per run; a transient read failure is retried and
    a persistent one reports as keychain read failed — distinct from not
    found
    , so a flaky keychain daemon can no longer block writes by claiming
    a stored secret is missing.
  • apply --write summaries count targets actually written ("X of Y written —
    Z blocked"), not planned changes.

Docs: README gains the plugin-parity walkthrough and owned-servers story; the
feature reference covers the new manifest fields and secret semantics; the
shipped using-agentstack skill teaches agents the new rules.