Ignore background tasks that workflow agents start in the Claude bridge - #2434
Merged
SawyerHood merged 1 commit intoAug 25, 2026
Merged
Conversation
The CLI reports every background task on the parent session, including tasks a workflow agent starts, but it never forwards that agent's tool_use blocks. The bridge keyed the task on tool_use_id alone, so the assembler minted a parent id no item ever claimed, the projection treated the orphan as the parent's own command, and task_started opened a provider-only turn that stayed open until the CLI's next result. The bridge now drops a task_started whose tool_use_id it never saw open (and that is not a restart of a tracked task). Tests prime the spawning tool_use as the real stream does, and a regression test covers the unforwarded-child case. Co-Authored-By: Claude <noreply@anthropic.com>
SawyerHood
deleted the
bb/fix-hidden-background-commands-thr_i7pnmrmq4r
branch
August 25, 2026 22:33
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Human comments
What was wrong
Background commands that Claude Code workflow agents ran showed up in the parent thread's "Running background command" card and sidebar count, as if the parent had run them. The CLI emits
task_startedfor every task in the session, including tasks a workflow agent starts, but it forwardstool_useblocks only from the main loop and fromAgentsub-agents.task_startedcarries onlytool_use_id(the child's own call), with no parent attribution. The bridge keyed the task on that id, the assembler minted a parent id that no item ever claimed, and the timeline projection treated the orphan as a root-level command. The sametask_startedalso emittedturn.open, so a workflow child's command opened a provider-only turn in the parent that stayed open until the CLI's nextresult.Evidence from one workflow-heavy thread: 2,971 of 3,052
local_bashtasks pointed at a parent call that never appeared in the log; 0 tool calls nested under its 73Workflowcalls (vs. 1,945 underAgentdelegations); 100 of its 124 turns were opened by a straytask_startedand lasted 500–1,900 s each. Orphanedlocal_agenttasks from workflow children also held the parent turn open throughhasCompletionBlockingClaudeTasks.What changed
plugins/provider-claude-code/src/task-translation.ts:translateClaudeTaskMessagetakeshasForwardedToolUse. Atask_startedwhosetool_use_idthe bridge never saw open, and that is not a restart of a tracked task, is not materialized: no row, noparentRef, noturn.open. Its later progress/notification events fall through the existing unknown-task branches.plugins/provider-claude-code/src/delta-translation.ts: wires the check tostate.startedTools.has(id).plugins/provider-claude-code/src/delta-test-harness.ts:spawningToolUseMessage/spawningToolUseForhelpers; existing hand-builttask_startedtests now prime the spawningtool_useas the real stream does.No
HOST_DAEMON_PROTOCOL_VERSIONbump: the wire format is unchanged; the daemon only emits fewer events. The thread-view projection fallback (isDirectBackgroundTaskForCurrentAgenttreating a missing parent as direct) is untouched; the orphans are removed at the source.The ordering invariant (spawning
tool_usestreams beforetask_started, and before the call'stool_result) holds in every committed fixture and recording, in a live CLI 2.1.245 run (backgrounded Bash:tool_use→task_started→tool_result; foreground Bash emits notask_started), and in a live resume run (SendMessageto a finished agent emits a newtask_startedwhosetool_use_idis the newSendMessagecall). Mining 32 recent Claude Code thread logs (≈8,300 background tasks): all 7,051 orphans sit in threads that calledWorkflow, none in the 22 workflow-free threads; among 1,266 legitimate tasks there were 0 cross-turn parents, 0 results-before-task, and 0 task-first orderings.How you verified
ignores tasks spawned by an unforwarded child (workflow agent)intask-translation.test.ts: fails before (a row and aturn/startedare emitted), passes after. It also checks that a childlocal_agentdoes not block the turn and that the parent's own next background command still materializes.pnpm exec turbo run test --filter=bb-plugin-provider-claude-code: 334 pass. The one failure isrecorded/forkinbridge.recorded-conformance.test.ts, which fails identically on the unmodified branch on this machine and whose recording contains no task messages.pnpm exec turbo run typecheck --filter=bb-plugin-provider-claude-code: pass. Prettier clean.Related: #2224 (the
background_tasks_changeddebug rows; not changed here).