Agent tool with run_in_background: false can return control before the subagent actually stops

Status Open
Maintainer reply None cached
Activity 0 comments · opened Aug 19, 2026

Agent tool with run_in_background: false can return control before the subagent actually stops

Summary: When a foreground subagent (run_in_background: false) is still mid-turn — it has emitted a text fragment and queued a tool call in the same assistant turn — the synchronous Agent tool call sometimes returns to the caller immediately with that text fragment as the final result, while the subagent keeps running (more tool calls, more turns) in the background. A subsequent message sent to that agent (e.g. via a resume/continue mechanism) is then delivered mid-stream into the still-running session ("The coordinator sent a message while you were working: ...") rather than resuming a genuinely paused one.

Impact: The caller has no reliable way to distinguish "the agent is done, here's its answer" from "the agent handed back a stale mid-task snapshot." In an orchestration workflow that treats the result as an authoritative structured handback (e.g. before writing durable state), this is dangerous: the natural failure mode is silently trusting an incomplete report. In our case we caught it because the returned text was an obvious non-sequitur ("Caught correctly. Restore and do a final full clean run." / "Now let's re-run the dry run to validate.") rather than a coherent final summary, and we followed up with a resume message that turned out to interrupt genuinely ongoing work — the agent had already queued further tool calls past the point the "result" was captured.

Evidence (two independent occurrences in one session, same shape both times):

Both subagents were started with run_in_background: false. Their session transcripts (~/.claude/projects/<project>/<session>/subagents/agent-<id>.jsonl) show:

  1. An assistant message whose content is a short text block (stop_reason: null on that block — i.e. not a turn boundary) immediately followed, in the transcript, by a tool_use block continuing the same line of work.
  2. Multiple further tool_use/tool_result pairs after that point — the agent was actively continuing (running tests, grepping files, reading source) — with no indication anywhere in the stream that it had stopped, hit a turn/token budget, or errored.
  3. Only later does a user message appear with content "The coordinator sent a message while you were working: ..." — the follow-up message we sent after receiving the (apparently premature) result.

Case 1 — phase-builder agent (sonnet, maxTurns: 100, actual tool_uses at final completion: 103 — nowhere near cut off mid-stream at the point in question):

  • result returned to caller: "Caught correctly. Restore and do a final full clean run."
  • Transcript: that text is one content block of an assistant message; the next block is a tool_use. The tool result that follows shows a full test run completing ([OK] lines). Several more turns follow before our resume message is injected.

Case 2 — delivery-metrics-collector agent (sonnet, maxTurns: 80, actual tool_uses at final completion: 88):

  • result returned to caller: "Now let's re-run the dry run to validate."
  • Transcript: text block followed by a Bash tool call, then a grep, then a Read, then another tool call — five more tool calls visible before our resume message is injected mid-stream.

In both cases, resuming the "completed" agent with a clarifying message worked and produced a correct, complete, coherent final report — consistent with the underlying session never actually having been lost or crashed, only with the synchronous return having fired too early.

What we ruled out: We checked the invoked agents' own configuration (maxTurns, model, effort) against their actual tool_uses counts at true completion; neither is close to a turn-budget boundary at the point the premature result was captured, so this isn't an agent-definition-side maxTurns cutoff being surfaced as a partial result.

Expected behavior: A synchronous (run_in_background: false) Agent call should block until the subagent has genuinely stopped (i.e., produced a turn with stop_reason: end_turn and no further pending tool calls), and the result field should reflect that final state — not an interim in-flight text fragment.

Environment: Claude Code CLI, Sonnet 5 (claude-sonnet-5) as both orchestrator and subagent model, macOS (Darwin 25.5.0), agents launched via the Agent tool from a plugin-defined subagent type (delivery-orchestration:phase-builder, delivery-orchestration:delivery-metrics-collector).

Reproduction difficulty: Intermittent — encountered twice in one multi-agent orchestration session (out of ~7 foreground Agent calls in that session), both on longer-running agents (20+ minutes wall clock, 80-100+ tool calls). Not yet isolated to a minimal repro; happy to share full transcript excerpts (redacted paths) if useful.

View original on GitHub ↗