Repository navigation
Conversation
ApprovabilityVerdict: Approved at Macroscope's review found this PR approvable — This is a narrowly scoped server bug fix that prevents Claude goals from being marked complete while a background subagent is still running, with targeted regression coverage. Existing completion behavior remains unchanged once background work has settled. You can add or adjust custom eligibility rules. Learn more. |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configuration
📒 Files selected for processing (2)
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 8 remain after this review. 📝 WalkthroughWalkthroughClaude goal completion now checks active background work in the matching live query. Four task types defer the goal check. Other defined subagent task types do not block completion. Tests cover task launch, wake continuation, and expected goal statuses. ChangesClaude goal completion
Priority: ➖ Normal Estimated code review effort: 2 (Simple) | ~15 minutes Change: Bug fix Suggested reviewers: Merge Risk: ⚪ Minimal · up to No actionable merge-blocking issue remains after normal checks. Security Architecture ReviewSecurity architecture risk: ⚪ Minimal · up to The change makes goal completion more conservative while background work runs. It does not add permissions, expose a new interface, or weaken the protection against replacing a process that still has active work. Retained concerns Security review detailsSecurity Blast Radius
Trust Boundaries and Controls
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
…round subagent runs Claude Code skips a goal's Stop hook check while background work runs and checks again on a later turn. The adapter inferred completion from a normal turn end plus an empty roster, but the roster leaves subagents out, so a turn that ended while a background Agent ran marked the goal complete. The completion check now also requires that the live process runs no background work of the types Claude Code 2.1.292 waits on: local_agent, remote_agent, in_process_teammate and local_workflow on the subagent path (local_bash is already on the roster). Tasks of other types, such as mcp_task and monitor_ws, are exempt, as they are in Claude. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
c9f9a64 to
98d67c1
Compare
Problem
On a Claude thread, a
/goalshows Goal complete when a turn ends while a background subagent (Agent withrun_in_background) is still running, even though Claude has not checked the goal. Claude Code skips the goal check while background work runs and checks again on a later turn, so the goal is still set in Claude; only T3's status is wrong. The goal row then offers only Clear, which invites the user to drop a goal that is still working.Seen on T3 Code Nightly 0.0.46-nightly.20261006.2735 (macOS), Claude Code 2.1.292. To reproduce: start a background subagent, then send
/goal <condition>while it runs. Claude acknowledges, ends the turn to wait for the subagent, and the goal row turns to "Goal complete".Change
#15592 infers Claude goal completion in
finalizeActiveTurn: the goal was active, the model replied this turn, the turn ended normally, and the background-task roster is empty. The roster holds onlylocal_bashwork; subagents are deliberately kept off it, so a running background subagent never blocked the inference.The check now also requires that the live process runs no background work of a type Claude waits on. It reuses
liveProcessRunsBackgroundWork, which already skips subagents orphaned by an earlier process and ones whose completion is already buffered. AforGoalCheckoption makes it ignore task types Claude does not wait on. The model-switch and query-replacement gates are unchanged.Which types defer the check comes from Claude Code 2.1.292 itself. Its Stop handler runs
Aa(taskRegistry.all())and skips the goal evaluation when that returns anything.Aakeeps non-terminallocal_agent,remote_agent,in_process_teammate,local_workflowandlocal_bashtasks, regardless ofambient. SoCLAUDE_GOAL_DEFERRING_TASK_TYPESlists the four subagent-path types, and atask_startedwith any othertask_type(for examplemcp_taskormonitor_ws) goes into an add-onlygoalExemptTaskIdsset. A missingtask_typestays deferring. Claude's other exclusions (observer agents,main-session, idle teammates, long-running remote agents) are not visible in SDK frames; for those T3 keeps the goal active, which is the safe direction.Once the background work ends and a later turn passes the check, the goal completes as before.
Scope and approval
Fixes #16611 (filed for tracking; not yet triaged). This is a small, focused fix for an obvious bug: the UI reports a goal as complete when the provider has not evaluated it, which contradicts Claude Code's documented behavior and the rule the existing code comment states. One gate in one adapter changes, plus tests. Codex goals, contracts and clients are untouched.
Verification
Live capture. I drove Claude Code 2.1.292 through the Agent SDK with this scenario: launch a background subagent, then
/goal. In the captured frames, the rootresultarrives while the subagent still runs, with no Stop hook feedback, so Claude skipped the check. Then come thetask_notification, a wake turn (init), and a final result with no feedback, so the goal passed. Replaying those exact frames through the adapter:main, the goal is markedcompleteright after the goal turn, which is the bug.activeafter the goal turn andcompleteafter the wake turn.New tests in
native goals:defers goal completion while a background subagent runsfollows the captured frame order (Agent call,background_tasks_changed, backgroundedtask_started, async ack, reply, result, then notification, wake, result). It assertsactive, thencomplete.treats a running $taskType … as goal $statusasserts thatmcp_taskgivescomplete, an ambientskip_transcriptlocal_agentgivesactive, and a missing type givesactive.main, or the intermediate designs I tried). 147/147 pass inClaudeAdapterV2.test.ts.tsc --noEmitinapps/serverpasses.vp fmt --checkis clean.vp linton the two files reports only an existing warning elsewhere in the file.Reviews. The fix went through three review rounds by GPT-6.1 Sol and Claude Opus 5.5. They checked foreground, nested and resumed subagents, in-turn completion, stop and failure, process replacement, buffered and live wake turns, and Claude's own deferral predicate in the CLI binary. No open findings remain.
Seen in a real thread (Nightly 0.0.46-nightly.20261006.2735): the goal row reads "Goal complete" while the background subagent is still coding and no review round has started.
Not checked: a packaged T3 build running this patch end to end.
Made with Claude Code (Claude Opus 5.5).
🤖 Generated with Claude Code