Background subagent never re-woken when its tracked background Bash child exits (child survives, wake event lost)
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
- Main session spawns a subagent via the Agent tool.
- 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'.
- The subagent ends its turn, expecting re-invocation when the waiter exits (the documented contract for tracked background children).
- The parent immediately receives a task-notification for the subagent with
status: completed, despite the live child; the subagent simultaneously disappears from the TUI. - Minutes later the waiter exits cleanly; its output file is written with the expected content.
- 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.
4 Comments
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).
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>withrun_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:
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.tasks/<agent-id>.outputfile's mtime stays frozen at turn end, through and past the child's exit, in all runs.tasks/<task-id>.outputreceives the captured stdout/stderr at exit — capture works; delivery goes to no one.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,
SendMessageto the parked agent recovers it instantly and it reports from the on-disk result in one call.Reproduced deterministically on Linux, v2.1.221 — the
platform:macoslabel 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-purposeand custom agent types).Minimal repro (1/1): a
general-purposesubagent runssleep 45 && echo REINVOKE_TEST_DONEwithrun_in_background: trueand ends its turn, per instructions.status: completed~7 s after spawn (subagent transcript: first record11:29:50Z, last record11:29:57Z) — the 45 s child was alive the whole time.11:30:41Z; itstasks/<id>.outputcaptured the stdout correctly.11:29:57Z— checked at11:32:23Zand later: never re-invoked.SendMessagerecovery 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":
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.Control, matching the OP: in the same session, the main agent's own
run_in_backgroundchildren (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.
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_DONEwithrun_in_background: true, end its turn, and write a marker file when re-invoked. Observed: the parent got the subagent'scompletednotification 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
SendMessagenudge is the right workaround for now — we're working on a fix.🤖 Generated with Claude Code