Ask a coding agent whether it finished, and it will say yes in confident past tense. Sometimes that is true. Sometimes the tests it says passed were never run, the feature it says works is a stub that returns a fixed value, and the only thing that is finished is the sentence. We built Keel to make the second case mechanically hard.
The failure is at claim time
Most tooling for agents tries to make them work harder or smarter. That is effort-time tooling, and it does not address the failure we kept seeing. The agent had put in the effort. The problem was the report at the end, which described the work in a way the work did not support.
So Keel intervenes at the moment of the claim. It does not tell the agent how to write code. It defines what "done" is allowed to mean, what evidence that word costs, and who is permitted to say it.
Five states, and only one of them costs anything
Every task in a Keel project is in exactly one of these states:
- NOT_STARTED
- IN_PROGRESS
- BLOCKED, with the blocker named
- MOCKED, declared, with the mock registered
- VERIFIED, with receipts
The first four are cheap to claim. An agent that is stuck can say so. An agent that stubbed a payment provider for now can say that too, and it is not a violation. The design bet is that agents drift into false completion because honest states feel like failure. Make honesty free and the drift has less to push against.
Only VERIFIED costs something, and it costs a five-step receipt: a build, the test run, the feature actually being exercised, a map from each requirement to the code that implements it, and a sweep for stubs. Without all five, the state cannot be VERIFIED. The claim is not rejected after the fact. It is not available.
Mocking is legal. Hidden mocking is not.
A stub is not a sin. Sometimes the payment provider is not wired up yet and the right move is a fake that returns success so the rest of the flow can be built. Keel allows this on two conditions: the task card must permit it, and the mock must be registered where the stub sweep will find it. A declared mock is a normal, honest state. An undeclared one fails verification, which is the whole point.
Two ledgers that cannot quietly change
STATUS.md is the single home of completion claims. If a task is not marked there, it is not done, whatever the commit message says. DECISIONS.md holds standing rulings so that a decision made in week one does not silently revert in week four when a fresh context window has no memory of it.
Alongside them sit the golden vectors: test cases cut directly from the specification, running in CI from the first task. They may never be edited to make an implementation pass. The spec is the bar, and the bar does not move to meet the work.
The agent installs it itself
A framework that asks a human to fill in twenty templates before the first line of code gets skipped. So Keel has the agent do the installation. BOOTSTRAP.md tells it to read the repository's SPEC.md, plus an optional mockup directory, and from those to write the invariants, the golden vectors, and the first phase of task cards. Then it hands the human one batched approval round.
That one round matters. The invariants and vectors are the quality bar for the whole project, and the human owns the bar. Everything after that is the agent working toward a standard a person signed.
Skipping bootstrap is not merely discouraged. The verification script refuses to pass while any {{placeholder}} remains in the file set, so a repo that has not been bootstrapped cannot verify anything.
A builder's report is a claim, not evidence
For larger work, ORCHESTRATOR.md turns the top-level session into a planner. It groups independent task cards into waves and dispatches one builder sub-agent per card, with the builder's mandate pasted in verbatim so nothing is lost to summarisation.
Then it does the thing that makes the arrangement honest: it re-runs verification itself. A builder cannot claim VERIFIED and cannot write to either ledger. It builds, it reports, and the orchestrator checks. The loop stops for exactly three reasons: an open question is gating all remaining work, a phase has ended, or the project is complete.
Where it stands
Keel is public on GitHub under the MIT licence, as a template repository. It is Markdown plus two shell scripts, with no dependencies, and it is agent-agnostic even though the file names follow Claude Code's conventions. It was extracted from a live project rather than designed on paper.
The honest gap, which we would rather state than have discovered: it has not yet been dropped into a scratch repository and run end to end through its own bootstrap. That proof is the next step, and until it exists, "it works" would be exactly the kind of claim the framework is built to reject.