Background subagent never re-woken when its tracked background Bash child exits (child survives, wake event lost)

Status Open
Maintainer reply ✓ Yes — bcherny
Activity 4 comments · opened Jul 14, 2026
💡 Likely answer: A maintainer (bcherny, collaborator) responded on this thread — see the highlighted reply below.

Environment

  • Claude Code v2.1.209 (CLI), macOS (Darwin 24.6.0)
  • Model: claude-fable-5 (main session), subagent spawned via Agent tool (subagent_type: general-purpose, model: opus)
  • Main session itself runs as a background job session

Summary

A background subagent that launches a tracked background Bash command (run_in_background: true) and then ends its turn is immediately reported to the parent as stopped/completed — the task-notification note says it fires when the agent stops "with no live background children of its own" — even though the child was just launched and is alive. The subagent also disappears from the TUI's agent view at that moment. When the child later exits (even ~90 seconds later), the subagent is never re-invoked. The child process itself is fine: it keeps running, and on exit its tasks/<id>.output file contains the expected final output. Only the wake event is lost. The subagent stays dormant until manually resumed via SendMessage, which responds "Agent … had no active task; resumed from transcript".

Repro pattern

  1. Main session spawns a subagent via the Agent tool.
  2. The subagent starts a remote job (detached tmux over ssh) and then launches a tracked waiter as its wake signal:

Bash(run_in_background: true): ssh host 'while tmux has-session -t <job> 2>/dev/null; do sleep 30; done'.

  1. The subagent ends its turn, expecting re-invocation when the waiter exits (the documented contract for tracked background children).
  2. The parent immediately receives a task-notification for the subagent with status: completed, despite the live child; the subagent simultaneously disappears from the TUI.
  3. Minutes later the waiter exits cleanly; its output file is written with the expected content.
  4. The subagent is never re-invoked. SendMessage to it returns "had no active task; resumed from transcript".

Measured timeline (three reproductions in one session, same day; file birth/mtime of the waiter output files)

| repro | waiter child born | child exited | child lifetime | subagent re-woken? |
|---|---|---|---|---|
| 1 | 17:30:04 | 17:31:35 | 91 s | no |
| 2 | 17:35:41 | 17:40:42 | ~5 min | no |

In both cases the parent's completed notification for the subagent arrived within seconds of the subagent ending its turn — i.e. while the child was demonstrably alive (it later wrote its completion output).

Two earlier sessions (Jul 10) hit the same symptom with coordinator-measured phase lengths of 9 min and 14 min. So this is not a long-timeout/expiry issue — children lasting 1.5–15 minutes all fail to re-wake their subagent. It appears deterministic for this pattern.

Expected

A subagent with a live tracked background child should not be treated as "stopped with no live background children" (nor removed from the TUI), and the child's exit should re-invoke the subagent.

Control

The main session's own background children with identical command shape (same ssh waiter against the same host) wake the main session reliably — same session, same day, every time. The loss appears specific to background children of subagents: either the child is disowned from the subagent's task tracking the moment the subagent's turn ends, or the child-exit event is not routed to re-invoke an already-completed subagent.

Impact / workaround

Remote jobs orchestrated by subagents complete silently and the pipeline stalls until a human notices. Workaround: the parent session duplicates every watcher (coordinator-side backstop) and SendMessage-nudges the subagent when the real completion is observed — doubling the monitoring plumbing.

View original on GitHub ↗

4 Comments

AnMakc · 1 month ago

Correction + new data after further reproductions: the original report said the child exited "hours later" — that was wrong. Measured child lifetimes that fail to re-wake the subagent are 91 seconds and ~5 minutes (two repros in one session, file birth/mtime evidence), plus 9 and 14 minutes in two earlier sessions. Body updated with the measured timeline. Also added: the subagent disappears from the TUI's agent view at the moment the premature 'completed' notification fires (i.e. as soon as it ends its turn with only a background child keeping it alive).

nicholas-lonsinger · 26 days ago

Reproduced deterministically on 2.1.221 (macOS), 3/3 runs, with two data points I haven't seen stated precisely here or in #78782: the harness visibly observes the child's exit (the agent-list row updates from it in real time), and the stall is unconditional with respect to the child's output and exit code.

Setup: the main session spawns one async general-purpose subagent whose entire task is to run sleep 180; echo FINISHED > /tmp/<marker>; date >> /tmp/<marker> with run_in_background: true, then end its turn, stating in its final message that it is waiting and will report on completion.

Observed in all three runs:

  1. The parent receives exactly one task-notification for the subagent, status: completed, 8–20 s after spawn (the length of the subagent's turn) — its result text says "I'm waiting for the background task," ~2.5 minutes before the child actually exits. The notification's boilerplate says it "fires each time this agent stops with no live background children of its own"; the child was live in every run.
  2. For the full 180 s, the parent session's footer keeps the subagent listed, plus a "1 shell" indicator — the harness tracks the child as belonging to the subagent.
  3. Within ~5 s of the child's real exit (marker-file mtime), the row flips to completed/green and the "1 shell" indicator disappears; the row is reaped ~30 s later. So the exit event is observed and drives lifecycle state — only the wake/dispatch step is missing.
  4. The subagent is never re-invoked: its tasks/<agent-id>.output file's mtime stays frozen at turn end, through and past the child's exit, in all runs.
  5. The child's own tasks/<task-id>.output receives the captured stdout/stderr at exit — capture works; delivery goes to no one.
  6. Run 3's child wrote stdout and stderr and exited 3: identical stall — and the row still flips green, so the nonzero exit isn't surfaced either. This rules out the stall being an optimization for silent, clean exits.

The changelog trail is consistent with a delivery path never having existed: 2.1.141 made "agents that finish work but leave a background shell running" classify as Completed (the premature notification above), 2.1.183 made the child survive turn end, and the original 2.0.64 contract says background completions "wake up the main agent" — literally main-only.

As others note, SendMessage to the parked agent recovers it instantly and it reports from the on-disk result in one call.

mageyuki · 25 days ago

Reproduced deterministically on Linux, v2.1.221 — the platform:macos label can be dropped.

Environment: Claude Code v2.1.221 (CLI, native installer), Linux (kernel 7.0.0-28-generic), main session on claude-fable-5; subagents spawned via the Agent tool (both general-purpose and custom agent types).

Minimal repro (1/1): a general-purpose subagent runs sleep 45 && echo REINVOKE_TEST_DONE with run_in_background: true and ends its turn, per instructions.

  • Parent received the subagent's task-notification with status: completed ~7 s after spawn (subagent transcript: first record 11:29:50Z, last record 11:29:57Z) — the 45 s child was alive the whole time.
  • Child exited ≈ 11:30:41Z; its tasks/<id>.output captured the stdout correctly.
  • Subagent transcript stayed frozen at 11:29:57Z — checked at 11:32:23Z and later: never re-invoked.
  • SendMessage recovery behaves exactly as described here: "Agent … had no active task; resumed from transcript".

Production impact (same session, real pipeline): we run implementation subagents that wrap a 15–25 min CLI process via a tracked background Bash call. Two of them ended their turn stating "the harness will re-invoke me when it exits":

  • Instance 1: child launched 2026-08-04T20:33:34Z, exited cleanly ~5 min later (20:38Z, output file written). The subagent was never re-invoked; the pipeline stalled 5 h 38 m until we noticed and SendMessage-nudged it (02:16Z). The subagent then completed all remaining work from the on-disk result in one resume.
  • Instance 2: identical pattern; caught within seconds only because we had armed a parent-side watcher by then.

Control, matching the OP: in the same session, the main agent's own run_in_background children (watch loops with identical shapes) re-invoked the main loop reliably, every time. The loss is specific to background children of subagents.

Workaround convergence (independently arrived at, matches the OP's): (1) subagent-side — never end the turn while the child runs; keep the turn alive with bounded foreground waits (timeout 300 tail --pid=<PID> -f /dev/null || true, repeated) and verify completion via PID + output file rather than notifications; (2) parent-side — duplicate watcher on the child's real output path plus a SendMessage nudge on completion. With both in place the pattern is fully mitigated, at the cost of doubled monitoring plumbing.

Happy to provide the transcripts' record timelines if useful.

bcherny collaborator · 14 days ago

Confirmed / reproduced on 2.1.233 (macOS, interactive session).

What I ran: the main session spawned one background general-purpose subagent whose only job was to run sleep 45 && echo REINVOKE_TEST_DONE with run_in_background: true, end its turn, and write a marker file when re-invoked. Observed: the parent got the subagent's completed notification about 4 seconds in (child still alive); the footer showed the parked agent plus "1 shell"; the child exited ~45 s later with its output captured correctly; the "1 shell" indicator and the agent row then disappeared, but the subagent was never re-invoked (its transcript stops at "waiting for background child" and the marker file was never written, 90+ s after the child exited).

So this matches your report exactly: the child's exit is observed and its output is saved, but the wake that should resume the parked subagent is dropped. Background children of the main session are unaffected. The SendMessage nudge is the right workaround for now — we're working on a fix.

🤖 Generated with Claude Code