/babysit — autonomous watch · fix · deploy · re-check loop
Babysit a running service so you don't have to. Each tick: read only new
logs, decide healthy-or-not, and — if not — hand a bounded fix to a sub-agent,
deploy it, and verify. Loop until you cancel. Call you (sound every 30s) only
when stuck or when a change is too risky to make unattended.
Claude Code only. This skill needs the native /loop cadence, the Agent
tool, and (optionally) a deploy MCP. Codex has no in-session loop primitive, so
there is no Codex variant — on Codex, drive a single /babysit tick from an
external cron + codex exec instead.
Letter = spirit. If a rule blocks you from reaching the goal it was written
for, the rule is wrong, not the goal. Don't look for a wording loophole — ask
what the rule protects, and protect that. Here the goal is: keep the service
healthy without surprising the operator. When in doubt, escalate; never
deploy a guess.
Deploy / log adapter (platform-agnostic)
babysit talks to your service through two shell commands — nothing platform-specific is assumed:
log_cmd — prints recent logs to stdout. Examples: ssh prod 'journalctl -u app --since "-6min" --no-pager', docker logs --since 6m <c>, kubectl logs --since=6m deploy/app, tail -n 200 /var/log/app.log.
deploy_cmd — ships the committed fix. Examples: git push deploy main, make deploy, flyctl deploy, kubectl rollout restart deploy/app.
rollback_cmd (optional) — one-step undo. Examples: git revert HEAD && git push deploy main, re-deploy the prior good build. If absent, babysit escalates instead of auto-undoing.
If you happen to run a platform with an MCP (e.g. coolify, or any other), you may point these at MCP tools instead of shell — resolve the app/resource id once at setup, and note which tool fetches logs, which deploys, and how to poll a deploy to a terminal state. The adapter is the contract; the backend is your choice.
Weaknesses and when NOT to use
- It deploys to a real environment unattended. That is the whole point and
the whole danger. Use only where a bad deploy is recoverable (CI gate,
health check, easy rollback). Never point it at something where one wrong
push is unrecoverable (irreversible migration, payment cutover, data wipe).
- Only as good as its trouble-definition. If "wrong" is vague, it either
ignores real fires or thrashes on benign noise. Spend the setup minute making
the definition concrete (patterns, health check, thresholds).
- A fix loop can mask a design flaw. Two failed fixes on the same signature
means stop and think, not "try a third agent". That's why recurrence
escalates instead of retrying forever.
- Not a monitoring system. No SLOs, no historical dashboards, no paging
integration. It's a babysitter for a session, not Datadog. For real on-call,
wire a real pager.
- Needs a reachable signal. If it can't read logs and can't run a health
check, it can't observe — it escalates and stops (a blind babysitter is worse
than none).
Three autonomy modes (default: full-auto)
| mode |
on trouble |
| full-auto |
sub-agent fixes → deploy → verify → loop. Escalate only on the triggers below. |
| fix-ask-deploy |
sub-agent prepares + commits the fix, then escalates for approval before deploying. |
| observe |
never touches code or deploy. Detects trouble → escalates. You fix. |
Mode is chosen at setup and stored in config.json; /babysit resume keeps it.
State on disk (.babysit/ in the target project — gitignored)
.babysit/
config.json # log_cmd, trouble-definition, deploy_cmd, interval, mode, guardrails
state.json # iteration #, log cursor, open incidents, per-signature fix attempts, deploy history, status
babysit.log # append-only audit trail (one line per event)
incidents/ # one file per escalation: logs excerpt + classification + agent summary + deploy result
alert.sh # escalation sound/notify loop (written at setup)
alert.pid # PID of a running alert loop (absent = silent)
alert.stop # touch this to silence the alert; remove to allow it again
Everything the loop needs lives here. Each tick re-reads disk, not the
conversation — so context never accumulates across hours of ticking. This is
the core context-economy trick; honour it (don't re-summarise prior ticks into
context, read state.json).
What counts as a problem (trouble_definition)
Concrete, in priority order — match any → it's a problem:
- Health check fails —
health_cmd exits non-zero, or health_url is not 2xx.
- Error patterns — new log lines matching the user's regex/signatures
(e.g.
FATAL, panic:, Traceback, 5\d\d , OOMKilled, connection refused).
- Error-rate threshold — matches/min over the user's limit.
- Crash/restart loop — repeated process restarts in the window.
Only new lines (since state.log_cursor) count, so a pre-existing error
logged once at boot doesn't re-trigger every tick.
Phase 0 — Resolve what to do
Read the argument the skill was invoked with (the text after /babysit, or the
user's stated intent), then:
stop → STOP (below). status → STATUS. resume → re-arm an existing config.
- No
.babysit/config.json → SETUP (first run).
- Otherwise → ITERATE (one tick; this is what
/loop re-fires).
Phase 1 — SETUP (first run only)
- Gather config. Prefer parsing the invocation / nearby notes; ask only what's
missing, via one
AskUserQuestion (≤4 questions, don't interrogate):
project_dir — repo to fix in (default: cwd).
log_cmd — a shell command that prints recent logs (see the adapter section).
If using a logs MCP instead, resolve the app/resource id once and note the tool.
health_cmd and/or health_url — optional but strongly recommended; it's
the cheapest, least-ambiguous signal and the post-deploy verifier.
trouble_definition — patterns / thresholds (see above). Get something
concrete; a vague definition is the #1 failure mode.
deploy_cmd — the shell command that ships a fix (see the adapter section).
If using a deploy MCP instead, note the resource id, the deploy tool, and how
to poll it to a terminal state. Optionally rollback_cmd.
commit_branch — branch the fix is committed to (default: current branch).
Heed the global rule about not committing to main unless main is the
deploy branch — for a prod hotfix loop it often is; confirm, don't assume.
interval — e.g. 5m (this is the /loop cadence, "every N").
mode — full-auto | fix-ask-deploy | observe (default full-auto).
- Guardrails (defaults, override on request):
max_fix_attempts_per_signature: 2, max_deploys_per_hour: 4,
max_blind_ticks: 3 (consecutive ticks with no readable signal → escalate),
max_iterations: null (until stopped).
- Write
.babysit/config.json and seed .babysit/state.json
({iteration:0, log_cursor:null, status:"baseline", incidents:[], signatures:{}, deploys:[], loop_armed:false}).
- Write
.babysit/alert.sh (script below) and ensure .babysit/ is in the
target project's .gitignore (append if absent).
- Baseline tick (observe-only, no fix/deploy). Read current logs, set
log_cursor to "now", note what normal looks like. This stops babysit from
firing on a pre-existing error the moment it starts. Record the baseline.
- Arm the cadence. Invoke the native
loop skill with
args: "<interval> /babysit" (e.g. 5m /babysit) so /babysit re-fires
every interval, then set state.loop_armed = true. If programmatic arming
isn't available, fall back to: tell the user to run /loop <interval> /babysit,
and/or self-pace with ScheduleWakeup (prompt "/loop /babysit").
Idempotency: never arm twice — if loop_armed is already true, skip.
- Report: mode, interval, what counts as trouble, how to
stop/status.
Then stop this turn — the loop takes over.
Phase 2 — ITERATE (one tick — runs every interval)
Keep this tick cheap and shallow — its job is triage, not investigation.
- Load
config.json + state.json from disk. iteration++.
- Fetch only new logs since
state.log_cursor (run log_cmd); advance the cursor.
Run health_cmd/health_url if configured.
- Signal unreachable (logs error AND no health signal):
blind_ticks++.
If blind_ticks ≥ max_blind_ticks → ESCALATE ("can't observe"). Else
record and return (try again next tick).
- Classify against
trouble_definition. Healthy → reset blind_ticks,
write a heartbeat line, return. (Don't spend tokens; this is the common path.)
- Problem → compute a normalized error signature (strip timestamps,
ids, line numbers) to track recurrence. Then:
- Recurrence guard: if
signatures[sig].fix_attempts ≥ max_fix_attempts
→ ESCALATE ("fix didn't hold"). Do not try again.
- Rate guard: if deploys in the last hour ≥
max_deploys_per_hour
→ ESCALATE ("deploy storm") and back off.
- mode = observe → ESCALATE ("trouble, you fix"). Done.
- Otherwise delegate the fix (Phase 3).
- After Phase 3 returns, act on the verdict (Phase 4).
- Record the tick to
state.json + append babysit.log. Return — /loop
re-fires after the interval.
Phase 3 — Delegate the fix to a sub-agent (context economy)
Never diagnose/fix in the main loop — that bloats context across hours.
Spawn one Agent (subagent_type general-purpose; Explore first if the cause
is unclear) with a bounded brief:
You are fixing one production incident. Working dir: <project_dir>, deploy
branch <commit_branch>.
Logs (new lines this tick): <excerpt>. Signature: <sig>.
Health: <health output>. Trouble definition: <…>.
Do: reproduce/locate root cause → make the smallest correct fix → run the
project's tests/build/linters if they exist → commit to <commit_branch> with
a clear message. Do NOT deploy. Do NOT make schema/data migrations,
touch secrets, or do anything irreversible — if the fix needs that, STOP and
report needs_human.
Return ONLY this (your final message is data, not prose):
fixed: <bool> · root_cause: <one line> · files: <list> ·
commit: <sha|none> · confidence: <low|med|high> ·
needs_human: <bool> · reason: <if needs_human or not fixed>.
Only that structured summary returns to the loop. The full investigation stays
in the sub-agent's context and is discarded — the babysitter stays light.
Phase 4 — Act on the verdict
needs_human:true OR fixed:false OR confidence:low → ESCALATE with the
agent's reason. Don't deploy a fix you don't trust.
- mode = fix-ask-deploy and
fixed:true → ESCALATE for approval
(status:"pending-approval", stash the commit sha). Deploy only after the
operator approves on a later tick.
- mode = full-auto and
fixed:true, confidence:med|high → DEPLOY:
run deploy_cmd (or your deploy MCP's deploy, polled to a terminal state).
Record {ts, sig, commit, result} in state.deploys.
- Verify (the deploy isn't done until it's verified): wait for it to
settle, fetch fresh logs + health.
- Healthy → mark incident resolved,
signatures[sig].fix_attempts++
stays as the count that worked; clear status. 🎉
- Still broken / worse than baseline →
signatures[sig].fix_attempts++;
if now ≥ max_fix_attempts → ESCALATE ("fix didn't hold") and, if a
one-step rollback exists (rollback_cmd / re-deploy the prior good build),
roll back and say so. If no safe rollback, escalate loudly and stop
touching prod.
ESCALATE — "call me until I come"
This is the only path that makes noise. Trigger it for the things below; for
anything else, keep quiet and keep working.
Escalation triggers (the "100% needs a human" set):
- Sub-agent
needs_human / no fix / low confidence.
- Same signature unresolved after
max_fix_attempts fixes.
- Deploy command/MCP failed, or post-deploy health is worse than baseline.
- Security signal in logs (auth bypass, leaked secret, active exploit) — escalate
immediately, before any fix.
- Data-loss / irreversible risk detected.
blind_ticks ≥ max_blind_ticks (can't observe).
max_deploys_per_hour tripped (thrash protection).
mode = observe (any problem) or mode = fix-ask-deploy (fix ready → approval).
How to escalate:
- Write the incident to
.babysit/incidents/<iso-ts>-<sig>.md (log excerpt,
classification, agent summary, deploy result, recommended human action).
- Fire the
PushNotification tool with a one-line summary + the incident path.
- Start the sound (only if not already ringing — check
alert.pid):
rm -f .babysit/alert.stop then run .babysit/alert.sh "<short reason>" with
run_in_background: true. It beeps + notify-sends every 30s until
silenced or capped (20 min), so you can't sleep through it.
- Set
state.status = "escalated" and stop auto-fixing this signature — the
loop may keep observing on its cadence, but it will not re-attempt the wall
it just hit. Don't spin.
- When the operator returns (next interactive turn while escalated):
touch .babysit/alert.stop to silence the alarm, summarise the incident, take
their decision (approve deploy / hand back to auto / stop), clear the status.
.babysit/alert.sh (write this verbatim at setup)
#!/usr/bin/env bash
# babysit escalation: beep + desktop-notify every 30s until silenced or capped.
# silence: `touch .babysit/alert.stop` · re-arm: remove that file.
set -u
DIR="$(cd "$(dirname "$0")" && pwd)"
MSG="${1:-babysit needs you}"
MAX="${2:-40}" # 40 * 30s ≈ 20 min hard cap (no runaway)
SND="/usr/share/sounds/freedesktop/stereo/alarm-clock-elapsed.oga"
echo $$ > "$DIR/alert.pid"
trap 'rm -f "$DIR/alert.pid"' EXIT
play() {
if command -v pw-play >/dev/null 2>&1; then pw-play "$SND" 2>/dev/null
elif command -v paplay >/dev/null 2>&1; then paplay "$SND" 2>/dev/null
elif command -v canberra-gtk-play >/dev/null 2>&1; then canberra-gtk-play -i alarm-clock-elapsed 2>/dev/null
elif command -v aplay >/dev/null 2>&1; then aplay -q "$SND" 2>/dev/null
else printf '\a'; fi
}
for _ in $(seq 1 "$MAX"); do
[ -f "$DIR/alert.stop" ] && break
command -v notify-send >/dev/null 2>&1 && notify-send -u critical "🔔 babysit" "$MSG"
play
sleep 30
done
rm -f "$DIR/alert.pid"
STOP / STATUS / RESUME
- STOP (
/babysit stop): touch .babysit/alert.stop (silence), cancel the
/loop (stop the loop skill / drop the ScheduleWakeup), set
state.status="stopped", print a session summary (ticks, incidents, deploys).
- STATUS (
/babysit status): print mode, interval, last few ticks, open
incidents, recent deploys, whether the alarm is ringing. No side effects.
- RESUME (
/babysit resume): re-arm the cadence for an existing config
(e.g. after a restart) without redoing setup.
How to do it wrong vs right
❌ Diagnose and edit in the main loop → context balloons over hours; the loop
gets slower and dumber each tick.
✅ Triage cheaply in the loop; delegate every fix to a fresh sub-agent; keep only
the structured verdict.
❌ Re-trigger on the same boot-time error every single tick.
✅ Track a log_cursor; only new lines count.
❌ Retry a failing fix a third, fourth, fifth time.
✅ Two strikes on a signature → escalate. Repetition without new information is
not progress.
❌ Deploy a low-confidence fix because the loop "should keep moving".
✅ Low confidence / needs_human / no rollback path → make noise, stop, wait.
❌ Beep forever / leave a runaway background process.
✅ Capped alert (20 min) + a alert.stop file + PID file; silenced the moment
the operator engages.
Senior-operator self-check (before each deploy / escalation)
- Is "trouble" real (matches the definition on new lines) or am I chasing noise?
- Is this fix the smallest correct change, committed to the right branch?
- Can I undo this deploy in one step if it's wrong? If not — should I be deploying
at all unattended?
- Have I hit this exact wall before? (Check
signatures[sig].) If yes — escalate.
- Am I about to do something irreversible or security-sensitive? → escalate, never auto.
1---2name: babysit3description: Autonomous watch → fix → deploy → recheck LOOP for a running service: every N minutes it reads only NEW logs and, on trouble, delegates a bounded fix to a sub-agent, ships it via your `deploy_cmd` (or a deploy MCP), and verifies — repeating until you stop it. Escalates with a repeating sound + desktop notification only when stuck or a change is unsafe. Use ONLY when the user explicitly wants this ongoing UNATTENDED loop — not a one-off log read, health check, or single fix. Claude Code only (needs the native /loop). Triggers: "/babysit", "babysit the service", "watch and auto-fix/deploy", "keep the service healthy unattended", "присматривай за сервисом".4---56# /babysit — autonomous watch · fix · deploy · re-check loop78Babysit a running service so you don't have to. Each tick: read **only new9logs**, decide healthy-or-not, and — if not — hand a bounded fix to a sub-agent,10deploy it, and verify. Loop until you cancel. Call you (sound every 30s) **only**11when stuck or when a change is too risky to make unattended.1213> **Claude Code only.** This skill needs the native `/loop` cadence, the `Agent`14> tool, and (optionally) a deploy MCP. Codex has no in-session loop primitive, so15> there is no Codex variant — on Codex, drive a single `/babysit` tick from an16> external cron + `codex exec` instead.1718> **Letter = spirit.** If a rule blocks you from reaching the goal it was written19> for, the rule is wrong, not the goal. Don't look for a wording loophole — ask20> what the rule protects, and protect that. Here the goal is: keep the service21> healthy *without* surprising the operator. When in doubt, escalate; never22> deploy a guess.2324## Deploy / log adapter (platform-agnostic)2526babysit talks to your service through **two shell commands** — nothing platform-specific is assumed:2728- **`log_cmd`** — prints recent logs to stdout. Examples: `ssh prod 'journalctl -u app --since "-6min" --no-pager'`, `docker logs --since 6m <c>`, `kubectl logs --since=6m deploy/app`, `tail -n 200 /var/log/app.log`.29- **`deploy_cmd`** — ships the committed fix. Examples: `git push deploy main`, `make deploy`, `flyctl deploy`, `kubectl rollout restart deploy/app`.30- **`rollback_cmd`** *(optional)* — one-step undo. Examples: `git revert HEAD && git push deploy main`, re-deploy the prior good build. If absent, babysit escalates instead of auto-undoing.3132If you happen to run a platform with an MCP (e.g. **coolify**, or any other), you may point these at MCP tools instead of shell — resolve the app/resource id once at setup, and note which tool fetches logs, which deploys, and how to poll a deploy to a terminal state. The adapter is the contract; the backend is your choice.3334## Weaknesses and when NOT to use3536- **It deploys to a real environment unattended.** That is the whole point and37 the whole danger. Use only where a bad deploy is *recoverable* (CI gate,38 health check, easy rollback). Never point it at something where one wrong39 push is unrecoverable (irreversible migration, payment cutover, data wipe).40- **Only as good as its trouble-definition.** If "wrong" is vague, it either41 ignores real fires or thrashes on benign noise. Spend the setup minute making42 the definition concrete (patterns, health check, thresholds).43- **A fix loop can mask a design flaw.** Two failed fixes on the same signature44 means *stop and think*, not "try a third agent". That's why recurrence45 escalates instead of retrying forever.46- **Not a monitoring system.** No SLOs, no historical dashboards, no paging47 integration. It's a babysitter for a session, not Datadog. For real on-call,48 wire a real pager.49- **Needs a reachable signal.** If it can't read logs *and* can't run a health50 check, it can't observe — it escalates and stops (a blind babysitter is worse51 than none).5253## Three autonomy modes (default: **full-auto**)5455| mode | on trouble |56|---|---|57| **full-auto** | sub-agent fixes → **deploy** → verify → loop. Escalate only on the triggers below. |58| **fix-ask-deploy** | sub-agent prepares + commits the fix, then **escalates for approval** before deploying. |59| **observe** | never touches code or deploy. Detects trouble → **escalates**. You fix. |6061Mode is chosen at setup and stored in `config.json`; `/babysit resume` keeps it.6263## State on disk (`.babysit/` in the target project — gitignored)6465```66.babysit/67 config.json # log_cmd, trouble-definition, deploy_cmd, interval, mode, guardrails68 state.json # iteration #, log cursor, open incidents, per-signature fix attempts, deploy history, status69 babysit.log # append-only audit trail (one line per event)70 incidents/ # one file per escalation: logs excerpt + classification + agent summary + deploy result71 alert.sh # escalation sound/notify loop (written at setup)72 alert.pid # PID of a running alert loop (absent = silent)73 alert.stop # touch this to silence the alert; remove to allow it again74```7576Everything the loop needs lives here. **Each tick re-reads disk, not the77conversation** — so context never accumulates across hours of ticking. This is78the core context-economy trick; honour it (don't re-summarise prior ticks into79context, read `state.json`).8081## What counts as a problem (`trouble_definition`)8283Concrete, in priority order — match any → it's a problem:841. **Health check fails** — `health_cmd` exits non-zero, or `health_url` is not 2xx.852. **Error patterns** — new log lines matching the user's regex/signatures86 (e.g. `FATAL`, `panic:`, `Traceback`, `5\d\d `, `OOMKilled`, `connection refused`).873. **Error-rate threshold** — matches/min over the user's limit.884. **Crash/restart loop** — repeated process restarts in the window.8990Only **new** lines (since `state.log_cursor`) count, so a pre-existing error91logged once at boot doesn't re-trigger every tick.9293---9495## Phase 0 — Resolve what to do9697Read the argument the skill was invoked with (the text after `/babysit`, or the98user's stated intent), then:99100- `stop` → **STOP** (below). `status` → **STATUS**. `resume` → re-arm an existing config.101- No `.babysit/config.json` → **SETUP** (first run).102- Otherwise → **ITERATE** (one tick; this is what `/loop` re-fires).103104## Phase 1 — SETUP (first run only)1051061. **Gather config.** Prefer parsing the invocation / nearby notes; ask only what's107 missing, via **one** `AskUserQuestion` (≤4 questions, don't interrogate):108 - `project_dir` — repo to fix in (default: cwd).109 - `log_cmd` — a shell command that prints recent logs (see the adapter section).110 If using a logs MCP instead, resolve the app/resource id once and note the tool.111 - `health_cmd` and/or `health_url` — optional but strongly recommended; it's112 the cheapest, least-ambiguous signal and the post-deploy verifier.113 - `trouble_definition` — patterns / thresholds (see above). Get something114 concrete; a vague definition is the #1 failure mode.115 - `deploy_cmd` — the shell command that ships a fix (see the adapter section).116 If using a deploy MCP instead, note the resource id, the deploy tool, and how117 to poll it to a terminal state. Optionally `rollback_cmd`.118 - `commit_branch` — branch the fix is committed to (default: current branch).119 Heed the global rule about not committing to `main` *unless* `main` is the120 deploy branch — for a prod hotfix loop it often is; confirm, don't assume.121 - `interval` — e.g. `5m` (this is the `/loop` cadence, "every N").122 - `mode` — full-auto | fix-ask-deploy | observe (default **full-auto**).123 - **Guardrails** (defaults, override on request):124 `max_fix_attempts_per_signature: 2`, `max_deploys_per_hour: 4`,125 `max_blind_ticks: 3` (consecutive ticks with no readable signal → escalate),126 `max_iterations: null` (until stopped).1272. **Write** `.babysit/config.json` and seed `.babysit/state.json`128 (`{iteration:0, log_cursor:null, status:"baseline", incidents:[], signatures:{}, deploys:[], loop_armed:false}`).1293. **Write `.babysit/alert.sh`** (script below) and ensure `.babysit/` is in the130 target project's `.gitignore` (append if absent).1314. **Baseline tick (observe-only, no fix/deploy).** Read current logs, set132 `log_cursor` to "now", note what *normal* looks like. This stops babysit from133 firing on a pre-existing error the moment it starts. Record the baseline.1345. **Arm the cadence.** Invoke the native **`loop`** skill with135 `args: "<interval> /babysit"` (e.g. `5m /babysit`) so `/babysit` re-fires136 every interval, then set `state.loop_armed = true`. If programmatic arming137 isn't available, fall back to: tell the user to run `/loop <interval> /babysit`,138 and/or self-pace with `ScheduleWakeup` (prompt `"/loop /babysit"`).139 **Idempotency:** never arm twice — if `loop_armed` is already true, skip.1406. **Report**: mode, interval, what counts as trouble, how to `stop`/`status`.141 Then stop this turn — the loop takes over.142143## Phase 2 — ITERATE (one tick — runs every interval)144145Keep this tick **cheap and shallow** — its job is triage, not investigation.1461471. **Load** `config.json` + `state.json` from disk. `iteration++`.1482. **Fetch only new logs** since `state.log_cursor` (run `log_cmd`); advance the cursor.149 Run `health_cmd`/`health_url` if configured.150 - **Signal unreachable** (logs error AND no health signal): `blind_ticks++`.151 If `blind_ticks ≥ max_blind_ticks` → **ESCALATE** ("can't observe"). Else152 record and return (try again next tick).1533. **Classify** against `trouble_definition`. Healthy → reset `blind_ticks`,154 write a heartbeat line, return. (Don't spend tokens; this is the common path.)1554. **Problem** → compute a normalized **error signature** (strip timestamps,156 ids, line numbers) to track recurrence. Then:157 - **Recurrence guard:** if `signatures[sig].fix_attempts ≥ max_fix_attempts`158 → **ESCALATE** ("fix didn't hold"). Do **not** try again.159 - **Rate guard:** if deploys in the last hour ≥ `max_deploys_per_hour`160 → **ESCALATE** ("deploy storm") and back off.161 - **mode = observe** → **ESCALATE** ("trouble, you fix"). Done.162 - Otherwise **delegate the fix** (Phase 3).1635. After Phase 3 returns, **act on the verdict** (Phase 4).1646. **Record** the tick to `state.json` + append `babysit.log`. Return — `/loop`165 re-fires after the interval.166167## Phase 3 — Delegate the fix to a sub-agent (context economy)168169**Never diagnose/fix in the main loop** — that bloats context across hours.170Spawn one `Agent` (subagent_type `general-purpose`; `Explore` first if the cause171is unclear) with a **bounded** brief:172173> You are fixing one production incident. Working dir: `<project_dir>`, deploy174> branch `<commit_branch>`.175> **Logs (new lines this tick):** `<excerpt>`. **Signature:** `<sig>`.176> **Health:** `<health output>`. **Trouble definition:** `<…>`.177> Do: reproduce/locate root cause → make the **smallest** correct fix → run the178> project's tests/build/linters if they exist → commit to `<commit_branch>` with179> a clear message. Do **NOT** deploy. Do **NOT** make schema/data migrations,180> touch secrets, or do anything irreversible — if the fix needs that, STOP and181> report `needs_human`.182> Return ONLY this (your final message is data, not prose):183> `fixed: <bool>` · `root_cause: <one line>` · `files: <list>` ·184> `commit: <sha|none>` · `confidence: <low|med|high>` ·185> `needs_human: <bool>` · `reason: <if needs_human or not fixed>`.186187Only that structured summary returns to the loop. The full investigation stays188in the sub-agent's context and is discarded — the babysitter stays light.189190## Phase 4 — Act on the verdict191192- `needs_human:true` OR `fixed:false` OR `confidence:low` → **ESCALATE** with the193 agent's `reason`. Don't deploy a fix you don't trust.194- **mode = fix-ask-deploy** and `fixed:true` → **ESCALATE for approval**195 (`status:"pending-approval"`, stash the commit sha). Deploy only after the196 operator approves on a later tick.197- **mode = full-auto** and `fixed:true`, `confidence:med|high` → **DEPLOY**:198 run `deploy_cmd` (or your deploy MCP's deploy, polled to a terminal state).199 Record `{ts, sig, commit, result}` in `state.deploys`.200 - **Verify** (the deploy isn't done until it's verified): wait for it to201 settle, fetch fresh logs + health.202 - **Healthy** → mark incident resolved, `signatures[sig].fix_attempts++`203 stays as the count that worked; clear status. 🎉204 - **Still broken / worse than baseline** → `signatures[sig].fix_attempts++`;205 if now `≥ max_fix_attempts` → **ESCALATE** ("fix didn't hold") and, if a206 one-step rollback exists (`rollback_cmd` / re-deploy the prior good build),207 **roll back** and say so. If no safe rollback, escalate loudly and stop208 touching prod.209210## ESCALATE — "call me until I come"211212This is the only path that makes noise. Trigger it for the things below; for213anything else, keep quiet and keep working.214215**Escalation triggers** (the "100% needs a human" set):216- Sub-agent `needs_human` / no fix / low confidence.217- Same signature unresolved after `max_fix_attempts` fixes.218- Deploy command/MCP failed, or post-deploy health is **worse** than baseline.219- Security signal in logs (auth bypass, leaked secret, active exploit) — escalate220 **immediately**, before any fix.221- Data-loss / irreversible risk detected.222- `blind_ticks ≥ max_blind_ticks` (can't observe).223- `max_deploys_per_hour` tripped (thrash protection).224- `mode = observe` (any problem) or `mode = fix-ask-deploy` (fix ready → approval).225226**How to escalate:**2271. Write the incident to `.babysit/incidents/<iso-ts>-<sig>.md` (log excerpt,228 classification, agent summary, deploy result, recommended human action).2292. Fire the `PushNotification` tool with a one-line summary + the incident path.2303. **Start the sound** (only if not already ringing — check `alert.pid`):231 `rm -f .babysit/alert.stop` then run `.babysit/alert.sh "<short reason>"` with232 **run_in_background: true**. It beeps + `notify-send`s every 30s until233 silenced or capped (20 min), so you can't sleep through it.2344. Set `state.status = "escalated"` and **stop auto-fixing this signature** — the235 loop may keep *observing* on its cadence, but it will not re-attempt the wall236 it just hit. Don't spin.2375. **When the operator returns** (next interactive turn while escalated):238 `touch .babysit/alert.stop` to silence the alarm, summarise the incident, take239 their decision (approve deploy / hand back to auto / stop), clear the status.240241### `.babysit/alert.sh` (write this verbatim at setup)242243```bash244#!/usr/bin/env bash245# babysit escalation: beep + desktop-notify every 30s until silenced or capped.246# silence: `touch .babysit/alert.stop` · re-arm: remove that file.247set -u248DIR="$(cd "$(dirname "$0")" && pwd)"249MSG="${1:-babysit needs you}"250MAX="${2:-40}" # 40 * 30s ≈ 20 min hard cap (no runaway)251SND="/usr/share/sounds/freedesktop/stereo/alarm-clock-elapsed.oga"252echo $$ > "$DIR/alert.pid"253trap 'rm -f "$DIR/alert.pid"' EXIT254play() {255 if command -v pw-play >/dev/null 2>&1; then pw-play "$SND" 2>/dev/null256 elif command -v paplay >/dev/null 2>&1; then paplay "$SND" 2>/dev/null257 elif command -v canberra-gtk-play >/dev/null 2>&1; then canberra-gtk-play -i alarm-clock-elapsed 2>/dev/null258 elif command -v aplay >/dev/null 2>&1; then aplay -q "$SND" 2>/dev/null259 else printf '\a'; fi260}261for _ in $(seq 1 "$MAX"); do262 [ -f "$DIR/alert.stop" ] && break263 command -v notify-send >/dev/null 2>&1 && notify-send -u critical "🔔 babysit" "$MSG"264 play265 sleep 30266done267rm -f "$DIR/alert.pid"268```269270## STOP / STATUS / RESUME271272- **STOP** (`/babysit stop`): `touch .babysit/alert.stop` (silence), cancel the273 `/loop` (stop the loop skill / drop the ScheduleWakeup), set274 `state.status="stopped"`, print a session summary (ticks, incidents, deploys).275- **STATUS** (`/babysit status`): print mode, interval, last few ticks, open276 incidents, recent deploys, whether the alarm is ringing. No side effects.277- **RESUME** (`/babysit resume`): re-arm the cadence for an existing config278 (e.g. after a restart) without redoing setup.279280## How to do it wrong vs right281282❌ Diagnose and edit in the main loop → context balloons over hours; the loop283 gets slower and dumber each tick.284✅ Triage cheaply in the loop; delegate every fix to a fresh sub-agent; keep only285 the structured verdict.286287❌ Re-trigger on the same boot-time error every single tick.288✅ Track a `log_cursor`; only **new** lines count.289290❌ Retry a failing fix a third, fourth, fifth time.291✅ Two strikes on a signature → escalate. Repetition without new information is292 not progress.293294❌ Deploy a `low`-confidence fix because the loop "should keep moving".295✅ Low confidence / `needs_human` / no rollback path → make noise, stop, wait.296297❌ Beep forever / leave a runaway background process.298✅ Capped alert (20 min) + a `alert.stop` file + PID file; silenced the moment299 the operator engages.300301## Senior-operator self-check (before each deploy / escalation)302303- Is "trouble" real (matches the definition on **new** lines) or am I chasing noise?304- Is this fix the *smallest* correct change, committed to the right branch?305- Can I undo this deploy in one step if it's wrong? If not — should I be deploying306 at all unattended?307- Have I hit this exact wall before? (Check `signatures[sig]`.) If yes — escalate.308- Am I about to do something irreversible or security-sensitive? → escalate, never auto.