Repository navigation
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
etags — 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.
Activity
iroiro147 commentedon Aug 2, 2026
Implementation plan for maintainer review before I open the PR:
Approach
Add a new
buzz-acpCLI flag--reply-anchor thread|top-level(defaultthread, preserving current behavior exactly). The flag selects between two deterministic injected instructions informat_context_hints().Changes
crates/buzz-acp/src/config.rs
ReplyAnchor { Thread, TopLevel }with#[derive(clap::ValueEnum)]/// Reply placement for human-facing turns. #\[arg(long, default_value_t = ReplyAnchor::Thread)]summary()so journal attests the mode.crates/buzz-acp/src/queue.rs
reply_anchor: ReplyAnchorthroughformat_context_hints()(and the three caller paths at lines 1276 / 1299 / 1310).ReplyAnchor::Threadmode: current behavior —append_reply_instruction()for threads/DMs,append_new_thread_reply_instruction()for top-level channel mentions.ReplyAnchor::TopLevelmode: replace both instruction injectors with a single directive:IMPORTANT: Reply at the channel root for this turn (no --reply-to). The operator has explicitly configured this deployment to avoid threading.resolve_reply_anchor()unchanged — it already returns the correct anchor ID; the injected instruction is what translates it. In top-level mode we simply emit no anchor into the prompt even thoughresolve_reply_anchor()computed one. (Cleanest no-drift change: anchor still resolved for symmetry, just not injected.)Tests added
resolve_reply_anchortests unchanged (still thread-mode default).format_context_hintstest assertingReplyAnchor::TopLevelemits no--reply-to-anchored IMPORTANT block.Configflag parsing (clapcomb-through).Rationale
--reply-toids).threadmode; this flag picks the mode.Happy to iterate on flag naming (
--reply-mode thread|top-level,--threading on|off, etc.) if you'd prefer a different shape. Opening the PR tomorrow IST once there's a few hours of soak time for design comments.iroiro147 commentedon Aug 2, 2026
Source-level verification of the plan (now confirmed against
mainHEAD):append_reply_instruction()andappend_new_thread_reply_instruction()exist exactly as described.format_context_hints()is the single injection point for both. No intermediate layer.main.rs → Config→pool.rs::PromptContext→queue.rs::FormatPromptArgs→format_context_hints(). So plumbing one new flag cleanly means adding a field on bothPromptContextandFormatPromptArgs, plus aReplyAnchorenum +--reply-anchorCLI flag + summary entry. All single-file changes inconfig.rs,pool.rs,queue.rs. Estimated ~50 LOC net (including doc comments).Default::default()already derived onFormatPromptArgsandReplyAnchor::Threadis the natural default — so existing tests that useFormatPromptArgs::default()stay untouched.I'll open the PR tonight IST (UTC+5:30) once the design has had ~6h to soak for any maintainer pushback on naming/shape. The branch is pre-staged on my fork.
iroiro147 commentedon Aug 2, 2026
Update: I spiked the implementation and the surface area is larger than I initially estimated.
Plumbing scope confirmed:
The flag must flow through the full chain
main.rs → Config→pool.rs::PromptContext→queue.rs::FormatPromptArgs→format_context_hints()→append_*_instruction(). Each step has a struct literal to update:crates/buzz-acp/src/config.rs— addReplyAnchorenum +--reply-anchorCLI flag +Config.reply_anchorfield + constructor mapping +summary()entry. (5 edits)crates/buzz-acp/src/pool.rs— addreply_anchor_mode: ReplyAnchorfield toPromptContext+ 3 test constructors. (4 edits)crates/buzz-acp/src/lib.rs:1528— wirereply_anchor_mode: config.reply_anchorin the mainPromptContextconstructor. (1 edit)crates/buzz-acp/src/queue.rs— import +FormatPromptArgs.reply_anchor_modefield (existingDefaultderive keeps tests alive) + rename theOption<&str>local param (name collision) + 2 append_instruction fn signatures + 3 internal call-sites + format_prompt caller. (~10 edits)Net: ~20 surgical edits across 4 files, ~80 LOC. Not un-doable, but definitely not a 'quick patch'. Given the change crosses a crate API boundary (adds a public enum in
buzz_acp::config), I want a green light on the flag naming (--reply-anchor thread|top-levelvs alternatives) and crate-public API shape before committing CI to it.Branch stays shelved on my fork; I'll revisit tonight IST. If a maintainer has appetite for it earlier, feel free to land the design from above — the structure is yours to use.
iroiro147 commentedon Aug 2, 2026
Scope reduction proposal for #4227.
After two splice attempts, the full "--reply-anchor flag with threading-aware prompt axillary" runs into multi-file AST-aware work that's beyond my line-anchored editing pattern. Failing surfaces:
Option A: full implementation paired against a larger context budget and IDE-style tooling.
Option B (proposed): split into two PRs:
B preserves the issue scope, removes the monolithic review risk, and matches the codebase's incremental-verification pattern (every PR carries its own cargo check/test gate).
Awaiting maintainer ruling. If B is acceptable I can land PR-A today; PR-B scope/timing per maintainer preference.
iroiro147 commentedon Aug 2, 2026
PR-A is up: #4285
ReplyAnchorenum +--reply-anchorCLI flag (Thread=default, TopLevel)If the split approach is acceptable, I'll follow up with PR-B (the actual prompt behavior change wiring through PromptContext → FormatPromptArgs → format_context_hints).
iroiro147 commentedon Aug 2, 2026
PR-B is up: #4286
--reply-anchorthrough PromptContext → FormatPromptArgs → format_context_hintsTopLevelmode tells agent to post at channel root (no--reply-to)Threadmode (default) = current behavior, zero regression riskBoth PRs are ready for review. Split rationale: PR-A is reviewable in 2 minutes (inert config surface); PR-B carries the actual behavior change in isolation for focused review.