cc-watchdog: dead-man's switch against silent agent-session die-outs#53
Merged
Conversation
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Member-facing docs for cc-watchdog: ONBOARDING step 13 (install + tmux/Herdr note) with two section-C smoke checks, a MAINTAINING rationale entry, and the silent-stall-prevention doctrine block in CLAUDE.global.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Self-clear must distinguish the declaring turn's own transcript tail writes from later resumed activity: cc-deadman runs as a tool call, so bare mtime>set — and any freshness-vs-now window — archives every declared deadline at the first idle tick, leaving idle-at-prompt stalls unalertable. First idle tick now stamps baseline=<transcript mtime>; self-clear requires strictly newer activity. extend strips the baseline. notify() now escapes backslashes/quotes and flattens control chars so a hostile reason can never cost the tier-1 alert. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds a new cc-watchdog onboarding component to detect and remediate “silent stall” Claude Code sessions (dead-man deadlines + periodic watchdog tick), including tmux + Herdr support, hermetic bash unit tests, and onboarding/maintaining documentation plus CI integration.
Changes:
- Introduces
cc-deadmanfor session-side deadline declaration/management andcc-stall-watchdog.shfor timer-driven enforcement (Slack notify + optional recovery injection + backstop scanning for undeclared tmux sessions). - Adds a systemd user timer/service and an installer script to deploy symlinks + units under
~/.local/binand~/.config/systemd/user. - Adds hermetic bash unit tests (PATH shims for tmux/herdr/curl/etc.), docs updates, and a new CI job running shellcheck + the unit test suite.
Reviewed changes
Copilot reviewed 16 out of 17 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| onboarding/watchdog/cc-deadman | Session-side CLI to set/extend/clear/list per-pane deadlines (tmux + Herdr pane keying). |
| onboarding/watchdog/cc-stall-watchdog.sh | Timer-driven watchdog enforcing deadlines, Slack notify, recovery injection/backoff, and tmux backstop scanning. |
| onboarding/watchdog/cc-stall-watchdog.service | systemd user oneshot service unit to run the watchdog script. |
| onboarding/watchdog/cc-stall-watchdog.timer | systemd user timer unit scheduling watchdog execution every 5 minutes. |
| onboarding/watchdog/install.sh | Idempotent installer wiring scripts into ~/.local/bin and installing systemd units/config. |
| onboarding/watchdog/README.md | User-facing documentation: concept, tmux/Herdr behavior, install, smoke test, and unit test instructions. |
| onboarding/watchdog/test/run_tests.sh | Hermetic unit test runner covering notify, tiering, recovery, backstop, Herdr paths, and install idempotence. |
| onboarding/watchdog/test/shims/tmux | tmux test shim used by the hermetic unit tests. |
| onboarding/watchdog/test/shims/pstree | pstree test shim used by the hermetic unit tests. |
| onboarding/watchdog/test/shims/notify-send | notify-send test shim for non-Slack fallback path testing. |
| onboarding/watchdog/test/shims/herdr | herdr CLI test shim for Herdr-pane behavior (status/list/run). |
| onboarding/watchdog/test/shims/curl | curl test shim for Slack webhook posting verification. |
| onboarding/ONBOARDING.md | Adds a new onboarding step explaining cc-watchdog, install, and verification checks. |
| onboarding/MAINTAINING.md | Documents cc-watchdog as the repo’s approach to silent-stall detection (timer-driven vs hook-driven). |
| onboarding/CLAUDE.global.md | Adds a “silent-stall prevention” contract: deadlines before long waits, clear on resume, etc. |
| .github/workflows/ci.yml | Adds a CI job to shellcheck watchdog scripts and run the hermetic unit tests. |
| .gitignore | Ignores docs/superpowers/ working files directory. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+4
to
+6
| [Timer] | ||
| OnBootSec=2min | ||
| OnUnitActiveSec=5min |
Comment on lines
+29
to
+31
| notify() { # $1 = message — escape for the JSON payload; a dropped alert is | ||
| # the one unacceptable failure mode, so backslashes/quotes/control chars | ||
| # must never invalidate the body. |
Comment on lines
+92
to
+96
| set_field() { | ||
| grep -v "^$2=" "$1" > "$1.tmp" || true | ||
| echo "$2=$3" >> "$1.tmp" | ||
| mv "$1.tmp" "$1" | ||
| } |
Comment on lines
+70
to
+73
| old=$(sed -n 's/^deadline=//p' "$f") | ||
| grep -Ev '^(deadline|notified|recovered|failed|recovery_kind|baseline)=' "$f" > "$f.tmp" || true | ||
| echo "deadline=$(( old + $1 * 60 ))" >> "$f.tmp" | ||
| mv "$f.tmp" "$f" |
Quote herdr status keywords (SC1010), drop the dead setts read left by the baseline-stamp redesign (SC2034), guard test cd calls (SC2164), rework cc-deadman arg parsing away from A&&B||C (SC2015), and add reasoned disables where the flagged code is correct (SC2012 mtime-sort ls, SC2001 per-line sed prefix, SC1091 runtime source). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds
onboarding/watchdog/: cc-deadman (session-side deadline declarations, tmux + Herdr pane resolution) + cc-stall-watchdog (systemd user timer, 5 min) with tiered enforcement — baseline-stamped self-clear → Slack notify at deadline miss → pane recovery-injection after a 60-min grace (24 h backoff) — plus a 6 h notify-only backstop for undeclared tmux sessions, hermetic bash unit tests (29, run in CI alongside shellcheck), and onboarding docs (install step 13, smoke checks, silent-stall doctrine in CLAUDE.global.md, MAINTAINING rationale).Motivation: a 36 h silent die-out — a final test suite owned by a stopped subagent died and nothing ever woke the session. Hook-driven watchers cannot see this stall class (they only wake when a turn ends); an independent timer can. Deadlines declared by the session itself keep false positives near zero (a legitimate 2.75 h quiet suite never trips anything).
Herdr-native: inside a Herdr pane, deadlines key to
$HERDR_PANE_ID, busy/idle uses Herdr'sagent_status(ablockedagent cannot self-clear — you get pinged), and recovery usesherdr pane run, degrading gracefully to notify-only if external control is unavailable.Design note: the self-clear condition is baseline-stamped because
cc-deadman setruns as a tool call (transcript writes land after the stamp); both naivemtime>setand freshness-window variants were empirically shown to archive every deadline at the first idle tick. Seeonboarding/MAINTAINING.mdand the regression testtest_wd_self_clear_baseline_sequence.Rollout: install via
onboarding/watchdog/install.sh, soak 2–3 days withWATCHDOG_DRY=1, then arm (and clearstate/pane-*.last-recoverydry-run stamps).🤖 Generated with Claude Code