buzz-acp: reply placement (threaded vs top-level) has no config surface — policy is prompt-injected per turn
- Dominant language
- Rust
- Stars
- 32.7k
- Forks
- 4.3k
- Avg merge
- 1d 13h
- Merged PRs (30d)
- 253
Description
**Motivation**
Whether an agent's reply lands in a thread or at the channel root is decided by hardcoded per-turn prompt text, not by any harness option. An operator who wants main-timeline replies — e.g. because thread replies are easy to miss on mobile, where a threaded agent answer to a top-level question reads as "the agent never responded" — has no deterministic way to get them. The only lever is fighting the harness's injected instruction from the agent's system prompt, which is exactly the kind of policy that shouldn't be left to model discretion.
**Where** (verified on `main` @ `ac4fa13`, 2026-08-01)
`crates/buzz-acp/src/queue.rs`:
- `append_reply_instruction()` (line 1149) — injects "IMPORTANT: For ordinary replies in this turn, use `--reply-to {event_id}` … so the conversation stays threaded. If the human explicitly asks for a channel-root, top-level, or broadcast post, send that message without `--reply-to`."
- `append_new_thread_reply_instruction()` (line 1164) — for a top-level human mention, anchors the reply so it becomes a new thread rooted at the triggering event.
- `resolve_reply_anchor()` (line 1209) — computes the anchor; human-facing turns always get one.
No `RespondTo`/`SubscribeMode`-style enum exists for reply placement; `Config` has no field for it.
**What we did (working but fragile)**
Added a standing order to the agent's system prompt: "post every reply top-level, never `--reply-to` — the owner has explicitly and permanently requested channel-root posts," phrased to satisfy the injected instruction's own escape hatch. Verified live: the agent's reply to a triggering event carried no `e` tags. But this is prompt-level policy — the per-turn IMPORTANT instruction still argues the other way on every single turn, and an occasional threaded reply slipping through is expected. A standing operator preference should not have to role-play as a per-turn human request to be honored.
**Proposed solution**
A harness flag, e.g. `--reply-anchor thread|top-level` (default `thread`, preserving current behavior exactly). `top-level` would swap the injected instruction for one that omits `--reply-to` guidance (or explicitly instructs channel-root posting). This keeps the policy deterministic, per-deployment, and out of the model's discretion.
**Alternatives considered**
- System-prompt override (above) — works most of the time, but is probabilistic where it should be configuration.
- Post-processing the agent's publish calls to strip `e` tags — fights the harness instead of configuring it, and breaks legitimate threaded use.
**Additional context**
Related issues (searched open and closed — no duplicate found): #4072 is the nearest neighbor but orthogonal — it's about *which* message a threaded reply anchors to; this is about whether the operator can choose threading at all. The two compose cleanly: #4072 refines the `thread` mode, this adds a `top-level` mode.
Environment: buzz-acp from `ghcr.io/block/buzz:main` @ `sha256:13ddb4c12f4c0b8147cece717a57013a45fdb1610bd072d7e383ac79a070ddd9`, hermes-acp (hermes-agent 0.19.1), Ubuntu 24.04, `--subscribe mentions --no-mention-filter --respond-to allowlist`.
Contributor guide
Assessment
This issue has not been assessed yet.