Skip to content

fix(clients): show a background command's ending in the turn it wakes - #601

Merged
incognitojam merged 3 commits into
mainfrom
styal/woken-turn-exit-row
Oct 1, 2026
Merged

incognitojam merged 3 commits into
mainfrom
styal/woken-turn-exit-row

Conversation

@incognitojam

@incognitojam incognitojam commented Oct 1, 2026 •

Copy link
Copy Markdown
Owner

Note

When a background command or monitor finishes while the agent is idle and wakes it, the woken turn now shows that ending inside its "Worked for…" fold, e.g. "Watch release checks ✓". The launch row in the earlier turn keeps the outcome as before.

What Changed

  • A background task's completed or failed ending now also shows as its own row in the turn where the agent learns about it, carrying the same status mark (✓ or ✗, with the result in the tooltip) as the launch row. That turn is:
    • the later turn the ending arrived during, or
    • the next turn to start, when the ending arrived while the agent was idle. With Claude Code this is the turn it starts by handing the result back to the agent.
  • The launch row keeps showing the outcome in its own turn, as fork fix(web,mobile): show background task endings on the call that started them #535 introduced.
  • No extra row for endings in their launch turn, stopped endings (killed by the agent, the user, or a session ending), or idle endings no turn has followed yet. That keeps fix(web,mobile): show background task endings on the call that started them #535's guarantee that a session-end stop cannot fold away a /compact divider.
  • Shared helper: @t3tools/client-runtime/work-log/background-exit, used by both web and mobile. The background-task-endings ledger entry is updated to match.

Why

Claude Code wakes the agent when a background command or monitor finishes. The woken turn starts without a user message, and until now its fold contained only what the agent did next, with nothing showing why the turn started. The ending was visible only as a status on the launch row, which may be far up the thread.

A read-only scan of one maintainer's local database:

  • 128 background endings arrived while the agent was idle and were followed by a turn without a user message (median 7.6s later, 90% within a minute).
  • Another 18 arrived during a later turn.

Notes

UI Changes

A synthetic Claude thread: a background watcher launched in the first turn finishes while the agent is idle, and the agent wakes into the second turn. The second turn's fold is expanded in both images.

Before After
Before: the woken turn shows only the agent's next command After: the woken turn starts with "Watch release checks" and a completed mark

Validation

  • Real data: ran the web derivation over a real thread where a "CI checks on PR UI Bugs when pinging files pingdotgg/t3code#857" monitor ended while the agent was idle. The ending row lands in the woken turn with the monitor's summary as its label, and the launch row keeps its outcome.
  • Synthetic fixture, web: in the dev app, the woken turn's fold reads "Received 1 update and ran 1 command" and lists the ending with a ✓ before the agent's command. The fold summary counts only the command. With the rule disabled, the woken turn shows only the command.
  • Focused tests:
    • New web tests cover an idle ending (no row until the next turn starts, then a row in that turn) and an ending that arrives during a later turn. New mobile feed test places the ending in the woken turn's group. All fail with the rule disabled.
    • Web and mobile tests for an idle ending followed by a user message check the ending sorts after that message, with the turn's work. Both failed before the ending took the turn's first activity time.
    • fix(web,mobile): show background task endings on the call that started them #535's tests (stopped ending in a later turn, failed ending in the launch turn, long foreground command) pass unchanged.
    • session-logic, timeline and thread-activity tests pass; typecheck passes for web, mobile and client-runtime; the ledger validator and its tests pass.
  • Not run on a device: mobile uses the same helper and is covered by the feed test.

Written by an agent (Claude Code, claude-opus-5-5).

When a background command or monitor finishes while the agent is idle, Claude hands the result back and the agent starts a new turn with no user message. The ending only showed as a status on the launch row in the earlier turn, so the woken turn gave no sign of why it started.

A completed or failed ending now also shows as its own row, with the same status mark as the launch row, in the turn where the agent learns about it: the later turn it arrived during, or the next turn after an idle ending. The launch row keeps the outcome. Endings in their launch turn, stopped endings, and idle endings no turn has followed add no row, so a session-end stop still cannot hide a compaction divider.
…hat starts its turn

An ending that arrived while the agent was idle kept its own timestamp when it moved into the next turn. When the user started that turn, the ending sorted before their message, so the turn's "Worked for" fold appeared above the message that started it. The ending now takes the receiving turn's first activity time and sorts with that turn's work.
@incognitojam
incognitojam force-pushed the styal/woken-turn-exit-row branch from ac3582b to 539d060 Compare October 1, 2026 18:54
@incognitojam
incognitojam merged commit 03c5057 into main Oct 1, 2026
24 checks passed
@incognitojam
incognitojam deleted the styal/woken-turn-exit-row branch October 1, 2026 19:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant