Subagent (Task tool) re-invoked ~9× after finishing, with no new input — result becomes a trailing closer instead of the deliverable

Open 💬 0 comments Opened Jun 24, 2026 by epljunioradv

Environment: Claude Code CLI (version visible in session jsonl). Custom subagents + plugins present; see caveat.

Summary

When a subagent is dispatched via the Task tool, it produces its full deliverable in an early turn, then is re-invoked ~9 times consecutively with no new user input. Each re-invocation the model emits a short throwaway closing remark ("Acknowledged.", "Session complete.", "Closing."). The harness returns the last assistant text block as the subagent's result, so the orchestrator receives a useless closer instead of the deliverable.

Evidence (from subagent transcript jsonl)

  1. Deliverable appears intact and verbose in an early turn (e.g. a 6746-char report).
  2. Then 8–9 consecutive type:assistant turns follow, several with stop_reason:end_turn, with zero user/tool turns between them.
  3. Each is a distinct real generation: distinct requestId per turn.
  4. The re-invocations carry input_tokens:0 (fully cached; nothing new is injected) — confirming the harness re-queries with no added content.
  5. Deterministic: always ~9 turns over ~30s, for any task including a trivial "return the string FOO".

What was ruled out

  • Hooks: all SubagentStop hooks were neutralized to no-op simultaneously and the loop persisted (still 9 turns). Stop hooks were instrumented and confirmed not to fire for subagent stops. No hook returns decision:block under any condition (tested with stop_hook_active both true and false).
  • Reasoning effort: dispatching the same trivial task at effort:low vs effort:high produced identical 9-turn loops — rules out a thinking-budget-drain explanation.

Impact

Subagent text returns are unreliable: the orchestrator receives a trailing acknowledgment instead of the work product. Workaround on our side = read the deliverable directly from the subagent transcript (subagents/agent-<id>.jsonl), never trusting the returned text.

Caveat (honest scope)

Observed in an environment with plugins installed. We neutralized all Stop/SubagentStop hooks and confirmed Stop hooks do not fire for subagents, which points to harness-native behavior — but we did not reproduce on a fully vanilla Claude Code install. A vanilla repro would confirm. Transcripts available on request.

Ask

Is this expected? What termination condition drives the post-end_turn re-invocation of a subagent, and can the harness return the substantive turn (or the first end_turn) instead of the last closer?

View original on GitHub ↗