keel

8 min read Original article ↗

keel

Rust · macOS & Linux · v0.10.1

AI coding agents that prove their work.

You say what “done” means. An agent — Claude Code, Codex, Copilot, Kiro — does the work. keel checks it, stops the line when a check fails or you haven't signed off, and keeps a tamper-evident record anyone can verify, even without your repo.

$cargo install keel-harness

Installs a binary called keel. Works with the agent you already use.

DWL KEEL EVERY FRAME BOLTS TO IT STEM STERN
Plate I — Side elevationThe part that keeps the hull true

How it works

You decide. The agent works. keel keeps score.

Coding agents are brilliant at writing code and bad at knowing when to stop. keel is the part that knows: what “done” means, whether the work got there, and who said so.

1 · Define doneA short spec whose every criterion has a test that can say no. You approve it, and the plan.

2 · Let it workAny agent you like. keel hands it the task and nothing it doesn't need.

3 · Prove itBuild, tests, review, your sign-off — then one file of evidence anyone can check.

Spec and plan you approve, the agent works, gates check it, you sign off, keel produces an evidence bundle. A failed gate goes back to the agent.
Plate II — The loopThree human checkpoints · nothing ships on a red gate

Use cases

What you can do with it

Start with one. Each works on its own.

For anyone using an agent

Keep an agent on a short leash

Nothing counts as done until the build and tests are green, a review pass has run, and you've signed off. A gate that fails sends the work back — it never quietly ships.

keel spec new rate-limit     # what done means
keel approve rate-limit --stage spec
keel plan rate-limit         # which files, how big
keel run rate-limit          # agent works, gates judge

For audit, risk and compliance

Show an auditor exactly what happened

Every approval and verdict is locked into a hash chain. One command packs the chain, the spec, the verdicts and the exact diff into a single file that anyone can verify offline, with no access to your code.

keel export
keel bundle verify keel-<run>.tar.gz
  pass  members · chain · approvals
  pass  gate-verdicts · trajectory
Approvals and gate verdicts form a hash chain; the bundle carries the chain, spec, verdicts and diff, and keel bundle verify checks it offline.
Plate III — The evidence chainEdit one entry and every link after it breaks

For teams on GitHub

Block pull requests nobody gated

Add one step to a workflow. A PR passes only if it carries the evidence of a passing run of exactly its content — or a maintainer labels it keel:exempt, and the record says so.

# .github/workflows/keel-cover.yml
on: pull_request
jobs:
  keel-cover:
    runs-on: ubuntu-latest
    steps:
      - uses: daneb/keel@v0.10.1
A PR with the bundle of a passing run of its exact content is covered; one with no bundle is uncovered; one labelled keel:exempt passes as exempted.
Plate IV — The PR checkCovered · uncovered · exempted

For platform teams

Let CI do the gating

GitHub Actions gates each PR inside a locked-down container — gVisor, when the runner has it — keeps the record where that container can't reach it, and commits the evidence back to the PR.

# in a pull_request workflow
- uses: daneb/keel/runtime@v0.10.1
  with:
    spec: rate-limit
    image: rust:1-bookworm
The GitHub runner holds the evidence chain and attests the container from outside; keel gates the PR inside a gVisor container; the bundle is committed back to the PR.
Plate V — The CI runtimeThe runner holds the pen · keel never can

For running agents locally

Put the agent in a sealed box

Pair keel with moor: a sandbox per project, no access to your disk, an allowlist for the internet — and keel's record written from outside, so the agent can't rewrite it.

moor new my-app
moor ask my-app "add rate limiting"
moor bundle -p my-app   # ✓ bundle pass

Why trust it

Every claim here is checked, not asserted

keel is built with keel. Every change to it carried a spec, passed its gates, and ships its own evidence bundle.

VALUE

Less babysitting, more shipping

  • Works with the agent you have — Claude Code, Codex, Copilot, Kiro — through one small adapter each.
  • 14.6× less context fed to the agent, at 100% recall, by handing it outlines and symbols instead of whole files.
  • One line in a workflow turns it into a PR check.
  • Remembers across sessions: mistakes that recur become checks, not more instructions to ignore.

QUALITY

Nothing is done until it's proven

  • Five gates, from “is this spec testable?” to “did a human sign off?” — each one a verdict with its evidence.
  • A test that can say no on every acceptance criterion; a spec that can't fail can't pass either.
  • Review built in: weakened tests and added mocks are caught, and serious security findings block.
  • 541 tests, 0 warnings at clippy -D warnings.

SECURITY

The agent can't mark its own homework

  • Tamper-evident record: every approval and verdict is hash-linked; edit, delete or reorder one and keel names where.
  • The pen stays outside the sandbox: under moor or CI, the record is written by the host, never by the agent.
  • gVisor, proven: on GitHub runners the gate runs in a user-space kernel, and the record says so — or says it couldn't.
  • Approvals bind to content: change the spec after sign-off and the approval stops counting.

RELIABILITY

It never guesses green

  • Three verdicts, not two: a check that couldn't run is blocked (exit 3) — never a silent pass.
  • Verifies offline: a bundle checks out with no repo, no network, no account — on a plane, or in an auditor's sandbox.
  • Tested on real pull requests, not just in unit tests: covered, uncovered and exempted, on live GitHub runners.
  • Frozen formats: the record and attestation formats change only additively, so evidence written today still verifies tomorrow.

Gates

Where the load is carried

Each gate answers one question and refuses to answer it vaguely.

G0

Is the spec answerable?

Every requirement falsifiable, every criterion carrying an oracle. A spec that cannot fail cannot pass either.

G1

Is the plan honest about its reach?

Blast radius computed from the import graph and compared with what the plan declared — not with what it hoped.

G2

Did the work stay inside its scope, and does it build?

Build, lint, tests, line budget, blast radius, store drift, baseline ratchet. G2.5 adds test-invalidation review, and grades the diff for security defects — a model, a scanner, or both — where high/critical block the gate.

G3

Could a reviewer actually check this?

Evidence complete, change reviewable in size, earlier gates green, a human verdict where one was required.

G4

Did we learn anything that should become a rule?

Episodes classified, promotions proposed, decay reviewed. G4 forces the decision; it does not make it for you.

pass · exit 0

The checks ran and held.

fail · exit 1

A check ran and said no.

blocked · exit 3

A check could not run. It never silently passes, and it is never counted as an agentic failure.

Evidence

Numbers, and where they came from

All of these are measured by keel on real repositories. The provenance matters as much as the value.

14.6×

Less context

At 100% recall on keel's retrieval benchmark.

1.25 s

To index 5,705 files

Cold, across eight languages.

541

Tests · 0 warnings

Clippy clean at -D warnings.

11 → 54%

G2 pass rate

Inside keel vs. on a real project. The low number was the artefact.

℄ KEEL DECK

The check to scrutinise first

keel's own metrics flag G2/store-drift: it has never failed in 26 runs across two repositories. That is either a check that is correctly always-true here, or gate theatre. A harness that measures other people's work should be able to say which — so it says so, on its own front page.

Plate II — Midship sectionBody plan · centreline · keel

Get started

Ten minutes to your first gated change

Point keel at a repository and take one small change all the way through. The getting-started guide walks the same path with commentary.

# install
cargo install keel-harness      # binary is called `keel`

# set up, then describe one change
keel init
keel spec new short-invocation
keel approve short-invocation --stage spec

# plan it, run it, prove it
keel plan short-invocation
keel run  short-invocation
keel bundle verify "$(keel export)"

# where does it stand? what's next?
keel next
keel serve                    # read-only, in a browser

Before you trust it on real work

  • macOS and Linux. Windows branches compile and are unexercised. That is a decision, not an oversight.
  • Configure a reviewer. Without a model or scanner behind it, G2.5 reviews with heuristics.
  • Pull requests from forks can't receive the CI runtime's bundle commit yet.
  • The evidence is young — a handful of repositories, one operator. The roadmap keeps a full accounting of what is deferred and why.