Idle-stream watchdog — abort a stalled stream, fleet worker + chat (T562, T570)
Claude Code v2.1.196 made a streaming idle watchdog default-on: it aborts and retries a
response stream that produces no events for 5 minutes. LoopAgentAdapter (fleet workers) AND
the interactive chat planner (plannerTurn, T570) share the same StreamWatchdog protection —
a hung upstream (connection open, zero chunks) no longer stalls either surface until the outer
wall-clock cap (fleet) or forever with only the spinner color drifting (chat).
How it works:
- The idle timer resets on every received stream event (chunk); it is armed right before the request is issued, so a provider that never even sends response headers is also caught.
- On
CYBERINE_STREAM_WATCHDOG_MSof silence, the request is aborted on a PRIVATEAbortController— distinct from the caller's ownAbortSignal. What happens next differs by surface:- Fleet workers (
LoopAgentAdapter): one retry on a fresh connection to the SAME model first; if that also stalls, escalate through the SAME fallback-model retry path used for 429/402/5xx overload errors (see "Fallback model chain" above) — trying the next configured model, or failing like any exhausted overload retry when none remain. - Interactive chat (
plannerTurn): no auto-retry and no model switch — the stall is surfaced immediately as a clear, actionable error message (notAbortError-shaped, so it is never mistaken for a silent user-initiated stop) telling the user to retry the message or switch model. This intentionally does not duplicate the fleet's model-fallback logic; it only respects whatever fallback the caller already applies on its own (e.g. the chat's model-cycle toggle).
- Fleet workers (
- A caller-initiated abort (task stop / Ctrl+B / Esc) always wins over the watchdog on both
surfaces: the run is reported
cancelled(fleet) or the abort propagates as the usual silent stop (chat), with no retry, even if the watchdog happened to be armed at the same time.
Run recipe:
# Lower the threshold for a faster-failing dev loop (default is 5 minutes):
CYBERINE_STREAM_WATCHDOG_MS=60000 cyberine run "..."
CYBERINE_STREAM_WATCHDOG_MS=60000 cyberine chat
# Disable the watchdog entirely (opt-out, mirrors CLAUDE_ENABLE_STREAM_WATCHDOG=0):
CYBERINE_STREAM_WATCHDOG_MS=0 cyberine run "..."Env vars:
| Var | Default | Purpose |
|---|---|---|
CYBERINE_STREAM_WATCHDOG_MS | 300000 | Idle-stream watchdog threshold in ms, shared by fleet workers and chat. 0 disables it |
Smoke test: npm run selftest:stream-watchdog (model-free; a local fake SSE server proves the
retry-on-stall, caller-abort-wins, opt-out, and idle-timer-cleared-on-a-genuine-network-error
behaviors without a live provider call).
Background fleet worker — claude --bg (k56eq)
The default claude build worker is an opaque claude -p child: nothing can open it, steer it, or outlive the orchestrator that spawned it. CYBERINECLAUDEWORKERMODE=bg swaps that ONE worker for a...
Worker-internal subagents — delegate_subtask (T313)
Implementer-class loop workers (loop--build) automatically get a delegatesubtask tool that lets the worker spawn a scoped subagent — a focused nested LoopAgentAdapter with its own system prompt, a...