Subagent silently deadlocks: self-backgrounded Bash work isn't harness-tracked; no stall detection wakes an idle multi-agent pipeline
Summary
In a multi-agent session (Agent tool + SendMessage teammates), a subagent launched a long-running test suite inside a Bash tool call using tail-buffered output, so the tool call completed immediately. The subagent then went idle "waiting for the completion notification." Because the completed Bash call left no live task in the harness's task table, no task-notification could ever fire. With every other agent also idle and no timer anywhere, the entire pipeline froze silently for ~6.5 hours on a fully awake machine until a manual message woke it.
Environment
- Claude Code CLI
2.1.261, macOS (Darwin) - Multi-agent team spawned via the Agent tool; teammates communicate via SendMessage
- The subagent was running a Postgres-backed
pytest -m integrationsuite against a local Docker stack
Timeline (verified from transcripts and system logs)
- 01:44:39 — the subagent's Bash launcher call returns instantly (
(Bash completed with no output)in its transcript). The suite was started with output piped throughtail— the subagent's own words: "output buffered throughtail, so the file stays empty until it finishes." - 01:44:44 — the subagent announces "Suite is running in the background ... Waiting for the completion notification" and goes idle.
- 01:45:21 — last transcript entry. Nothing at all until the manual nudge.
- The suite never actually ran: the target Postgres container recorded zero client connections for the entire night, the worktree's
.pytest_cache/test-results never advanced past an earlier offline run, andpsshowed no pytest/uv process. - 08:30 — the orchestrator session sent a manual status-check message; the subagent woke and recovered.
- The machine never slept:
pmset -g logshows no sleep/wake events; a display-sleep assertion was held continuously for ~11h.
Why this is a footgun, not just misuse
The correct mechanism exists — Bash run_in_background: true tasks are harness-tracked and re-invoke the agent on completion. But nothing prevents, warns about, or detects this pattern:
spawn a detached long-running process inside a Bash call that then completes, then idle awaiting a "completion notification" that can only ever come from harness-tracked tasks.
Agents reach for it naturally: tail-buffering keeps tool results small for long suites.
Compounding gaps:
- No stall detection. When an agent goes idle, nothing notices that its assigned board task is still
in_progresswhile it has no live tracked background tasks and no queued messages. No warning to the lead session, no auto-nudge after a threshold. - Orphaned/failed-to-spawn processes are invisible. A Bash call that completes while leaving child processes behind — or that failed to leave any — is indistinguishable from a clean finish.
- The multi-agent wake model is purely message-driven. There is no built-in liveness heartbeat for subagents. (We now run a parent-side cron heartbeat as a workaround.)
Requests (any subset would help)
- Stall detection: flag when an agent idles with no pending tracked tasks while its assigned task is still in_progress — or surface "agent idle unexpectedly" to the lead session.
- Warn when a Bash call's side effects include child processes that outlive the call, or when an agent's final message references background work that is not harness-tracked.
- Agent-facing guidance: for long-running work, always use Bash
run_in_background; never self-background viatail/nohup/disowninside a completing call. - (Optional) a lightweight subagent-visible wakeup/heartbeat primitive so teams don't have to build parent-side cron jobs purely for liveness.