block / block/buzz

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

Open
#7,375 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Rust
Stars
32.7k
Forks
4.3k
Avg merge
1d 13h
Merged PRs (30d)
253

Description

## 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 `` / `` / `` 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//*.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:

```text
[Base]
You are operating inside the Buzz platform — a Nostr-based messaging platform for human-agent collaboration.
...
[System]

[Agent Memory — core]
...
```

On 0.5.22 the first user message begins directly with ``.

**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:

```text
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

- prompt re-framing landed 2026-08-26: #6701 (paired tags), #6706 (dedup)
- per-thread agent sessions landed 2026-08-31: #6732
- `[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=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 `.
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:

```text
~/.agents//CLAUDE.md # persona (same file passed to --system-prompt-file)
~/.agents//.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 && 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).

Contributor guide

Open the contributing guide

Research direction

Start at the buzz-acp entry point handling protocol-v1 sessions, especially the --system-prompt-file path and prepend_base_for_legacy around session creation. Compare the behavior and recent changes in #3126, #6701, #6706, and #6732, then reproduce with claude-agent-acp and inspect the session transcript. Done means both prompts reach the session and a normal reply is published rather than silently dropped.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
backend, cli, tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.