Files
buzz/docs
morgmartandClaude 0261e344d0 fix(agents): stop the Welcome intro loop with an ack that costs nothing
Observed with Codex on a fresh Welcome channel: Fizz, Honey, and Bumble
reply to each other 21+ times, each message announcing it will now stop
replying, each announcement waking the others.

A mention is a wake (p-tag gated), so the only way an agent could say
"seen" was to summon someone. Combined with an unconditional MUST in the
shared base prompt, that has no exit:

  :44 you MUST @mention the delegator when you finish delegated work

"I won't reply again" is itself a summons. Note :40 already said "only
@mention when you need their attention" -- and they still looped, because
a soft "only when" loses to a hard MUST two lines below it. Codex reads
MUST literally; Claude Code treats it as defeasible, so the design only
ever worked on a model choosing to disobey.

Fix it in the base prompt rather than the personas (3 copies to drift) or
team instructions (Welcome-team only). Three bullets, all in Callback
Mentions:

- Bound the callback: it hands work back, is sent once, and a delegator
  can waive it. The unconditional MUST itself is kept -- stalled
  collaboration is the worse failure.
- Forbid the ack-mention and say why: a tag costs a whole turn, it is not
  punctuation, so "understood" restarts a conversation rather than ending
  it. A literal model needs the mechanism, not just the rule.
- Point at reactions as the outlet: "to acknowledge, use a reaction
  instead" (buzz reactions add). This is the load-bearing part. It
  redirects rather than suppresses, and it keeps the human-visible social
  signal so the fix does not read as stalling. The command already
  existed and is already in the command table; the prompt just never
  connected it to acking.

:61 ("every turn MUST publish a reply") is deliberately left alone. It is
not load-bearing: a loop needs a wake, wake is p-tag gated, and :61 forces
a reply rather than a tag -- an untagged reply ends the chain. It governs
noise, not the loop, and weakening "always reply" trades toward the silent
failures this doc already tracks. Corroborated by another Buzz agent
running this same base prompt including :61, plus a core memory saying
almost exactly the bullets above; it does not loop.

Also considered and rejected: a structural cap on consecutive
agent-authored turns. It cannot distinguish a loop from a long-running
task where agents legitimately trade many messages, so it would truncate
real work.

Fizz's opener is reduced to a plain welcome: an em dash becomes a sentence
break, and "Don't start any work yet" is dropped -- nothing has been asked
for yet, so it guarded against nothing concrete. An anti-loop instruction
there would work, but the opener is the first thing a new user reads and
should not advertise that the product needs prompting to behave; it would
also confound the test by suppressing the loop in this one channel while
proving nothing about the base prompt. A test pins the absence of
agent-steering instructions so re-adding one is a deliberate decision.

Also corrects the doc's rate-limit note. "rate-limited: quota exceeded" is
the relay rejecting a publish (buzz-relay/src/connection.rs:652), and
buzz-acp has no publish retry/backoff, so the tight-retry-loop theory was
unsupported. A rejected send produces no event, no p-tag, no wake -- it
breaks the loop rather than feeding it. Rate limiting is downstream; the
two can be fixed independently.

Not verified live. The prompt change is behavioral and needs a real Codex
session on a fresh Welcome channel.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-18 15:53:48 -07:00
..