Subagents killed by stream-idle watchdog when host laptop sleeps

Resolved 💬 3 comments Opened Apr 27, 2026 by CaseyLeask Closed May 1, 2026

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 JSONL version field)
  • macOS Darwin (Apple silicon)
  • Both Bash-tool subagents and worktree-isolated subagents affected

Reproduction

  1. Spawn a long-running subagent (anything that takes > a few minutes — multi-file refactor, big test suite run, etc.).
  2. 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).
  3. Return.
  4. The agent has been killed with Stream idle timeout - partial response received and ~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)

  1. macOS suspends the agent's process and halts its open TCP socket on sleep.
  2. The Anthropic API stream, mid-response, has no retry/recover logic on the agent side — it just sits in the broken-stream state.
  3. 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.
  4. 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 (IORegisterForSystemPowerkIOMessageSystemHasPoweredOn), 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 -d in a sidecar terminal while running long agents
  • sudo pmset -a sleep 0 for 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.

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗