Monitor tool: compulsive infinite-spawn loop when used for heartbeat-checking long-running background tasks
Summary
When Monitor is used to poll whether a long-running background process is still alive, each notification fires a new model turn. The model's reflex is to spawn another Monitor as a response — even immediately after writing text like "I will not spawn another monitor." The loop is unstoppable through intent and only breaks when the underlying process finishes.
Reproduction
- Start a long-running background process with
Bash(run_in_background=True)(e.g. a 30-45 min pentest scan). - Instead of waiting for the single
task-notification { status: completed }event, callMonitoronce with a PID-death check. - When the monitor fires a heartbeat ("pid alive"), the model responds by spawning another Monitor.
- Repeat indefinitely.
Observed result: 309 Monitor spawns in a single session, over ~90 minutes. The model correctly diagnosed the problem and wrote the fix into project documentation mid-session, then immediately spawned monitor #261.
Session evidence
Session ID: c1a5c6b8-48df-4e2e-8d1d-60ffb5da9fb9 (local, not shareable), but the pattern is fully described in the conversation: the model wrote "I will not call Monitor again" or equivalent at least a dozen times and violated it within seconds each time.
Monitor names escalated from descriptive ("HexStrike R30 completion") → single letters ("a", "b", "c") → repeated letters ("aaa", "aaaa", "aaaaa") as the model ran out of ideas for names while continuing to spawn.
Root cause
The Monitor tool fires a notification for each stdout line of the watched command. Each notification is delivered as a new model turn. The model treats turns as requiring a response. Monitor is the nearest available tool, so it gets called reflexively.
This is distinct from the model being "stuck" — it was actively reasoning correctly about the problem and still couldn't stop.
Suggested fixes
- Session-level rate limit: Warn or hard-cap when Monitor is called >N times (e.g. 5) with commands that match the same PID-check pattern within a session.
- UI indicator: Show the active Monitor count somewhere visible so the operator can interrupt earlier.
- Documentation: Add a note to the Monitor tool description warning against heartbeat-checking long-running PIDs — use
Bash(run_in_background=True)+task-notificationinstead.
Workaround (already documented)
Use Bash(run_in_background=True) for long-running processes and wait for the single task-notification { status: completed } event. Do NOT call Monitor. If a mid-wait status check is needed, call TaskOutput(block=False) exactly once.
This workaround is now documented in the affected project's CLAUDE.md files, which will prevent recurrence in future sessions for this project — but the underlying model behavior is not fixed.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗