Skip to content

Provider protocol: launch.command is the inner ACP agent, not the process to exec — a conformant provider can ship silently inert agents #5548

Description

@jimparkins

Summary

Writing a third-party buzz-backend-* provider, I shipped a deploy that Buzz
reported as fully successful — backend_agent_id returned, last_error: null,
worktree created, process alive — and which produced a completely inert
agent
. Nothing was connected to the relay.

The cause: I exec'd launch.command as the process to run. It is actually the
ACP agent that runs under buzz-acp; the harness is what authenticates to the
relay, listens for mentions, and drives the agent over stdio. A provider is
responsible for running the harness and passing the inner agent through
BUZZ_ACP_AGENT_COMMAND / BUZZ_ACP_AGENT_ARGS.

That is a reasonable contract. The problem is that nothing states it, and
nothing can catch getting it wrong.

Why the docs didn't prevent it

docs/remote-agents.md §Launch data describes the field as:

"launch": {
  "command":      str,          // command NAME (e.g. "goose"), never a host path
  "args":         [str],        // normalized args, definition fallback applied

Read on its own, command + args reads unambiguously as the thing to
execute
. The spec does say elsewhere that agent_command/agent_args are
"the ACP agent under the harness", but the deploy contract never states that
the provider must supply the harness, and §Launch data — the section a provider
author works from — doesn't mention buzz-acp at all.

Why no test catches it

Every deploy-*.request.json fixture in
crates/buzz-backend-kubernetes/tests/fixtures/provider-wire/ carries no
launch command at all
deploy-no-owner, deploy-relay-mesh,
deploy-relay-mesh-padded, deploy-tag-image have neither launch nor
agent_command. That is correct for the Kubernetes binding, whose container
image ENTRYPOINT is the harness (§K8s Entrypoint). deploy-full-launch does
carry launch, but is only asserted structurally.

So a provider can pass the entire golden-fixture suite, satisfy [L2]
conformance as written, and still deploy agents that never connect. The layer
the bug lives in is the one the fixtures cannot reach.

Symptoms, so others can recognise it

Two runtimes, two different signatures, one cause:

  • goosegoose acp blocks on stdin, so the process lingers. ps shows a
    healthy agent, the worktree/pod looks fine, and it never responds to anything.
  • buzz-agent — exits immediately with nothing driving it, so its terminal
    disappears and it looks like a crash with no error.

In both cases Buzz's own view is a successful deploy: backend_agent_id set,
last_error: null. There is no failure to surface, because from the provider
protocol's perspective nothing failed.

Suggested fixes

Any one of these would have prevented it, roughly in order of preference:

  1. Have launch carry the resolved harness invocation — e.g. a
    harness_command field, or make command/args the full command to exec
    with the inner agent already expressed in env. Then providers cannot get
    it wrong, which is consistent with the stated rationale for the launch
    block ("A provider MUST NOT reimplement that derivation").
  2. State it in §Launch data: the provider runs the harness; launch.command
    and launch.args go to BUZZ_ACP_AGENT_COMMAND / BUZZ_ACP_AGENT_ARGS
    (comma-delimited).
  3. Add a fixture whose expected behaviour exercises the harness layer, so
    [L2] conformance means something here.

Context

Found while building an out-of-tree provider that runs Buzz agents in
Orca worktrees. Happy to send a docs PR for (2) if that is
useful.

Verified against main at 07a3c76.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions