Subagents killed by stream-idle watchdog when host laptop sleeps
Subagents killed by stream-idle watchdog when host laptop sleeps
Summary
When the host machine sleeps (macOS auto-sleep, lid close, etc.) while a subagent is mid-conversation, the agent's API stream silently breaks. The stream-idle watchdog then kills the agent after ~10 min with Stream idle timeout - partial response received even though the work was healthy and the user is still around — they were just away from the keyboard for a while.
This silently loses subagent work that was making real progress.
Versions
- Claude Code
2.1.119(per the agent JSONLversionfield) - macOS Darwin (Apple silicon)
- Both
Bash-tool subagents and worktree-isolated subagents affected
Reproduction
- Spawn a long-running subagent (anything that takes > a few minutes — multi-file refactor, big test suite run, etc.).
- Walk away from the keyboard for ≥ 10 min so the laptop's auto-sleep kicks in (default ~10 min on battery, longer on AC but still finite).
- Return.
- The agent has been killed with
Stream idle timeout - partial response receivedand ~10-15 min of "no progress" recorded in the watchdog. The agent's last activity in its JSONL coincides with macOS entering the sleep state.
Evidence — two real failures from one session
Both agents stalled mid-assistant-turn (i.e. waiting for the model's next response). Timestamps below are AEST.
Agent A — failed mid-implementation
| Time | Event |
|------|-------|
| 17:42:19 | Last successful assistant text emitted ("Now let me add the...") |
| 17:42:01-22 | pmset shows caffeinate assertion clientDied, audio sleep assertions released, display-power-down sequence |
| 17:59:33 | Watchdog fires: API Error: Stream idle timeout - partial response received |
| | Net result: 17 min of dead air; agent killed; ~150 LOC of partially-applied code, untestable, not committed |
Agent B — failed seconds after starting
| Time | Event |
|------|-------|
| 18:00:17 | Agent's last tool_result (a git status) returned successfully |
| 18:00:18 | pmset: Sleep — Entering Sleep state due to 'Maintenance Sleep':TCPKeepAlive=active |
| ~18:10:17 | Watchdog fires (10 min after last activity) |
| | Net result: zero progress; agent killed |
The 1-second gap between agent activity and Sleep in Agent B is the smoking gun.
Root cause (best understanding)
- macOS suspends the agent's process and halts its open TCP socket on sleep.
- The Anthropic API stream, mid-response, has no retry/recover logic on the agent side — it just sits in the broken-stream state.
- The agent harness's stream-idle watchdog measures wall-clock idle time, not "wake-clock" idle time, so 10 min of laptop sleep counts as 10 min of idle.
- On wake, the harness kills the agent rather than reconnecting.
Suggested fixes (from cheapest to best)
1. Acquire a caffeinate -i assertion while subagents are running
While any subagent is in flight, the harness can hold an IOPMAssertionCreateWithName(kIOPMAssertionTypePreventUserIdleSystemSleep, ...) (Apple-platform equivalent of caffeinate -i). Releases when the subagent returns. Easy to wrap on macOS via caffeinate(8) or directly via the IOKit API.
This is the path of least surprise — it just makes the existing code work the way users expect.
2. Distinguish wall-clock idle from "process actually idle"
Track time during which the agent process was actually running (e.g. via clock_gettime(CLOCK_MONOTONIC) ratchets that the kernel pauses during sleep, or via subscribing to IOPMScheduleUserActivity). Don't count laptop-sleep time toward the watchdog.
3. Detect wake events and reconnect the API stream
On wake (IORegisterForSystemPower → kIOMessageSystemHasPoweredOn), the harness can verify whether any open API stream is still alive and, if not, reopen it and ask the model to continue. Stronger fix; more engineering surface.
Workarounds users can apply today
caffeinate -i -s -din a sidecar terminal while running long agentssudo pmset -a sleep 0for the duration of agent-heavy sessions- External display + lid closed (depending on hardware config)
- Disable auto-sleep in System Settings while running agents
But all of these put the burden on the user; the harness should handle this transparently.
Why this matters
Subagent failures from sleep are silent and confidently misleading — the watchdog message says "stream idle timeout" but the actual cause is local power management. Without pmset log inspection, users will assume it's an Anthropic API problem or their network and either retry blindly (wastes time) or stop using subagents (wastes the feature). Surfacing the real cause, or better, preventing it, would be a meaningful reliability win.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗