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
- Run
buzz-acp from 0.5.22 with --agent-command claude-agent-acp and --system-prompt-file <persona>.
@mention the agent (channel or DM).
- 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.
- 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).
Summary
Since upgrading
buzz-acpto the binary shipped in Buzz Desktop 0.5.22, neither the compiled-in[Base]platform prompt nor the agent's own--system-prompt-filepersona reaches aclaude-agent-acpsession. 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 —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 withkind:5, andoutcome="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-acpextracted from the Buzz Desktop 0.5.22 AppImage (previous binary: a build from 2026-08-04)@agentclientprotocol/claude-agent-acp0.70.0, Claude Code 2.1.261, node from nixwss://Type=simple, config viaEnvironmentFileBUZZ_ACP_SYSTEM_PROMPT_FILEset,BUZZ_ACP_SESSION_POLICY=thread,BUZZ_ACP_AGENTS=1,BUZZ_ACP_MODEL=opus[1m],BUZZ_ACP_PERMISSION_MODEleft at defaultBUZZ_ACP_NO_BASE_PROMPTis not set and--base-prompt-fileis not usedEvidence
1. The prompt is in the session on the old binary and absent on 0.5.22. Counting the string
operating inside the Buzz platformin the Claude Code session transcripts (~/.claude/projects/<project>/*.jsonl):The persona from
--system-prompt-fileis 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:On 0.5.22 the first user message begins directly with
<context>.2. It is not a stripped prompt in the build.
stringson 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/newsystem prompt is discarded and the legacy in-band path is supposed to take over:4. Relay side. Across seven turns on 0.5.22 the agents published only
kind:7(👀,💬), then twokind:5retractions per turn, and zerokind: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 sendcalls. 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
[Base]was still delivered by a build from 2026-08-04; it is not delivered by 0.5.22 (tagged 2026-09-04)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=threadand 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/newsystem prompt is built and then discarded, andprepend_base_for_legacyis 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 — bothConversation(dm)andThread(channel, root)sessions come up without it.Steps to reproduce
buzz-acpfrom 0.5.22 with--agent-command claude-agent-acpand--system-prompt-file <persona>.@mentionthe agent (channel or DM).operating inside the Buzz platformand for any line unique to the persona file — both are absent.outcome="ok".Expected
[Base]and the--system-prompt-filepersona 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:Two caveats we measured, since both fail silently:
CLAUDE.md(or.claude/CLAUDE.md) pointing outside the working directory is loaded. An@importor 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.mdcontent 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 withcd <agent dir> && claude -p '...'instead.A per-agent directory is required rather than one shared file:
CLAUDE.mdis also inherited from every parent directory, so two agents sharing a working directory cannot have different personas, and anything placed in$HOMEleaks 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).