Nested-Agent orchestrator (e.g. built-in /code-review) reports status: completed after yielding to spawned children, before its assigned work is done
Summary
A background-forked skill run of the built-in /code-review command spawned 8 parallel Agent tool calls (subagent_type general-purpose, model sonnet) as independent "finder" agents, intending to wait for all 8, run a verification phase, then report via ReportFindings. Instead, the orchestrating agent's own turn ended (accurately reported as status: "completed") immediately after each status check, well before its assigned work was actually done — requiring 3 separate manual SendMessage resumes from the top-level session, over roughly 20 minutes, before it collected all 8 finders' results and produced the final report.
This is distinct from #81048 and #80235: those describe a task-notification falsely claiming completed while the underlying process is demonstrably still alive (verified via pgrep/TaskStop/file growth). Here the "completed" status for each individual notification was true for that turn — the orchestrator genuinely stopped executing — but it stopped before finishing the multi-step task it was given, because waiting on its own previously-spawned nested Agent() children doesn't block the parent's turn; it just yields, and there is no automatic re-wake tied to "my own children finished" the way top-level tasks get task-notifications.
Reproduction sequence (from session transcript)
- Top-level session runs
/code-review <PR URL>with an instruction to prefer sonnet-tier agents. This launches as a forked background skill execution. - The orchestrator spawns 8 named finder agents (
angle-a-linescan,angle-b-removed-behavior,angle-c-crossfile,angle-reuse,angle-simplification,angle-efficiency,angle-altitude,angle-conventions), all viaAgent(model: "sonnet"), then does a singlesleep 60(backgrounded) followed by asleep 1(foreground, no-op), and ends its turn. - Task-notification arrives:
status: "completed", result text: "I'll wait for the 8 finder agents to report back before moving to verification." — i.e. the orchestrator's stated intent contradicts its own "completed" status; it hasn't done what it says it's about to do. - Top-level session sends a
SendMessagenudge telling it to check finder status viaListAgents, wait properly, then proceed through verification andReportFindingswithout ending its turn again until done. - Orchestrator resumes, checks status, finds 1/8 done, reports "waiting on the remaining 7" — and ends its turn again (another
status: "completed"notification). - Steps like #5 repeat 2 more times (7→6→"all 8 done, proceeding to verification") entirely on the harness's own re-notification cadence — no further manual nudge needed after the first, but each of these intermediate stops is a
status: "completed"notification for work that is self-evidently unfinished by the orchestrator's own stated criteria. - On the 4th notification, all 8 finders had genuinely finished (confirmed: the final report included real findings from 6 of the 8 angles, with the orchestrator explicitly noting the other 2 —
angle-efficiency,angle-conventions— "never reported back despite being confirmed still running across many repeated check-ins over a very extended period," so it proceeded to verification on the 6 that did report, rather than blocking indefinitely).
Impact
Any skill or custom workflow built on the fan-out-then-synthesize pattern (spawn N background finder/worker agents from within an agent that is itself a background task, then collect + verify + report) is unreliable in this harness unless an external actor (a human, or a separate top-level session) notices the stall and manually resumes it via SendMessage, potentially multiple times. This directly undermines built-in multi-agent skills like /code-review that are structured this way — three of four notification cycles in this run required the review to look "done" when it manifestly wasn't (still waiting on unfinished child agents), and the fourth cycle silently dropped 2 of 8 review angles (efficiency, conventions) with no forcing function to prevent that beyond the orchestrator's own judgment call to stop waiting.
Root cause hypothesis
Nested Agent() calls spawned by an agent that is itself running as a background/forked task do not give their parent a genuine blocking-wait primitive, nor an automatic re-invocation the moment all of them complete (the way a top-level session gets a task-notification per background agent). The parent's only real option is to check-and-yield, relying on the harness's own re-notification cadence (or an external nudge) to get another chance to check again later. Each check-and-yield is reported as status: "completed" even though the orchestrator's own assigned task (a code review awaiting 8 finders) is incomplete — the status field describes "this turn ended" rather than "the work you gave me is done," but nothing in the notification distinguishes those two very different things.
Workaround used
Manual SendMessage resume from the top-level session on the first stall; subsequent stalls resolved via the harness's own re-notification without further intervention, but only because a human was watching and willing to wait through ~20 minutes and 4 notification cycles for an 8-agent fan-out. A tool built specifically for this exact pattern — deterministic fan-out/collect without relying on a model-driven agent's own turn surviving until its children finish — is the Workflow tool's parallel()/pipeline() primitives, which appear architecturally immune to this specific failure mode since the awaiting happens in a script, not in another agent's own context.
Environment
- Claude Code CLI, version
2.1.229(from session transcript) - macOS (Darwin 25.6.0)
- Model:
claude-sonnet-5(top-level session and orchestrator); finder agents alsoclaude-sonnet-5 - Trigger: built-in
/code-reviewslash command, invoked via theSkilltool as a forked background execution
Related
- #81048 — same symptom vocabulary (
task-notificationsayscompleted), different root cause (there: notification lies about liveness; here: notification is accurate about the turn ending, but the turn ending doesn't mean the assigned task is done) - #80235 — broader "premature/fabricated notification" pattern; this report is a narrower, reproducible instance specific to nested-
Agent()-orchestrator-as-background-task