anthropics / anthropics/claude-code
[BUG] A completed subagent is never revived by its own pending Monitor(persistent: true) event
- Dominant language
- Python
- Stars
- 145k
- Forks
- 23.1k
- PR merge metrics
- PR metrics pending
Description
**Symptom:** a subagent that ends its turn with a pending `Monitor(persistent: true)` is never revived when that monitor emits an event. The monitor's own command runs to completion normally (verified in the 2026-08-23 repro: the loop exited after the condition became true); the completed subagent is simply never woken, and whatever it promised to report dies unread. Only the top-level session receives task events reliably.
This makes the "arm a watch, end the turn, report when it fires" pattern — which the Monitor tool description actively encourages — silently unusable inside a subagent.
## Environment
- Claude Code 2.1.258 (interactive CLI, not stream-json), macOS Darwin 25.6.0, Apple M2
- Originally observed on 2.1.220; re-verified on 2.1.258 before filing
## Minimal repro
Top-level session spawns one depth-1 subagent whose entire prompt is:
1. `Monitor` with `persistent: true` and
`command: until [ -f /tmp/repro/flag ]; do sleep 2; done; echo MONITOR_FIRED`
2. `date > /tmp/repro/armed.txt`
3. End the turn immediately with the word `ARMED` (do not poll, do not wait)
4. *If later revived by the monitor event*: `date > /tmp/repro/revived.txt`, end turn with `REVIVED`
The parent waits for `armed.txt`, then creates `/tmp/repro/flag`.
**Result on 2.1.258:** `armed.txt` written, flag created 5s later, `revived.txt` never written, no further turn from the subagent within 180s. The subagent's last and only output was `ARMED`.
## Measurements
| when | version | depth | outcome |
|---|---|---|---|
| 2026-08-22 (production incident) | 2.1.220 | 2 | not revived |
| 2026-08-23 (controlled repro) | 2.1.220 | 2 | not revived |
| 2026-08-23 (controlled, flag file) | 2.1.220 | 1 | not revived |
| 2026-09-18 (controlled, flag file) | 2.1.258 | 1 | not revived |
The single revival ever observed (the 2026-08-22 incident, depth 3) is the anomaly: that agent had been resumed via `SendMessage` in between, which appears to have re-registered it.
## What does work (for contrast)
- A background agent's **completion** broadcast reaches the top-level session reliably at any depth — a depth-3 grandchild's final report arrived at the main session in the same second, without passing through its already-completed parents.
- `SendMessage` addressed by **agent id** revives a completed agent ("was stopped (completed); resumed it"). Addressed by agent **type** it fails with "no reachable agent by that name".
- So the wake path exists and works when driven externally. It is specifically the agent's *own* pending Monitor event that does not drive it.
## Same failure via backgrounded Bash
A subagent's own `Bash(run_in_background: true)` task is no better. 2026-08-27: a CI-watching subagent backgrounded its wait because the 600s foreground cap would have been exceeded, then ended its turn. The child completed ~20 minutes later; the subagent was never revived. The verdict was only recovered because the *top-level* session had independently armed its own watcher on the same file.
## Impact
In the original incident a correct CI verdict sat unread for 21 minutes: the subagent had reported "watch armed, I'll report when it fires", and nothing was ever going to fire it. The promise reads as a valid contract to both the agent and the person reading the transcript, and it is backed by nothing.
The workaround is to forbid the pattern outright in subagents — a watching subagent must hold its turn open with a foreground `Bash` until-loop (re-run on exit 124), and the caller must additionally own a deadline and do one cheap direct read if the silence exceeds it. That works, but it means a subagent cannot absorb a wait longer than its foreground budget without the caller duplicating the watch.
## Possibly related
- #39632 (closed not planned): `enqueuePendingNotification` with `priority="later"` emits `queueChanged`, but the consumer only re-triggers for `priority="now"`. Same shape — an enqueued notification with no consumer to drain it — though that report is about an idle top-level session under stream-json, and this one is about a *completed subagent* under the interactive CLI.
- #86443 (open): scheduled desktop sessions ending with unconsumed `` payloads.
## Ask
Either:
1. Deliver a subagent's own pending task events to it and resume it, the same way `SendMessage` by agent id already resumes a completed agent; or
2. If Monitor-then-exit is intentionally a top-level-only pattern, say so in the `Monitor` tool description and make the call fail loudly (or warn) when a subagent arms a persistent monitor it will never see fire.
Silent non-delivery is the worst of the three, because the agent confidently reports that the watch is armed.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with the minimal depth-1 reproduction using Monitor(persistent: true), then compare its behavior with SendMessage addressed by agent id and a backgrounded Bash task. Trace the Monitor event and completed-subagent wake path; done means the pending event revives the subagent, or the tool clearly warns or fails when that pattern is unsupported.
Written by the indexing model from the issue text.
Assessment
- Domain
- cli, devtools, tooling
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100