---
name: agent-fleet
description: Run a self-healing software factory of cheap AI agents on a laptop plus one box, with one task board as the only truth, one integration train as the only door to main, oracles before edits, and a watch loop that rates and improves itself. Use when setting up, auditing, or scaling multi-agent coding fleets.
---

# minifleet: a software factory your agent builds for you

You do not install this. A coding agent reads it and builds a fleet fitted to one person's repo, machines and budget; this file is the spec it builds to and the rubric it is graded by. It is a set of contracts and rules, not a framework. The code that implements them for one project lives in `~/.instacalc/bin` (reference only; copy ideas, not files). Everything below was earned the hard way; each rule has a failure behind it (see `references/failures.md`).

## The shape (one paragraph)

Humans write intent into a **board** (SQLite). A **dispatcher** claims tasks into **lanes** (cheap models first, escalating), each lane working in its own **worktree** from a **pool**. Lanes commit and **ship** to an **integration train** on a separate box that rebases, regenerates, runs light guards and fast-forwards `next`; a heavy gate runs hourly and promotes `next` to `main`. A **supervisor** loop reconciles, reaps stalls, feeds the board from **generators**, opens **canaries**, and alerts. A **watch tick** (a smart model, every ~30 min) reads the numbers, fixes one root cause or launches one improvement, and keeps a 3-line note. The owner only answers questions on a decision list.

## Goals (the spec) and how to grade a fleet against them

Local first · resumable · fast · portable · simple · modular · adaptable · inspectable · self-healing · micro-optimizable · nothing gets stuck without noticing. Grade each A to F with evidence from the last 24 h, not from the design. The questions that expose gaps:

- Local first: does everything run with the box and the internet down, except promote? Can a landing happen on the laptop alone?
- Resumable: after `kill -9` of any process (lane, dispatcher, supervisor, train) does work resume from the last checkpoint with no human step? Is the retry prompt fed the previous attempt's notes?
- Fast: canary claim-to-land under 5 min; train pass under 3 min; queue wait p50 under 2 min for tiny.
- Portable: one config file for paths, runners, box; an `init` that builds the board, pool and services on a fresh machine; no hard-coded home paths or OS-specific schedulers outside one adapter.
- Simple: can a newcomer read the README and name every process in `ps` within 10 minutes? Fewer scripts than you can list from memory; dead ones archived.
- Modular: board, lanes, pool, train, supervisor, watch are replaceable one at a time behind their contracts.
- Adaptable: caps are soft, admission adaptive, rotation data-driven, generators are plug-in sources.
- Inspectable: one command shows a task's whole trail (events, attempts, gate text, transcript link); one command shows the last 10 train passes with step timings; one line shows velocity.
- Self-healing: every failure class in `references/failures.md` has a guard that fires without a human.
- Micro-optimizable: every step has a timing in a log a tool can aggregate (lane setup/think/test, pass steps, generator pass).
- Nothing stuck unnoticed: flow alarms, not only process alarms: queue non-empty with no launch for 10 min; train queue non-empty with no pass for 10 min; `shipped` older than 20 min without a verdict; any status older than 2x its p90; a generator pass adding 0 three times while the board is low; the same guard failing 3 branches in an hour (environment red, not branch red).

## Primitives every fleet has, and the part that is yours

The agent builds your fleet, but it builds it out of a small set of primitives whose SHAPE is the same everywhere. That is what lets two people's fleets be compared, and lets an agent from one fleet read another. Keep the shapes; write the code however fits your repo and language.

| Primitive | Shape (same for everyone) | What varies (yours) |
|---|---|---|
| Board | one SQLite file: `tasks`, `task_events`, `attempts`, ledgers; one writer CLI with the verbs in `contracts.md`; writer-token triggers on every table | the CLI's language, extra columns, your tiers and runners |
| Inbox | a folder of task files (markdown with frontmatter: title, tier, files, check, stages) that an ingest step turns into board rows; humans and agents both drop files there | who writes to it, how often it is swept |
| Prompt | staged (`STAGE n (ship by minute m)`), an `If time runs out` line, a runnable check; linted on `add` | your stage shapes and checks |
| Lanes | one script per model that claims, writes a progress beat every minute, commits by name, ships; cheap first, escalate on evidence | which models, the rotation order, the deadlines; more than one host: `references/machines.md` |
| Pool | N worktrees; claims as files (`<slot>.claim` = task id + epoch); claim/touch/release/retarget; salvage to `wip/<task>` incl. untracked; busy protection for unknown holders | pool size, setup steps, where it lives |
| Train | queue as refs; pass = rebase, regen (scoped then unscoped), light guards, oracle check, fast-forward, push; `passes.jsonl` with step timings; failed verdicts flow back to the board | which guards, which box, the heavy gate's cadence |
| Status | one command; first line is the velocity line `tasks/h X (24h Y) = Z% of target · landings/h ...`; then machines, board, processes, train, alerts | targets, extra sections |
| Alerts | one append-only `ALERTS.md`; `critical:` prefix for alarms; one notification channel | thresholds, channel |
| Decisions | one `DECISIONS.md` the tick appends to and the owner answers in place; nothing else may ask the owner | the questions |
| Digest | one markdown file per program every agent appends to under its own heading; a daily morning report | programs |
| Config | one `fleet.json`: home, repo, worktree root, box (the train), `boxes[]` (every lane host), node, runners with caps, scheduler. Adding a machine: `references/machines.md` | the values |
| Tick | the ritual in `tick.md`; a 3-line note per tick in `watch-notes.md` | cadence, who runs it |

Everything not in this table is yours to invent: guards for your repo, generators for your backlog, oracles for your domain, codemods, dashboards. A sample implementation may exist under `examples/`; treat it as one person's answer, not the answer.

## Eleven rules that carry the weight

1. **The board is the only truth and has one writer.** One SQLite file, one CLI that writes, triggers that refuse every other connection (`RAISE(ABORT)` unless a per-connection token function exists) on EVERY table. Exports (JSONL, dashboards) are read-only views. Reads set a busy timeout; writes retry on lock, then alert loudly. Silent write failure caused the worst incident we had.
2. **Terminal means terminal.** `done`, `shipped`, `cancelled`, `quarantined` are refused by every later writer (finish, reap, deadline kill, adopt), which logs an `ignored` event instead. Cancel kills the lane and drops the lease. A quarantined task is only revived by an explicit requeue.
3. **One front door.** Nothing lands on `next` except through the train; nothing lands on `main` except the promote gate. The train runs: rebase, regen (scoped, then an unscoped catch-up), light guards, corpus/oracle check, push. Per-landing guards stay light (seconds to a minute); the full suites run at promote and failures are bisected back to the landing.
4. **Oracle before edit.** Record current behavior (examples, an edge grid, generated-output bytes, rendered SVG/HTML) before changing anything; after, diff to zero or ledger each intended difference by name. Check that a file is **live** (a build reads it and breaking it changes output) before spending an hour on it. Reads are not compiles.
5. **Never discard work.** Slot salvage commits tracked and untracked files to `wip/<task>` before any reset. A slot held by an unknown-to-the-board agent is never stolen while a process has it open or a file changed in the last 30 minutes. Lanes commit `[wip]` early.
6. **Soft limits, adaptive room.** Caps are ceilings, not targets; the live admission formula is load and RAM (about 1.6x cores active, 2.2x idle). A tiny-task reserve keeps one lane for quick wins. Never lower a cap as a "recommendation"; raise ceilings and let the formula govern.
7. **Cheap first, escalate on evidence.** Rotation: free/flash models first, then mid, then strong. A task reaped twice on the same runner moves one rung up. Deadlines honor the prompt's own "ship by minute N" plus grace, capped. Breakers pause a runner after repeated infra exits; quota exhaustion is an infra class, not a task failure.
8. **Every failure returns to its author with the reason.** A failed train verdict sets `failed_landing` with the gate text, records an attempt outcome, and requeues to the author's runner; the second failure escalates. Generators never re-emit a target with two prior reaps or fails in 24 h.
9. **Everything auditable, token-cheap.** Events and attempts tables, an alerts file that only humans and the tick read, an ops log for config changes (`cap set --why`), a per-program digest file every agent appends to, and a 3-line watch note per tick. Logs link to transcripts; they do not contain them.
10. **The tick improves the factory, not just the product.** Each tick: measure (velocity line, canary claim-to-land minutes, stuck, reconcile dry-run, load), fix one root cause with evidence, or launch one improvement; write the note; surface decisions. Twenty-whys after any storm; the fix is a guard, not a hotfix.

11. **A negative claim needs two methods.** "Missing", "unregistered", "inert", "not running" are never reported from one probe. Print the environment the probe ran in (PATH, user, shell), then confirm by an independent route: absolute paths or a login shell for remote tools (a non-login ssh shell on macOS has no `/opt/homebrew/bin`), the registry's RDAP for a domain (an empty DNS record proves nothing), a deliberate break test for liveness, `pgrep` plus the lease for a process. Never attach an instruction to the owner to a negative claim that has not passed the second method. Put the probe in a tool so the guard is code, not memory.

## Build order (the agent asks five questions first: repo, machines, models and daily budget, what "landed" means, when you sleep)

Each step has an acceptance check; do not start the next until it passes.

### Setup in three days

**Day 1, board and lanes.** SQLite board (`tasks`, `task_events`, `attempts`, plus ledgers) with the writer-token triggers; a CLI with verbs `add next claim finish done cancel hold retry requeue reap landing-failed note get export sql(read-only)`; a prompt lint (stages with minute promises, "If time runs out", a runnable check); one lane script per model that writes a progress beat every minute; a dispatcher with adaptive room, rotation, tiny reserve, breakers, self-reload on stable code.

**Day 2, worktrees and the train.** A pool of N worktrees with claim/touch/release/retarget, salvage incl. untracked, busy protection; a ship script that bundles a branch to the box; the train with scoped+unscoped regen, light guards (build, examples, import check, parse check, `landing-scope`: a rebased branch may not delete or revert a recently landed path its own commits never touched; `builder-sources-parse`: every generator input must parse), union-merge for append-only files, failed-landing feedback; a promote gate for the heavy tier.

**Day 3, healing and watching.** Supervisor loop with periodic blocks (reconcile every 5 min, stall doctor every 2, generators every 10 when todo is low, runner-fit every 10, canary in a 5-minute window twice an hour, digest at 06:00, morning report at 06:30, attempts rebuild, pool refresh at night); a status tool with the velocity line; critical-watch (dispatcher dead, stores diverged, canary red, load high, capacity drift) with OS notifications; the watch tick prompt (see `references/tick.md`).

## Scorecard (what to print every tick)

| Number | Target we use | Why |
|---|---|---|
| tasks/h, landings/h | 33 / 55 | throughput, both halves |
| canary claim to land | under 5 min | the whole pipe, end to end |
| queue wait p50 by tier | tiny under 2 min | starvation shows here first |
| failed landings returned | 100% within 5 min | nothing sits as "shipped" |
| events/min, db lag | nonzero, 0 s | the board is alive and single |
| slots held vs running | equal | no stolen or leaked worktrees |
| load / cores | 1 to 2.5x | soft limits working |

## What makes this spread

Not the code. The three things people can copy in an afternoon: the **one-writer board with triggers**, the **train as the only door** with light guards per landing and the heavy gate at promote, and the **tick ritual** (measure, fix one root cause with evidence, write three lines, surface decisions). Publish the scorecard, the failure catalog, and the twenty-whys template. Keep the reference implementation small and boring.

## Files in this skill

- `references/contracts.md`: table shapes, status lifecycle, verbs, prompt lint, deadline and room formulas, guard list.
- `references/failures.md`: the catalog of root causes we hit and the guard that now prevents each.
- `references/tick.md`: the watch-tick prompt and the decision-list etiquette.
