Describe the bug
A plain, top-level message to an agent in a 1:1 DM gets answered inside a thread rather than
inline in the DM, so the human has to open a collapsed "N replies" affordance to read a reply to
their own direct message. Nothing in the conversation asked for a thread.
This is the second half of #2748, which fixes the anchor for replies already inside a thread and
explicitly parks this part:
Worth discussing whether top-level DM exchanges should thread at all — a 1:1 DM arguably reads
best flat, with threading reserved for explicit user-initiated threads.
Filing it separately so the behavior question can be settled on its own. It is orthogonal to
#2748: the two touch different branches and neither PR (#2766, #2778) changes this path.
Steps to reproduce
- DM a managed agent (no
@mention, no thread) — e.g. "find the X repo".
- The agent answers.
- The answer is not in the DM. The DM shows the original message with a
3 replies footer, and
the answer only appears after opening the thread panel.
Expected behavior
An ordinary answer to a top-level DM arrives inline in the DM. A DM is already a private 1:1
conversation — there is nothing to keep a thread tidy for. Threads inside a DM stay reserved for
threads the human opened (or explicitly asks for), and those already anchor correctly once #2748
lands.
Root cause
crates/buzz-acp/src/queue.rs — in format_context_hints, the DM branch only emits a reply
instruction inside the if let Some(ref root) = thread_tags.root_event_id arm:
// If this is a DM reply, include thread structural info as supplementary.
if let Some(ref root) = thread_tags.root_event_id {
...
if let Some(event_id) = reply_anchor {
append_reply_instruction(&mut s, event_id);
}
}
s
A top-level DM has no thread tags, so reply_anchor is None and the [Context] block says
nothing at all about where to reply. With no destination supplied, the agent falls back to the
general rule in base_prompt.md:
The app/harness will choose the correct reply destination: the root of the triggering thread when
the turn is already threaded, or the triggering top-level event when the human started a new
thread.
…and opens a thread rooted at the DM. In a channel that rule is right — format_context_hints
emits append_new_thread_reply_instruction for exactly that case. In a DM it produces a thread
nobody asked for.
Proposed fix
Give the top-level DM case its own explicit instruction — answer inline, no --reply-to — as the
else of the existing if let Some(root) arm, mirroring how the channel branch handles its
top-level case. Threaded DM turns keep their existing instruction, so this does not touch the lines
#2766/#2778 modify.
I have this implemented and tested locally and will open a PR against this issue.
Version and platform
Desktop app on macOS (Darwin 25.4.0), self-hosted relay, desktop-managed agent, default settings.
Reproduced on main at 63c62fc.
Describe the bug
A plain, top-level message to an agent in a 1:1 DM gets answered inside a thread rather than
inline in the DM, so the human has to open a collapsed "N replies" affordance to read a reply to
their own direct message. Nothing in the conversation asked for a thread.
This is the second half of #2748, which fixes the anchor for replies already inside a thread and
explicitly parks this part:
Filing it separately so the behavior question can be settled on its own. It is orthogonal to
#2748: the two touch different branches and neither PR (#2766, #2778) changes this path.
Steps to reproduce
@mention, no thread) — e.g. "find the X repo".3 repliesfooter, andthe answer only appears after opening the thread panel.
Expected behavior
An ordinary answer to a top-level DM arrives inline in the DM. A DM is already a private 1:1
conversation — there is nothing to keep a thread tidy for. Threads inside a DM stay reserved for
threads the human opened (or explicitly asks for), and those already anchor correctly once #2748
lands.
Root cause
crates/buzz-acp/src/queue.rs— informat_context_hints, the DM branch only emits a replyinstruction inside the
if let Some(ref root) = thread_tags.root_event_idarm:A top-level DM has no thread tags, so
reply_anchorisNoneand the[Context]block saysnothing at all about where to reply. With no destination supplied, the agent falls back to the
general rule in
base_prompt.md:…and opens a thread rooted at the DM. In a channel that rule is right —
format_context_hintsemits
append_new_thread_reply_instructionfor exactly that case. In a DM it produces a threadnobody asked for.
Proposed fix
Give the top-level DM case its own explicit instruction — answer inline, no
--reply-to— as theelseof the existingif let Some(root)arm, mirroring how the channel branch handles itstop-level case. Threaded DM turns keep their existing instruction, so this does not touch the lines
#2766/#2778 modify.
I have this implemented and tested locally and will open a PR against this issue.
Version and platform
Desktop app on macOS (Darwin 25.4.0), self-hosted relay, desktop-managed agent, default settings.
Reproduced on
mainat 63c62fc.