fleet is a harness that makes AI coding agents produce work you can check.
It is not a model and it does not call one directly. It drives the harnesses you already have
installed — claude and codex — and wraps them in the thing they lack: a gate that refuses an
ambiguous task, a second agent that independently verifies the first, a receipt for every run, and
a bar that treats "the tests passed" as the floor rather than the finish line.
The premise, paid for in this repo: an agent that reports success is not an agent that succeeded.
PRINCIPLES.md is 19 corrections the owner had to give, several of them six times.
bash fleet/install.sh # once
fleet # then, in any projectType fleet in any directory. It opens a terminal UI scoped to that directory, discovers what
that project makes available, and puts the harnesses on your task.
- Skills from
.claude/skills/*/SKILL.md— workspace, then this repo, then$HOME, nearest wins. Each message is matched against them and the matches are printed before the turn, so a wrong match is visible rather than silently steering the run. - Slash commands from
.claude/commands/*.md, plus all 38fleetverbs as/<verb>. - MCP servers from
.mcp.json/~/.claude.json, each reportedavailable/absent/declared— never assumed present. - House rules: this repo's
PRINCIPLES.md, plus the workspace's ownCLAUDE.md/AGENTS.md.
shift+tab cycles three modes:
| mode | what happens |
|---|---|
solo |
one harness answers, streamed, tool calls shown live |
fanout |
both harnesses on the same task, role-split: one builds, one verifies read-only |
fleet |
hands off to fleet run — the gated pipeline below |
Fan-out is role-split rather than duplicated because two agents writing to one tree collide; this repo has a receipt for that exact collision. Both models are on the task, only one holds the pen. If one harness is unusable the split collapses to solo and says so — a half fan-out never reads as a whole one.
Details: registry/modules/cli/tui/README.md.
The path that refuses before it builds:
task → intake → clarifying questions (REFUSES, exit 7) → SOW → human acceptance
→ role fan-out → per-role SDLC → review → verdict
It stops and asks rather than guessing, and it will not fan out until a human has explicitly accepted the Statement of Work. Six roles each own a gate that can actually fail:
| role | gate | fails when | reviewed by |
|---|---|---|---|
intake-pm |
ambiguity | an open question is unanswered | architect |
architect |
contract | acceptance checks are absent or drifted | verifier |
builder |
implementation | lint, typecheck, or the locked suite is red | verifier |
designer |
design-a11y | a view fails WCAG AA, or paints nothing at the real viewport | human |
verifier |
independent-verification | evidence cannot be reproduced | human |
meter-cfo |
budget | projected cost exceeds remaining budget | human |
A role whose gate cannot fail is rejected by roles.sh rather than documented.
fleet help lists them all. The ones you will actually reach for:
fleet status # live suite and requirement evidence
fleet test small # hermetic lane: no network, no API-key environment
fleet deps # is every dependency present AND usable
fleet ledger verify # is the receipt chain intact
fleet corpus # score this repo against its own catalogued failures
fleet arch-check # enforce the one-way dependency graph
fleet scan # the configured security scanners
fleet console # the loopback evidence plane, at 127.0.0.1:7317The refusals are the product. A closed exit table, the same for every verb:
| exit | meaning |
|---|---|
| 0 | ok |
| 1 | the work failed |
| 2 | usage |
| 3 | a required tool is missing |
| 4 | upstream output was unparseable — never reported as success |
| 5 | the budget refused it |
| 6 | an invariant was violated |
| 7 | the request is ambiguous — answer the questions first |
| 8 | the receipt chain is broken |
Standing refusals:
- Never pushes, merges, or opens a PR. That gate is yours, always.
- Never authors a commit. fleet brings no credentials and no git identity.
- Never reports a proxy as the property. An HTTP 200 is not a rendered page;
exit 0after a pipe is not a pass; a backend that exits 0 with no parseable output is exit 4, not success. - Never reports a harness as ready because its binary exists. Every harness gets a real round trip before the UI calls it ready.
- Never writes
ledger/RECEIPTS.jsonlfrom a test or a chat turn. A test suite with no path override once wrote 776 rows into the production chain and broke its hashes permanently. - Publishes the denominator. "0 violations" is meaningless without how many were checkable —
fleet corpusscores 85% of the mechanisable half and says out loud that the other 22 rows are judgement failures no linter reaches.
bash fleet/install.sh # everything, idempotent
bash fleet/install.sh --check # report only, change nothing
bash fleet/install.sh --update # also upgrade the adopted stack in placeSeven phases: interpreter repair → adopted stack (delegated to fleet setup) → fleet on PATH and
in ~/.zshrc → agent roles into ~/.claude/agents → L8 hooks → console build → permissions →
verification with real exit codes.
One machine-level trap worth knowing. If node on your PATH is old (nvm's v10 here), it cannot
parse ESM and silently kills codex, ccusage, and the terminal UI with a misleading
SyntaxError: Unexpected token {. fleet detects this and repairs its own PATH at the front
door, so every verb is immune; your shell is left alone. FLEET_NO_NODE_REPAIR=1 opts out.
fleet needs two distinct models — invariant I1 is that the generator is never the verifier. With only one installed, verification is not independent and fleet says so rather than pretending.
Two models, not necessarily two vendors. _i1_looks_like_model matches sonnet and opus
independently, so generator=sonnet with verifier=opus is genuine independent verification on one
vendor — which is what the lockcheck path already records (gen=sonnet ver=opus, exit 0). If you
have only claude installed, point the builder at it:
FLEET_BUILDER_HARNESS=claude FLEET_BUILDER_MODEL=sonnet fleet run --accept-sowThe default is unchanged (codex / codex-default), and FLEET_INTAKE_HARNESS /
FLEET_INTAKE_MODEL do the same for the intake author.
Nothing below is a claim; each is a command with an exit code.
fleet deps # 0 == every required dependency present and usable
fleet ledger verify # 0 == the hash chain is intact
fleet test small # the hermetic lane
fleet arch-check # 0 == the dependency graph is one-way
FLEET_LEDGER="$(mktemp "${TMPDIR:-/tmp}/fleet-corpus.XXXXXX")" fleet corpusEvery receipt-writing command takes a temporary ledger in the same command. The console:
fleet console # http://127.0.0.1:7317
fleet console --build # rebuild web/dist firstIt binds loopback only and refuses to start elsewhere (exit 2) — it serves local agent prompts
and MCP config, so off-box reachability would be an exfiltration surface. It also refuses to serve
an unbuilt web/dist (exit 4) rather than returning 404 on every route while looking healthy.
One-way dependencies, enforced by fleet arch-check (exit 6 on a violation):
registry/lib/ primitives; depend on nothing
registry/features/ atomic adapters; may import registry/lib only
registry/services/ workflows; compose features and lib
registry/modules/ operator surface; compose services and lib
fleet the single front door: `fleet` (UI) or `fleet <verb>`
PRINCIPLES.md owner corrections; stays at root intentionally
install.sh one-command machine setup
registry/ the four tiers above
console/ loopback evidence plane: server + web
tests/{small,medium,large}/ executable proof by size; fixtures colocated
docs/{adr,design,guides,reports}/ no loose documentation files
state/memory/ tracked learning corpus
ledger/ tracked, append-only, tamper-evident receipts
var/ ignored runtime output: runs, logs, caches, evidence
vendor/ ignored adopted upstreams, pinned in state/deps.lock
- A feature:
registry/features/<name>/<name>.sh; tests intests/{small,medium,large}/. - A service:
registry/services/<name>/; modules are the only tier composing multiple services. - A run:
var/runs/<id>/—brief.md,report.md,meta.txt,out.logtogether. - A decision, spec, how-to, or report: start at
docs/guides/README.md. - The receipt authority:
ledger/.
PRINCIPLES.md — 19 corrections, ordered by how many times each had to be
repeated, because repetition count is the honest measure of how badly a lesson failed to transfer.
The three that cost the most:
- A proxy is not the property. An API 200 is not a rendered page; a DOM count is not a paint.
- Adopting a tool is not the tool working. Two orchestration tools were adopted and defended for a day without either having ever run.
- A check cheaper to fake than to satisfy will be faked. 447 of 521 receipts passed the core invariant with strings that were not models.
Where a principle can be made into a check that FAILS, the check is the artifact and the prose is
only its index: fleet corpus scores the mechanisable half and exits 6 on a miss.