[BUG] Foreground Bash past the 600 s cap becomes an orphan with no exit notification, and Monitor accepts unlimited duplicate arms on the same condition (60 in 8 min)
Summary
Two harness behaviours combine into a runaway loop while the model waits on a long job:
- A foreground
Bashcall that reaches the 600 000 ms ceiling is not killed and not converted into a tracked background task. The process keeps running, but the caller gets no handle and no completion notification. The model is left with a running job it cannot wait on. - The
Monitortool accepts a new arm on a condition identical to one already armed, returns "armed" at once, and the turn ends. Nothing tells the model the previous arm is still live. With nothing else to do, it re-arms every few seconds.
Result in one session: ~60 Monitors and 45 orphaned sleep.exe processes in about 8 minutes, all in the user's chat, for one 27-minute test battery.
Related, not duplicates: #94178 (orchestrators re-arm shell watchers for their own children; the model-side half of this), #95242 (TaskStop leaves the spawned process running), #94393 / #94553 (Monitor lifetime capped at 30 min).
Repro
- Windows 11, Claude Code CLI 2.1.251, model claude-fable-5-1 as orchestrator, Opus subagent.
- Subagent brief: run
ctest --preset gcc-gates-fast(~27 min) in the foreground withtimeout: 3600000. - The Bash tool clamps to 600 000 ms. At 10 min the call returns; the ctest process is still running.
- The subagent, told the run must finish, arms
Monitoron the log. It returns "armed". The turn ends. The subagent is re-invoked with nothing new, arms another Monitor, and again. Between arms it also runssleep 30calls. - After 8 minutes: 63 background tasks in the panel. Killing the session leaves 45
sleep.exealive.
Second occurrence, different waiter, same cause (2026-09-20, another project)
An Opus subagent (quoted 350–500 k tokens) waited on a long build by calling Bash "Check CI progress" every ~2 s in the foreground. Hundreds of calls, each a full tool round at the agent's context size. It ended at 541 k tokens, 347 tool calls, 2.5 h, with the overrun entirely from the polling. The brief had not forbidden polling; the harness offered no cheaper way to wait than a tool round, and nothing rate-limited a run of read-only calls that changed nothing.
So the waiter varies (Monitor, sleep, a bare re-check call) but the shape is fixed: the model has a job it cannot block on, so it turns "wait" into "make a tool round and end the turn", and repeats.
Expected
- At the foreground cap, either kill the process tree (and say so in the result) or promote the call to a background task with the same exit notification a
run_in_background: truecall gets. Silently orphaning is the worst of both. Monitorshould refuse or coalesce an arm on a condition that is already armed in the same session, and the "armed" result should say a wait is pending and the model need not act.- Session end should terminate child processes of Bash calls it spawned (this half is #95242).
- A run of consecutive Bash calls that only read (log tail,
pgrep, a progress file) with no other effect should be warned on or rate-limited, as #95202 also suggested.
Workaround we run now
A PreToolUse hook that refuses: any foreground test call asking for a timeout above 600 000 ms, the long battery outside run_in_background, any sleep of 30 s or more, any while/until around a sleep, and the Monitor tool outright. Long runs go to the background and the session waits for the single exit notification. This works but every project has to rediscover it.
Environment
- Platform: win32 (Windows 11 Pro 10.0.26200), PowerShell primary + Git Bash
- Version: 2.1.251
- Model: claude-fable-5-1 orchestrator, claude-opus subagent
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗