Keel · a ledger of record · est. 2026rules · ledgers · roles · gates
The AI-Agent Playbook
Keel
The part of a ship that keeps it upright and on course. AI coding agents are fast, forgetful, and confidently wrong — Keel is the discipline that keeps a codebase from capsizing after thousands of agent-made changes. A small set of files and rules you drop into any repo, new or old.
docs/falsified.mdthe file no other framework has
Idea
Verdict
Why (mechanism + numbers)
Date
Cache embeddings in Redis
killed
Hit rate 4% — inputs near-unique per request; +40ms lookup for no benefit
A tweak of a dead idea is the same idea → see entry above
2026-07-14
The killed-ideas ledger: every experiment you ruled out, with the mechanism and the numbers — so no agent ever re-runs it.
01
The problem
Why this exists
An agent will make a hundred changes to your repo in an afternoon. Most are fine. Three habits compound into rot.
They forget. No memory of last week's failed experiment — so they propose it again. And again. Each re-run costs you the review to notice it's a re-run.
They over-reach. Asked to fix one thing, they "helpfully" refactor three others. Every unrequested change is review you didn't budget for and risk you didn't sign up for.
They're confidently wrong. "The tests pass" — without running them. "This handles the edge case" — without reading the code that supposedly handles it.
None of these is fatal once. All are corrosive across thousands of edits. This kit installs a counter-discipline for each: ledgers against forgetting, scoped roles and gates against over-reach, an evidence rule and a blind adversarial reviewer against confident wrongness.
Where it sits next to spec-kit and Kiro
Spec-driven tools like GitHub spec-kit and AWS Kiro are generative: the spec is the source of truth and code is generated from it. This playbook is epistemic: the code is the source of truth, and it governs how agents are allowed to make claims about it.
Question it answers
Source of truth
spec-kit / Kiro
"How do I produce code from intent?"
The spec
This playbook
"How do I keep a codebase trustworthy after thousands of edits?"
The code
Not a competitor — the reliability layer underneath whatever generation workflow you use. Use spec-kit to write the feature; use the ledgers, roles, and gates to keep it — and the next ten thousand edits — honest.
02
The philosophy
The fifteen principles
Everything else on this page is an implementation of one of these lines.
Instructions live in tiers: global rules, a project map, subsystem extras.
Confused → stop and ask. Problem report → diagnose, don't edit.
Code answers how; docs answer why.
Keep a ledger of killed ideas. A tweak of a dead idea is the same idea.
Decisions get one home, a date, and a "revisit if."
Report verdict first, metrics vs a named baseline, caveats, recommendation last.
Measure what the system actually acts on, not the population.
Implementer, reviewer, and auditor are different agents.
A claim about code that doesn't trace to a fresh read is labeled "unverified."
Memory belongs to the tool; ledgers belong to you.
One canonical value per concept; one choke point per external dependency.
No silent failures, and raw output for any pass/fail claim.
Deterministic core; the LLM narrates at the boundary, never computes alone.
Evals are the durable asset; prompts and models are consumables.
Start small — instruction file, working rules, the two ledgers — and grow when it hurts.
If fifteen is too many to hold, they collapse into five moves: ledgers, not memory · separate the roles · gates on behavior · deterministic core · grow when it hurts.
03
Day one
The minimal kernel
The smallest thing that counts as "set up" — four files. Resist adding more until absence causes real friction.
your-repo/
├── AGENTS.md# the rules + the project map (canonical, tool-neutral)
├── CLAUDE.md# a stub that imports AGENTS.md — Claude Code reads this
└── docs/
├── decisions.md# choices made — dated, with "revisit if"
└── falsified.md# ideas killed — mechanism and numbers
Everything else — roles, hooks, evals, the docs/ai vs docs/plans split — is growth, not kernel. Don't add it on day one.
Two tracks
Code-first projects add three things immediately: a lockfile-pinned environment, linting, and one passing test — so the evidence rule has something to point at from the start. Docs-first projects (research, design phases) defer all three until real code arrives.
Greenfield or brownfield — same kernel
New repo: ledgers start empty and grow naturally. Existing repo: ledgers also start empty — and you fill forward from your next decision. Never backfill history; that's an archaeology project that never ends. Dropping the kernel into a five-year-old repo changes no code.
04
The core artifact
The two ledgers
Memory belongs to the tool; ledgers belong to you. An agent's context window forgets — a committed file does not.
falsified.md — the killed-ideas ledger
The piece no other framework has. spec-kit, Kiro, and ADR practice all record what you decided. None records what you killed — and that's exactly the memory an agent lacks.
Every entry needs the mechanism of failure and the numbers. "It was slow" invites a re-run; "p99 was 2.3s vs a 400ms budget because each call re-tokenizes the full prompt" tells the next person exactly what would have to change to reopen it. Keep killed entries forever — the ledger's value is that it never forgets.
The rule that makes it work
A tweak of a dead idea is the same idea. Resurrection requires new evidence that addresses the recorded mechanism — not a fresh coat of paint.
decisions.md — the choices ledger
Every deliberate choice gets one home, a date, and a "revisit if" — so ten thousand edits from now, anyone can see what was chosen and when to reconsider.
## 2026-07-12 — FastAPI over Flask
Status: accepted # proposed | accepted | superseded | deprecatedBecause: We need async handling and OpenAPI generation out of the box.
Rejected Flask because: Sync-first; extra extensions, more moving parts.
Consequences: Pydantic models everywhere; ties us to Python 3.10+.
Revisit if: We drop the async requirement.
The Status, Consequences, and append-only discipline are borrowed from ADR/MADR — fifteen years of prior art for exactly this. Two rules worth stealing: write imperatively ("We use Postgres", never "we should probably…"), and append, don't edit — a changed mind is a new entry that supersedes the old one, not a rewrite.
The docs split
As you grow: docs/ai/ holds durable why reasoning, committed forever. docs/plans/ holds ephemeral implementation notes, deleted once the work graduates — a stale plan is worse than no plan. Code answers how; docs answer why.
05
Separation of powers
The three roles
A single model that checks its own work is an echo chamber. Splitting the work across separate agents breaks it — a pattern now echoed in Anthropic's own best-practices and the documented adversarial code review pattern.
Auditor — vets the idea
Step 0, always: the dead-list check against falsified.md. Then the decisions check. Then, if genuinely new: what's the cheapest test that would kill this if it's wrong? Verdict: already-killed / blocked-by-decision / worth-testing.
│ approved plan ▼
Coder — implements one scoped step
Touches only the named files. No "while I'm here" fixes. Never commits. Stops on ambiguity. Every "it works" claim ships with the command and its raw output.
│ diff only — no reasoning ▼
Reviewer — tries to refute it
Runs in a fresh context. Sees only the diff and the acceptance criteria — not the coder's reasoning. Adversarial by charter, scoped to correctness and requirements.
shipfix-firstcan't-verify
│ ▼
The human authors the commit
Always. No agent commits or pushes — that's the edit gate, and it's enforceable (chapter 06).
The nuance to get right
A reviewer told to "find problems" will invent them and drive over-engineering — a documented failure mode. Scope the reviewer to correctness and requirements only, and tell it to say ship plainly when the work is sound. Adversarial, not theatrical.
You don't need all three for a one-line change — that's principle 15. Reach for the reviewer when a change is non-trivial; reach for the auditor once falsified.md has enough entries that re-runs are a real risk.
06
Behavioral rules
The gates
Three rules that live at the top of AGENTS.md and counter the two worst habits: guessing when confused, and editing when asked to diagnose.
Ambiguity gate
Confused or ambiguous? Stop and ask. If running unattended, state the ambiguity and which assumption you chose — silent resolution of confusion is never acceptable.
Edit gate
Questions and problem reports get diagnosis only — report findings, change nothing — until the human says fix or implement. Never commit or push. The human authors every commit.
Evidence rule
A claim about the code that doesn't trace to a fresh read is labelled unverified. No silent failures. For any pass/fail claim: the raw output — the command run and what it returned.
From advice to enforcement
The honest catch: AGENTS.md is context, not enforcement. An agent usually follows it; compliance isn't guaranteed. To make a gate a hard constraint, use a PreToolUse hook — a check that runs before a tool call and can block it. A ten-line script that rejects any git commit or git push from an agent turns "the human authors every commit" from a request into a rule the tooling enforces.
Adopt hooks last. Start with the gates as written rules; add enforcement once the team trusts the discipline. Enforcement added before trust just feels like the tool fighting you.
07
When your product uses an LLM
Applied-AI addendum
Four extra rules for projects where an LLM runs inside the product — not just beside it.
Deterministic core; LLM at the boundary
Logic with a right answer — pricing, permissions, state transitions — lives in deterministic, testable code. The LLM sits at the edge: it turns messy input into structured calls, and structured results into prose. It never does the arithmetic a function should, because you can't unit-test a vibe. When something breaks, you point at a function and a test — not at a prompt and a shrug.
One choke point per model
Route every model call through one client. When you switch models — and you will — you change one file, not fifty.
Evals are the durable asset
Prompts get rewritten; models get deprecated. What lasts is the eval harness. Grow it from real failures: don't write a comprehensive suite up front — you'll guess wrong about what breaks. Every time production surprises you, that case joins evals/. The harness grown from actual failures is the one that catches the next one.
Measure what the system acts on
If your agent escalates 5% of tickets, your accuracy number is about that 5% — not the population where "do nothing" is trivially 95% right. Track experiments at the application boundary, where a decision changes behavior — not buried in the engine where the metric flatters you.
08
Getting started
Adoption & interop
Greenfield — new repo
Copy in the four kernel files.
Fill the project map in AGENTS.md: stack, domain terms, how to run tests, the landmines.
Code-first? Add a lockfile, linting, one passing test now.
Start both ledgers empty.
Grow when it hurts: first re-run of a dead idea → start using falsified.md; first untrusted change → bring in the reviewer; first unauthorized commit → add the hook.
Brownfield — existing repo
Drop in AGENTS.md + the CLAUDE.md stub. Change no code.
Fill the project map honestly — especially the landmines.
Start both ledgers empty; fill forward. Never backfill.
Introduce the reviewer on your next PR. One role, one PR.
Add the auditor once falsified.md has entries; adopt hooks last.
No migration, no rewrite, no big bang. If it doesn't help, you've lost four files.
Running alongside spec-kit or Kiro
They don't collide: let spec-kit own .specify/ and its per-feature specs; let this playbook own AGENTS.md and the two ledgers. A spec-kit constitution states principles up front; decisions.md records choices as you go; falsified.md records what you ruled out — and nothing else offers that last one.
AGENTS.md and CLAUDE.md
AGENTS.md is the canonical, tool-neutral standard (adopted by Codex, Cursor, Amp, and more) — put your real instructions there. CLAUDE.md is a stub importing it via @AGENTS.md, since Claude Code reads its own file. And keep it under ~200 lines — past that, agents start ignoring the tail. Add a rule only when you'd otherwise re-explain it.