Autopilot — continuous cron agent
State an objective once; the autopilot advances it while you sleep.
The loop
state/goals/<name>.md ← one goal per file (success_criteria, wake_on, priority)
↓
cron: */15 * * * * (when autopilot recipe engaged)
↓
snappy-os autopilot --tick --dispatch
↓
spawn headless claude with:
program.md + state/index.md + goal file + tail of tick log
↓
agent takes ONE concrete step:
a) mark a success_criterion DONE (if reality supports it)
b) write a regen brief for a blocking skill
c) append a friction row
d) edit a skill page or library
e) run a lint/test and record the result
↓
tick row appended to state/log/goals/<name>.ndjson
eval row appended to state/log/evals.ndjson
full transcript written to state/log/goals/transcripts/<name>-<ts>.log
↓
when every success_criterion is met → move file to state/goals/done/
Why this compounds
Alone, a cron that fires a model every 15 minutes is a slot machine. Paired with the rest of snappy-os, it compounds:
- program.md + state/index.md are injected as context — the agent isn't
starting from zero every tick.
- The tick log is memory — each tick reads the last 20 ticks so moves
don't repeat.
- Eval scores + PID — a verb that fails across ticks rewrites itself.
The autopilot's own ticks are eval'd, so the autopilot improves too.
- Frictions persist — a P0 discovered in tick N shapes the system prompt
for tick N+1.
- Canonical is shared across machines — every tenant's autopilot ticks
contribute to the same aggregate.
Safety rails
- Gated: only runs when
autopilotrecipe is engaged instate/engaged.json. - Budget-capped:
--max-budget-usd 1per tick (hard Anthropic cap). - Timeout: 5 minutes per tick (spawnSync timeout).
- Tool allow-list:
Read, Write, Edit, Grep, Glob, Bash(npx tsx *), Bash(node *), Bash(git status/diff/log *). Norm, nogit push, no network shells. - Scoped dir:
--add-dir ~/projects/snappy-os— nothing outside. - Auditable: full transcript per tick written to
state/log/goals/transcripts/. - Reversible: every change is git-trackable; if a tick goes sideways,
git diff+ revert.
Goal file shape
---
name: finish-snappy-os
title: Ship snappy-os end-to-end
status: open
priority: 1
created: 2026-04-17
owner: robert
success_criteria:
- doctor is 21/21 on Robert's MBP — DONE 2026-04-17
- Fresh-install smoke passes on Ubuntu container
- At least one quorum promotion has landed
wake_on:
- cron:*/15
- friction:p0
---
# finish-snappy-os
Longer-form context. What "done" looks like. Blockers. Next actions.
Tick scripts
state/bin/autopilot/break.sh # one breaker tick (finds + logs an open row)
state/bin/autopilot/fix.sh # one fixer tick (resolves an open row)
cat state/engaged.json # list engaged recipes
Wiring the cron (manual for now)
Add to crontab:
0,30 * * * * cd ~/projects/snappy-os && state/bin/autopilot/break.sh >> ~/.claude/logs/snappy-os-breaker.log 2>&1
15,45 * * * * cd ~/projects/snappy-os && state/bin/autopilot/fix.sh >> ~/.claude/logs/snappy-os-fixer.log 2>&1
Engage by adding "autopilot" to the recipes array in state/engaged.json. First tick lands within 30 minutes.
When to disengage
- You're mid-edit on a skill the autopilot is likely to touch.
- Cost-sensitive period (Anthropic cap notwithstanding, $1 × 96 ticks/day = $96/day worst case; usually nowhere near).
- Debugging the goals system itself.
The design choice this represents
Between "human in the loop for every step" (high-friction, doesn't scale) and "fully autonomous agents with no off switch" (terrifying), autopilot picks a middle path: state an objective, the cron advances it, you can turn it off any time. The human owns the goal, the agent owns the tick.