block / block/buzz

buzz-acp ignores `thread_replies` — new-thread instruction always forces `--reply-to`

Open
#4,699 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

`thread_replies` from a persona pack has no effect. An agent configured with
`thread_replies: false` still opens a new thread for every top-level channel message,
because `append_new_thread_reply_instruction()` unconditionally appends an `IMPORTANT:`
directive telling the model to use `--reply-to `.

This is the same class of gap as #2899 (`mcp_servers` parsed and validated but never
plumbed to the runtime).

## Why this should work

`PERSONA_PACK_SPEC.md` §10 states the behavioral config fields are the harness's job:

> The behavioral config fields in a persona's frontmatter control how the agent
> participates in Buzz conversations. **These are all Buzz-specific — the agent runtime
> has no awareness of them.**

And `thread_replies` is documented as:

> | `thread_replies` | bool | `true` | `true` / `false` | Reply in-thread when the
> triggering message is in a thread. |

Since the agent runtime is explicitly not aware of these fields, `buzz-acp` is the only
component that can honour them.

## Actual behaviour

`thread_replies` does not appear anywhere in `crates/buzz-acp`. It exists only in
`crates/buzz-persona` (parse, merge, resolve, manifest) and `crates/buzz-db`. It is
parsed, merged and validated — `buzz pack inspect` even prints `Thread replies: false` —
and then dropped.

The prompt builder in `crates/buzz-acp/src/queue.rs` takes the `else` branch for a
top-level channel message and always calls:

```rust
fn append_new_thread_reply_instruction(s: &mut String, event_id: &str) {
s.push_str(&format!(
"\nIMPORTANT: This is a new top-level message. For ordinary replies in \
this turn, use `--reply-to {event_id}` on `buzz messages send` — the \
triggering message is the thread root. Do NOT reply into any other \
(older) thread. ..."
));
}
```

There is no configuration path that suppresses this.

## Why prompting cannot fix it

We tried. Both the persona system prompt and a patched base prompt instruct the agent to
reply flat in the channel and to ignore any reply target suggested in `[Context]`. The
model still threads, and inconsistently so — flat at 13:03, threaded at 14:28 on the same
kind of question.

The reason is prompt position and specificity. The harness directive is marked
`IMPORTANT:`, carries the concrete event ID, and sits at the very end of the prompt; the
persona rule is abstract and much earlier. The concrete, closer instruction wins. Verified
in the agent's own request logs — the model received the directive and complied exactly:

```
buzz messages send --channel 29c37e15-… --reply-to cb710fe8… --content -
```

## Reproduce

1. Persona pack with `thread_replies: false`; confirm with `buzz pack inspect`.
2. Run `buzz-acp` (any agent command) subscribed to a channel.
3. Post a new top-level message in that channel — not inside a thread.
4. The reply is threaded under the triggering message.

Observed on `3d7712cc36e8da563cb1c121fc58bfc505d38496`, still present on `main` at time of
writing.

## Suggested fix

Gate the call site on the resolved `thread_replies` value. The split is already in the
right place — `append_reply_instruction()` (replying *inside* an existing thread) is
correct as-is and should keep working; only the new-thread branch needs to respect the
flag.

Note that the unit tests in `queue.rs` assert on the current wording
(`"new top-level message"`, `--reply-to `), so they would need a `thread_replies:
false` counterpart.

## Workaround

Patching `append_new_thread_reply_instruction()` at build time to emit the opposite
instruction. Works, but it means carrying a source patch against a pinned upstream commit.

Contributor guide

Open the contributing guide

Research direction

Start in crates/buzz-acp/src/queue.rs, especially the top-level-message branch that calls append_new_thread_reply_instruction(), and trace how the resolved thread_replies value is available from the persona configuration. Run the queue.rs unit tests, adding coverage for thread_replies: false. Done means false suppresses the new-thread --reply-to directive while true preserves it and existing thread replies remain unchanged.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
backend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
76/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.