Skip to content

fix(supervisor): a message that joins the running turn no longer leaves the bot busy - #71

Merged
httpsphl merged 1 commit into
mainfrom
fix/busy-after-joined-turn
Sep 30, 2026
Merged

httpsphl merged 1 commit into
mainfrom
fix/busy-after-joined-turn

Conversation

@httpsphl

Copy link
Copy Markdown
Owner

What happened

A crew's chief finished its turn but kept showing "working" (typing dots, spinner in the composer) forever. While it was between tool calls, another bot's message was delivered. Claude Code took that message up inside the running turn and closed both with a single result. The supervisor counted one turn per message written and closed one per result, so one turn was left over and the bot never went back to idle.

Fix

  • The slot keeps the uuids written and not yet replayed, plus whether a turn is open. A replay takes its uuid out and opens the turn, system/init opens it, result closes it. Busy = something waiting, a turn open, a subagent, or an approval.
  • It matches replays by uuid because /compact also gives back its output with a uuid nobody wrote (spec 8.6/19).
  • write_message now takes the line's uuid (courier, compaction, test helper).
  • Routines had the same assumption: a message joining a run's turn dropped the run. A turn now keeps every run it took up and finishes them all at its result.

Checked with the real Claude Code (2.1.284, Haiku, the daemon's flags)

  • Message written between two tool calls: replayed right after a tool result, inside the same turn, no new system/init, one result (num_turns: 5).
  • Message written during a text-only reply: its own turn (init, replay, result).
  • /compact with nothing to compact: replays the command with the uuid sent.

Recorded in spec 19; spec 7.2, 8.1, 9.1 and 20 updated.

Tests

  • New: a_message_that_joins_the_running_turn_ends_with_it, a_message_that_joins_the_runs_turn_leaves_the_run_to_it.
  • Tests that ended a turn without a replay now emit it, as Claude Code does.
  • cargo fmt, clippy -D warnings, cargo test --workspace (3 runs) pass.

Manual step (real Claude Code)

With the dev daemon, ask a bot to read several files one at a time. While it's reading, send it a second message from the chat. The bot should go back to idle (no dots, no spinner) after the single reply.

…es the bot busy

The supervisor counted one turn per message written and closed one per
`result`. Claude Code takes up a message written between two tool calls
inside the turn already running and ends both with a single `result`
(checked with 2.1.284), so the count stayed at one and the bot showed
"working" forever after a real turn.

The slot now keeps the uuids written and not yet replayed, plus whether a
turn is open: a replay takes its uuid out and opens the turn, `init` opens
it, `result` closes it. Replays with a uuid nobody wrote (the output
`/compact` gives back) only open the turn.

Routines had the same assumption: a message joining a run's turn dropped
the run, which then never finished. A turn now keeps every run it took up.

Spec 7.2, 8.1, 9.1, 19 and 20 updated with the probe results.
@httpsphl
httpsphl merged commit 7a31d34 into main Sep 30, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant