Plan-driven operating layer for coding agents
A keel keeps the hull on course when the wind pushes sideways. keel does that for Codex, Claude Code, Gemini CLI, Cursor, Copilot, OpenCode, Aider and Pi.
How a session goes
You describe a problem, not a command. The agent classifies it; if it's complex it writes PLAN.md — objective, dated requirements, a task table with a verification per row — and stops. Nothing is written until you reply go. From there every task closes only on a verification that actually ran.
What keel puts under each gear
Every framework ships the three gears — an agent that gets the end state, a loop that iterates against a check, a graph that runs work in parallel. keel does not compete on them. It adds the parts none of them ship: the gate, the append-only log, the arguer, the fake edge test, output contracts, the model-free reduction, the hash-sealed verdict. Each one is a brake, not a throttle.
The plan stays short and says where we are. The log is append-only, one entry per checkpoint — DID / DECIDED / BLOCKED / NEXT, under 100 words — and says how we got here. On resume the agent reads both and restarts from the last NEXT. To hand the work to a person, point them at the log. The hook refuses commits that delete a line from it.
Ask an agent "is this plan good?" and it says yes. premortem.sh opens a fresh session that sees only PLAN.md and has it narrate how the plan failed twelve months out — aiming at the ASSUMED lines, the edges, the verifications that would pass even with a wrong result. The top three risks enter the plan as PRE-MORTEM lines with a countermeasure, and you approve them with the table.
OUT, shape, a runnable check. A node with a declared output shape is readable by the next node with nobody in between; an output outside its shape is rejected, not adapted to. Sequential remains the default: parallelism is chosen, not suffered.Positioning
Orchestrators make agents go: they execute the graph, retry, fan out, scale. keel makes them accountable: the graph lives in a plan a person approves, and the rules are enforced by git, not by the model's good will. Use both — keel sits above whatever runs the work.
| Where the graph lives | Who approves before code is written | What is enforced — and by what | Vendor | |
|---|---|---|---|---|
| Orchestration frameworks LangGraph · CrewAI · AutoGen | Python code, written by a developer | Optional human-in-the-loop node, if you build one | Nothing beyond your own code | Any model, your stack |
| Agent-native subagents Claude Code · Codex · Copilot | Implicit in the conversation | Per-tool permission prompts; PR review afterwards | Vendor hooks or sandbox, one agent only | One vendor |
A bare AGENTS.md | Nowhere | Whatever the text says | Nothing — instructions the model may skip | Any |
| keel | PLAN.md, a table a person reads, validated by plan_graph.py | Explicit DRAFT → APPROVED state before any write | Git pre-commit hook, 4 checks · hash-sealed checker verdict · write-time hook where the agent allows it | Any agent, any model |
What keel does not do: run your graph at scale, manage distributed state, retries or queues, replace CI, or remove the human. It is the keel, not the engine.
Compatibility
Everything binding is markdown, standard python3 and git. What varies per agent is isolated in two places: how it reads AGENTS.md (adapters/) and how a fresh session is opened (scripts/lib_agent.sh, one backend per CLI plus custom). What an agent can't provide is documented, not faked.
reads AGENTS.md natively · the others get a one-line bridge file from adapters/install_adapter.sh
The Codex app, Cursor, Windsurf, VS Code with Claude Code or Copilot, Claude Desktop (Cowork) with the project folder connected, a chat with the folder attached. Where the app reads AGENTS.md or CLAUDE.md the rules load on their own; where it doesn't, one first message does it: "Read AGENTS.md and docs/AGENT_SOP.md, then: <your problem>". The plan, the log and the approval are the same files; the pre-commit hook fires whenever anyone — app or human — commits.
Safety net
Everything in AGENTS.md is an instruction, and an instruction can be ignored on a bad day. The pre-commit hook is git: identical for every agent, and it fires exactly where unapproved work would become permanent.
Any staged file other than PLAN.md / PROGRESS.md with Plan status: DRAFT → commit refused.
Needs checker_task<n>.txt with VERDICT: KEEP and a SHA-256 that still matches the artifact.
plan_graph.py must say GRAPH: OK: no cycles, no fake independence, no task without verification or contract.
The log is append-only. A diff that deletes an entry is refused; you add an entry saying what changed and why.
Claude Code additionally gets the gate at write time through a PreToolUse hook. Deliberate bypass everywhere: git commit --no-verify.