A2D — agent to done
No more skipped. No more slopped. No more forgotten rules. Exactly what you ask.
You asked for seven things. The agent did four, added two you never asked for, broke a
rule you corrected last week, and announced "done". A2D makes that impossible to say.
It is not another way to run agents. It is an enforcement layer you put on top of the
harness you already use — a checklist the agent cannot close on its own word, rules
that survive its memory, and a completion verdict that is produced by running a proof,
not by the model deciding it feels finished.
Why the agent's word is not evidence
An agent looking for the shortest path to "done" can edit the checker, rewrite the rule
file, patch the hook config, git commit --no-verify, reinterpret a prose rule as
"not applicable here", or simply mark its own item complete.
So the design rule is one sentence:
Completion must be a fact outside the agent, not its opinion of itself.
Concretely, in this package:
- The checklist lives in a file the server writes, not the agent.
a2d_complete does not accept a claim. It takes a verifier — a typed proof — and
re-runs it server-side. A fabricated proof is rejected and the item stays open.
- A Stop hook refuses "I'm done" while anything is still open.
- A per-item iteration limit force-skips an impossible item instead of looping forever,
so the fuse never turns into a hang.
Remove any one of the four and the enforcement leaks.
Local enforcement protects you from a forgetful agent. It does not protect you from
an agent that edits the rules — everything here is a file in its working directory. That
is a real limit, and it is stated here rather than hidden.
Install
npm install -g a2done
cd your-repo
a2d init
a2d init writes project-local config only. It never touches your global
~/.claude/settings.json.
The first 60 seconds
$ a2d init
a2d init — repo: /Users/you/your-repo
✓ MCP: Registered MCP server "a2d" (claude mcp add).
✓ hooks: /Users/you/your-repo/.claude/settings.json
added: Stop, PostToolUse, UserPromptSubmit
✓ .a2d: /Users/you/your-repo/.a2d
✓ guardian: Installed git pre-commit guardian.
RESTART REQUIRED — if a Claude Code session is already open in this repo, exit and
start it again. Hooks and MCP servers are read at startup; a live session will keep
running unwired and a2d will look broken.
Then: the agent has a2d_plan / a2d_complete / a2d_status and cannot stop while the
checklist has open items. Run `a2d doctor` to verify wiring, `a2d uninstall` to remove it.
$ a2d doctor
a2d doctor:
✓ node — v22.14.0
✓ MCP "a2d" registered — present in `claude mcp list`
✓ MCP server built — /usr/local/lib/node_modules/a2done/dist/src/mcp/server.js
✓ guardian built — /usr/local/lib/node_modules/a2done/dist/src/guardian/pre-commit.js
✓ Stop hook — wired
✓ PostToolUse hook — wired
✓ UserPromptSubmit hook — wired
✓ .a2d state dir — /Users/you/your-repo/.a2d
✗ plan.json — none yet (created by a2d_plan)
✓ git pre-commit guardian — installed
1 item(s) need attention (see ✗ above).
That one ✗ is correct: there is no plan until the agent makes one. a2d doctor reports
what is true, not what is comforting.
$ a2d status
No plan. Call a2d_plan to create a checklist.
Canon: no rules yet.
Now give your agent a task with more than one part. It calls a2d_plan to register the
items, and cannot stop until each one is closed with a proof that passes.
Changed your mind? a2d uninstall is the exact inverse of a2d init — it removes only
the entries it recognises as its own, leaves a foreign pre-commit hook untouched, and
keeps your plan and rules unless you pass --purge.
Which harness
A2D deliberately has no exclusive relationship with any harness.
MCP server (a2d_plan, a2d_complete, a2d_complete_batch, a2d_status, a2d_rule_record, a2d_rule_query) | any MCP client — Claude Code, Cursor, Codex, and anything else that speaks MCP over stdio |
| git pre-commit guardian | any harness, any editor, any workflow that ends in a commit — no MCP needed |
| Stop hook and context injection | the Claude Code hook protocol, which is what a2d init wires automatically today |
QFactory, GSD, BMAD and the rest are harnesses like any other here. If your harness runs
git and speaks MCP, the enforcement applies. Wiring adapters for further harnesses is
free and always will be — that is distribution, not product.
Proof types
a2d_complete takes one of these, and the server runs it:
file_exists | the path exists (and, if given, contains a substring) |
command_exit | a command exits with the expected code |
grep_count | a regex matches a file/glob an exact number of times |
test_pass | a command exits 0 |
human | never machine-passes → the item becomes needs_human, not done |
Commands run anchored to the repo root, with a hard timeout. Details in SPEC.md.
human matters: an item that genuinely needs your eyes is not quietly auto-approved and
not silently dropped. It is parked in a state that is neither.
Rules that outlive the conversation
When you correct the agent, record the correction once. It becomes canon and applies from
then on, in every session:
a2d_rule_record { text: "No emoji in headings", scope: "*.html", class: "hard",
verifier: { type: "grep_count", pattern: "🚀|✨", path: "*.html", expect: 0 } }
Rules come in two classes, and the difference is whether a machine can decide them:
Hard — carries a verifier, so it is decidable.
- Injected into context at the start of each turn.
- Checked after every
Edit/Write on a file in scope; a violation is reported back to
the agent immediately.
- Checked again by the git guardian on staged files: a violation exits 1 and the commit
does not happen. Bypass is
git commit --no-verify — this is your machine, not a jail.
Soft — a description with no checker, for taste that no regex can settle.
- Injected into context the same way, so it is present rather than remembered.
- Not enforced, and never pretends to be. It carries a
hits counter instead, so a soft
rule that keeps getting violated is visible as a candidate for a real checker.
Rules live in .a2d/canon/*.yaml, one per file, human-readable, meant to be committed and
reviewed like code.
What's on disk
.a2d/plan.json the checklist — human-readable, commit it
.a2d/canon/*.yaml your rules — human-readable, commit them
.a2d/state-runtime.json per-item iteration counters — gitignored
Plain files, plain git. Nothing about your work leaves your machine: there is no network
code anywhere in src/ — no telemetry, no account, no phone-home. The only processes
this package spawns are git, the claude CLI during init/uninstall/doctor, and
the commands you put in your own verifiers.
Reusable checklists
A loop manifest is a checklist with its verifiers already attached:
a2d loop loops/sdd-page.yaml
What is free, and stays free
Everything in this package, under Apache-2.0, with no account and no network:
- the Stop hook and the anti-stop logic
- the execution registry and evidence-gated completion
- all five verifiers, run server-side
- the local canon — no limit on the number of rules
- the git guardian
a2d doctor and a2d uninstall
- adapters into other harnesses
- an open, git-able file format — your plan and your rules are yours, in plain text
This is not a trial and not a crippled tier. The line elsewhere is not "more rules"; it
is about rules the agent cannot reach to weaken. This package is the half that is useful
on its own.
Development
npm install
npm run typecheck
npm test
bash test/integration.sh
Status
v0.2.0. The package name is not final — see NAME-SWAP.md in the repository.
License
Apache-2.0. See LICENSE.