keel
README.md
# keel
**An observable autonomy harness for AI coding agents.** — *by [TokenDrift](#open-core--keel-is-the-free-sensor)*
keel is an [MCP](https://modelcontextprotocol.io) server that gives your coding agent (Claude Code, Cline, …) the tools to run a long task **end to end — without drifting, cheating, or losing its work** — while recording everything it does so you can steer on cost and quality.
You start the task. The agent disciplines itself. You come back to a milestone report.
> The name: a keel is the part of a boat you never see — the spine under the waterline that stops it from being blown sideways by the wind. That's the job.
---
## The problem
An agent left alone on a long task tends to do four things you can't see until it's too late:
- **It loses the thread.** Context gets compacted, earlier decisions are forgotten, work is redone or contradicted.
- **It cheats.** Faced with "make the tests pass," an agent will quietly edit the tests themselves — reward hacking. The suite goes green; nothing actually works.
- **It loses files.** An overwrite, a bad refactor, an hour of work gone with no checkpoint.
- **It's a black box on cost.** You have no idea what the run cost you, which model burned the budget, or whether the agent looped twenty times on one step.
keel puts a tool on each of these, and the agent calls them itself — because the rules are injected into its `CLAUDE.md` at init. Every call emits an event, so the whole run is legible afterward.
---
## keel in action
A real run on a throwaway `calc-kit` project — the agent was told to implement `add(a, b)` so the locked tests pass, following the keel protocol. This is the actual sequence, unedited:
```
1. load_context → project loaded, tests intact
2. record_decision → "add = a + b, minimal, no deps" logged
3. (writes calc.py)
4. save_progress → state persisted
5. verify → green: 2 passed, tampered: false
6. checkpoint → commit fac81a4 — milestone CERTIFIED
7. check_drift → no drift
8. log_usage → sonnet, 4000/1200 tok → $0.03
9. route_task → (sensitive) recommends EU-hosted model;
US + CN clouds excluded
10. stats → 1 verify / 100% pass, 1 certified milestone, 0 cheat alerts
11. report → milestone report written to .keel/reports/
```
Then, to show the anti-cheat is real — we modified a locked test file by hand (simulating an agent tampering to force a green) and ran `verify`:
```json
{
"tampered": true,
"tests_changed": ["~ tests/test_calc.py (modified)"],
"passed": true
}
```
`tampered: true` **and** `passed: true` at the same time. keel doesn't confuse "the tests pass" with "the tests are intact" — it reports both axes separately. An agent can make the suite green *by rigging it*, and keel still sees it. That distinction is the whole point.
---
## The anti-cheat: a proof regime, not a prison
The hard problem with any optional-tool harness: an agent can ignore `verify` and just run `pytest` in the terminal, short-circuiting the one mechanism that catches cheating. A polite instruction in `CLAUDE.md` shapes what the agent *tries* to do — it doesn't *stop* anything.
keel closes this with **three layers**, on the principle that no single layer is perfect but together **no path is simultaneously easy, silent, and untraced**:
1. **Persuasion** — the `CLAUDE.md` block tells the agent, in no uncertain terms, that `verify` is the only judge and direct test runs are forbidden. Handles the dominant case: an agent that drifts out of negligence, not malice.
2. **A mechanical guard** — `init_project` installs a `PreToolUse` hook (`keel-guard`) into the project's `.claude/settings.json`. It intercepts `pytest`, `python -m pytest`, `npm test`, `yarn test`, `go test` **before they execute** and refuses them, redirecting the agent to `verify`. This runs in the Claude Code harness, outside the model's control. On our setup it holds **even under `--dangerously-skip-permissions`** (bypass mode skips interactive confirmations, not hooks — verify on your own machine, see *Honest limits*).
3. **Tamper-proof attestation** — for anything that slips through, `verify` emits a hash of the exact working-tree state it judged, and `checkpoint` only marks a milestone `certified` if a passing, untampered `verify` ran against *that same tree*. A bypass produces an **uncertified** milestone — visible in `stats` and `report` — rather than a silent one.
Layer 2 makes the obvious bypass hard. Layer 3 makes *every* bypass visible. keel certifies what it witnessed; it doesn't claim to make evasion impossible — and that honesty is exactly what produces the **"% certified milestones"** signal worth tracking over time.
**The golden rule that makes it work: you write the tests, never the agent.** `verify` runs your locked suite and detects any change to it, file by file. If you change the tests yourself, re-run `lock_tests` (a human action).
---
## Install
keel is plain Python — one dependency (the MCP SDK, which pulls in FastMCP and pydantic), plus git. It is developed and hardened on **Windows**, and runs on macOS/Linux.
```bash
git clone https://github.com/tdalbanmoreynas/keel.git
cd keel
python -m venv .venv
pip install -r requirements.txt
python keel_server.py # must start without error (Ctrl-C to quit)
```
On Windows the venv activation is `.venv\Scripts\activate`; on macOS/Linux it's `source .venv/bin/activate`. Activation is optional if you point your client at the venv's Python directly (below).
### Connect to Claude Code
```bash
# from the keel folder, pointing at the venv's interpreter (absolute paths)
# macOS/Linux:
claude mcp add keel -- /absolute/path/to/keel/.venv/bin/python /absolute/path/to/keel/keel_server.py
```
Windows example:
```bash
claude mcp add keel -- "D:\path\to\keel\.venv\Scripts\python.exe" "D:\path\to\keel\keel_server.py"
```
Or paste the block from `mcp_config.example.json` into your client's config (Cline: `cline_mcp_settings.json`).
**Two things that will save you a debugging session:**
- **Add an allow rule** for keel's tools in your Claude Code settings (`mcp__keel__*`), or the agent's first keel call hangs waiting on an authorization prompt that doesn't always surface.
- **Launch your client from the project root.** The `keel-guard` hook loads from the current directory's `.claude/settings.json` with no parent fallback — it's active when Claude Code runs from where the project lives.
---
## Compatibility
keel has two parts, and they have different reach.
**The 12 MCP tools** are standard [MCP](https://modelcontextprotocol.io) — they work with **any MCP-capable coding agent**: Claude Code, Codex, Cursor, Cline, Windsurf, Zed, VS Code + Copilot, Continue, Goose, and the Cline forks (Roo Code, Kilo Code). Memory, checkpoints, the anti-tamper `verify`, attestation, decision logging, cost tracking, and `route_task` all run anywhere MCP runs.
**The `keel-guard` hook (layer 2)** is **Claude Code–specific.** It's a `PreToolUse` hook in `.claude/settings.json` — a Claude Code mechanism that no other client implements today. So:
| Client | MCP tools (layers 1 & 3) | Mechanical guard (layer 2) |
|---|---|---|
| **Claude Code** | ✅ Full | ✅ Yes — the `keel-guard` hook installs and fires |
| Codex, Cursor, Cline, Windsurf, Zed, Copilot, Continue, Goose | ✅ Full | ⚠️ Not installed — no hook system |
On a non–Claude Code client you still get the persuasion layer (the injected rules) and, crucially, the **attestation layer**: a checkpoint that skipped `verify` still comes out **uncertified** in `stats` and `report`. You lose the mechanical block on direct test runs, but you don't lose visibility — the bypass is still recorded. That's the proof-regime design paying off: the guarantee that *matters* (you can always tell whether a milestone was verified) doesn't depend on any one client's hook system.
Claude Code is where keel is fullest and where it's developed and hardened. Other clients are first-class for everything except layer 2.
---
## Workflow
1. **Once per project** — `init_project`: creates `.keel/`, writes the architecture and immutable constraints, **locks your test files**, initializes git, installs the `keel-guard` hook, and injects the autonomy rules into `CLAUDE.md`.
2. **Then the agent self-manages** by following those rules: `load_context` at the start of every session, `save_progress` + `checkpoint` after each step, `verify` to validate, `log_usage` after each model call, `record_decision` at each architectural choice, `report` at the end.
You come back at milestones, not at every line.
---
## The 12 tools
| Tool | Role | Guards against |
|---|---|---|
| `init_project` | Lays the harness (architecture, constraints, test lock, git, hook, CLAUDE.md) | — |
| `load_context` | Resumption briefing at session start | Context loss |
| `save_progress` | Writes done / doing / todo to disk | Context loss |
| `record_decision` | Append-only log of architectural choices | Architectural drift |
| `checkpoint` | Git commit of the step, with certification | File loss |
| `verify` | Runs the locked tests, detects tampering | Cheating (reward hacking) |
| `lock_tests` | Re-locks the tests (human action) | — |
| `check_drift` | Recalls constraints, flags unsaved work | Drift |
| `route_task` | Most cost-effective model for a subtask | Cost / data sovereignty |
| `log_usage` | Records real spend of a model call | Cost observability |
| `stats` | Aggregated metrics (cost, cheating, certification, velocity) | Steering |
| `report` | Markdown milestone report for the human | Steering |
---
## What keel records
Every tool emits an event to `.keel/events.jsonl` (local, private to your repo). From that trace, keel continuously derives: sessions, checkpoints, **certified vs. uncertified milestones**, verify pass rate, **cheating alerts**, **real cost per model**, and velocity. That trace is what makes an agentic run legible — and it's the raw material for the funded layer below.
---
## Open-core — keel is the free sensor
keel is one product in two pieces. This repo — the local sensor — is **free and MIT, forever.** It runs entirely on your machine: it watches your agent, catches tampering, tracks waste and cost, and writes everything to a local `events.jsonl` that never leaves your repo. A solo developer needs nothing else.
The funded piece is a **cloud dashboard for engineering teams** (*by TokenDrift*), planned, on top of the same sensor. Where the free tier answers *"how is my agent doing?"*, the team dashboard answers *"how is my whole team doing, over time?"* — by aggregating the sensors of every developer on the team: total agent spend and recoverable waste, the share of milestones that were honestly certified (not just green), real-time alerts when a budget or a cheat-rate spikes, and anonymized benchmarking against other teams (*"your agents tamper 3× more than the median"*).
The split is deliberate: the sensor is free because **a local binary is cloneable and can't be sold** — its job is to be useful and to spread. The paid value lives in the **team-level network and aggregated data**, which a single local install structurally can't produce. Same model as Langfuse, PostHog, and Sentry: free and complete for the individual; paid when you become a team that needs the collective view.
Privacy is built into the split: the sensor sends **metadata only — never your code or prompts.** Cheat detection runs locally; only the verdict (certified / suspect) would ever leave the machine.
---
## A note on `route_task` and prices
The model prices (`keel_core.py`, `MODELS` constant) are June 2026 estimates — replace them with your real rates. `route_task` accounts for agentic burn (cost = tokens × iterations × inefficiency) and excludes non-EU clouds when `sensitive=True`, which is why a sensitive subtask in the run above was routed to an EU-hosted model.
---
## Honest limits
keel is built to be honest about what it does and doesn't guarantee — that honesty is the product, not a disclaimer.
- **The guard catches canonical test invocations, not every conceivable form.** An aliased runner, a test buried inside a shell script (`bash run_tests.sh`), or an exotic invocation outside the matched patterns can slip past layer 2. The pattern list is extendable; completeness isn't claimable. This is exactly why layer 3 exists: whatever slips past is still recorded as an uncertified milestone.
- **Bypass mode is environment-dependent.** Whether the hook fires under `--dangerously-skip-permissions` is contested across sources and may vary by Claude Code version. On the setup keel was hardened against, it *does* still fire — but **test it on your own machine** rather than trusting it blind. Either way, layer 3 catches the bypass as `no_verify`.
- **`lock_tests` is a human action by convention.** Nothing mechanically stops an agent from calling it — but doing so to mask a tampered test shows up in the trace. Watch the cheat alerts; read the git diff at checkpoints.
None of these break keel. They're the precise boundary of a proof regime: it certifies what it witnessed, and makes the rest visible.
---
## License
MIT — see [LICENSE](LICENSE). © 2026 Tristan Dalban Moreynas.
This server cannot be deployed
Maintenance
ActivityStale
ResponsivenessNo issues