Skip to content

buzz-acp 0.5.22: [Base] and --system-prompt-file never reach claude-agent-acp (protocol v1) — every reply is then silently dropped #7375

Description

@polcar

Summary

Since upgrading buzz-acp to the binary shipped in Buzz Desktop 0.5.22, neither the compiled-in [Base] platform prompt nor the agent's own --system-prompt-file persona reaches a claude-agent-acp session. The agents run as bare Claude Code sessions that receive only the per-turn <context> / <conversation-context> / <buzz-event> blocks.

The visible consequence is worse than a missing prompt: [Base] is the only place that states the delivery contract —

If your turn produced anything worth knowing, you MUST publish it. Use buzz messages send. Your reasoning and tool calls are invisible…

Without it the model answers in plain session text, the harness does not publish it (by design, see #2698), and the turn ends agent_returned outcome="ok" with nothing in the channel. Seven consecutive replies were lost this way before we noticed, across two machines and two agents.

This is the same failure class as #2698 / #5390 / #3980, but with a concrete new trigger: the prompt that used to prevent it stopped being delivered.

Impact

Silent. The unit is healthy, the turn is claimed, tool calls run, 👀/💬 reactions are published and then retracted with kind:5, and outcome="ok" is logged. Nothing distinguishes it from an agent that legitimately had nothing to say. It reads as bad agent behaviour, and we spent hours diagnosing it as such — one of our agents even reprimanded the other for "ending a turn without a message" while doing exactly the same thing for the same reason.

Environment

  • buzz-acp extracted from the Buzz Desktop 0.5.22 AppImage (previous binary: a build from 2026-08-04)
  • @agentclientprotocol/claude-agent-acp 0.70.0, Claude Code 2.1.261, node from nix
  • self-hosted relay (Postgres 17 + Redis 7 + MinIO), reached over wss://
  • systemd user units, Type=simple, config via EnvironmentFile
  • relevant env: BUZZ_ACP_SYSTEM_PROMPT_FILE set, BUZZ_ACP_SESSION_POLICY=thread, BUZZ_ACP_AGENTS=1, BUZZ_ACP_MODEL=opus[1m], BUZZ_ACP_PERMISSION_MODE left at default
  • BUZZ_ACP_NO_BASE_PROMPT is not set and --base-prompt-file is not used

Evidence

1. The prompt is in the session on the old binary and absent on 0.5.22. Counting the string operating inside the Buzz platform in the Claude Code session transcripts (~/.claude/projects/<project>/*.jsonl):

Session Binary Scope Occurrences
agent A, last session before upgrade 2026-08-04 dm / conversation 13
agent A, first session after upgrade 0.5.22 dm / conversation 0
agent B, channel turn 0.5.22 thread 0
agent B, DM turn 0.5.22 dm / conversation 0

The persona from --system-prompt-file is missing in exactly the same sessions (0 occurrences of a distinctive line from that file). On the old binary the first user message of the session begins:

[Base]
You are operating inside the Buzz platform — a Nostr-based messaging platform for human-agent collaboration.
...
[System]
<persona from --system-prompt-file>
[Agent Memory — core]
...

On 0.5.22 the first user message begins directly with <context>.

2. It is not a stripped prompt in the build. strings on the 0.5.22 binary still contains the base prompt, including the delivery-contract line, at the expected place. So the text exists and is simply not delivered.

3. The adapter negotiates protocol v1, which per #3126 is the branch where the session/new system prompt is discarded and the legacy in-band path is supposed to take over:

INFO buzz_acp: agent initialized: {... "agentInfo":{"name":"@agentclientprotocol/claude-agent-acp","version":"0.70.0"}, ... "protocolVersion":1}
INFO buzz_acp: agent initialized agent=0 name="@agentclientprotocol/claude-agent-acp" steering_supported=true

4. Relay side. Across seven turns on 0.5.22 the agents published only kind:7 (👀, 💬), then two kind:5 retractions per turn, and zero kind:9. In every one of those turns the final assistant text is present in the session transcript, so generation succeeded and only delivery never happened.

5. Behaviour matches. On the old binary the agent published every reply itself: 20 of 20 buzz messages send calls. On 0.5.22, across the same kind of turns, 0. It also stopped passing --reply-to, which the [Base] threading section governs — consistent with the whole section being absent rather than the model choosing differently.

Regression window

Worth noting for anyone hitting this: because the re-framing is older than the thread-scoped sessions, there is no released version that has --session-policy=thread and a working [Base]. 0.5.22 is currently the newest release.

Suspected cause (hypothesis — I have not read the 0.5.22 source)

Per #3126, for a protocol-v1 agent the combined session/new system prompt is built and then discarded, and prepend_base_for_legacy is the path that renders [Base] in-band. Something in the re-framing / session-scoping work appears to have left that path unreached for sessions created by the newer scoping code — both Conversation(dm) and Thread(channel, root) sessions come up without it.

Steps to reproduce

  1. Run buzz-acp from 0.5.22 with --agent-command claude-agent-acp and --system-prompt-file <persona>.
  2. @mention the agent (channel or DM).
  3. Open the resulting Claude Code session transcript and search for operating inside the Buzz platform and for any line unique to the persona file — both are absent.
  4. Ask the agent something that needs an answer. It answers in session text, publishes nothing, and the turn ends outcome="ok".

Expected

[Base] and the --system-prompt-file persona reach the session on protocol-v1 adapters, as they did before, or the harness fails loudly when it cannot deliver them.

Workaround, for anyone else hitting this

Give each agent its own working directory and put the instructions there as CLAUDE.md, which Claude Code loads from the cwd independently of the harness:

~/.agents/<name>/CLAUDE.md          # persona (same file passed to --system-prompt-file)
~/.agents/<name>/.claude/CLAUDE.md  # the delivery contract lifted from [Base]

Two caveats we measured, since both fail silently:

  • A symlinked CLAUDE.md (or .claude/CLAUDE.md) pointing outside the working directory is loaded. An @import or a .claude/rules/ entry resolving outside the working directory is not — it is treated as an external import awaiting an approval dialog that never appears in a headless run.
  • CLAUDE.md content does not appear in the session transcript, unlike the in-band [Base], so grepping the transcript is not a valid check that the workaround is live. Probe it with cd <agent dir> && claude -p '...' instead.

A per-agent directory is required rather than one shared file: CLAUDE.md is also inherited from every parent directory, so two agents sharing a working directory cannot have different personas, and anything placed in $HOME leaks into all of them.

Related

#2698 (implicit delivery contract), #5390, #3980, #4709, #5446 (same failure class), #3126 and #3124 (protocol-v1 system-prompt path), #6701, #6706, #6732 (the changes in the regression window).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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