# The Definition of Done for AI Agents, v1.0

- Version: 1.0 (2026-11-07)
- Author: Connor Gallic
- Canonical: https://connorgallic.com/definition-of-done
- This file: https://connorgallic.com/agent-dod/spec-v1.md
- Receipt schema: https://connorgallic.com/agent-dod/receipt.schema.json
- Checker: https://connorgallic.com/agent-dod/agent_dod.py
- License: text CC BY 4.0, checker MIT
- Companion: AI agent governance rules, https://connorgallic.com/ai-agent-governance
- Cite as: Gallic, C. (2026). *The Definition of Done for AI Agents, v1.0.* https://connorgallic.com/definition-of-done

## The rule

An agent saying "done" is a claim. **Done is a verdict, issued by something other than the agent, after reading the result back from the system where it lives.**

The page is live at its URL. The email is in the provider's sent log. The charge is in the payment processor. The call is in the carrier's log. Not the agent's memory, not a green exit code, not a card on a dashboard.

Part 1 says what counts as done. Part 2 is AI agent governance: how to run agents in production so that "done" stays true when nobody is watching.

## Why this exists

Agents rarely fail by being dumb. They fail by saying "done" when it isn't.

- Anthropic's Claude Code best practices describe the same failure: "Claude said it was done and it wasn't quite, usually because it had no way to check its own work." Their checklist for unattended runs starts with "Does it know what done looks like?" (https://code.claude.com/docs/en/best-practices, read 2026-11-07)
- METR found frontier models modifying tests and scoring code to look successful ("Recent Frontier Models Are Reward Hacking", 2025-06-05, https://metr.org/blog/2025-06-05-recent-reward-hacking/).
- In my own fleet, from 2026-10-01 to 2026-11-06, agents settled 1,436 tasks and marked 585 "done". One of the 585 carried enforced read-back proof. That does not mean the rest were fake: a spot check of 13 randomly picked done tasks that had a checkable link found all 13 real (sample biased toward tasks with links). It means nobody could show which were real without checking by hand. (https://connorgallic.com/blog/agent-receipts-v1)

Scrum's "Definition of Done" is a team agreement about when work is releasable. This one is narrower and stricter: it is about whether a claim of completion by a machine can be believed.

## Part 1: what counts as done

### Proof levels

| Level | Name | What it means |
|---|---|---|
| P0 | None | A status and nothing else. |
| P1 | Asserted | The agent describes what it did. |
| P2 | Artifact | A cited thing that resolves: commit, pull request, file, test log. Shows work was produced, not that it landed. |
| P3 | Read-back | An independent process read the real after-state from the authoritative system after the run. |
| P4 | Reconciled | A P3 read-back tied to a business outcome: a customer reached, a payment, a client delivery, content a person can see. |

**Done requires P3.** P4 is what you report as results.

### Status ladder

Use the word that is true, and no higher one.

planned → built → deployed → scheduled → executed → verified (P3) → reconciled (P4)

Side states, each terminal for that attempt: **blocked** (names the outside condition), **held** (stopped at an approval gate, nothing left the building), **failed** (crashed, timed out, errored), **superseded** (replaced before it ran).

For outbound messages the ladder is longer than people think: queued < accepted < sent < delivered for texts and email; queued < accepted < ringing < answered < completed for calls. Approved is not scheduled, and scheduled is not sent.

### The ten done rules

- **DOD-1 Name the outcome first.** Before work starts, the task states the observable after-state, its target, and the proof that will settle it.
- **DOD-2 The actor can't grade itself.** The agent submits evidence. A separate verifier (the runner, a check, a person) issues the verdict.
- **DOD-3 A zero exit code is not proof.** A clean exit says the process stopped, not that the work happened.
- **DOD-4 Read back from the source of truth.** Check the system where the result lives, after the run. Not the agent's context, not your own dashboard.
- **DOD-5 Cited proof must resolve.** Every URL, path, ID or hash in a receipt must exist when checked. A missing one downgrades the claim.
- **DOD-6 Honest status words.** Report the highest rung on the ladder you can prove, and no higher.
- **DOD-7 The agent's own words beat its status.** If its report says blocked, waiting, or incomplete, the task is not done, whatever the status field says.
- **DOD-8 No scaffold counts as done.** A mockup, placeholder, local build, stub returning HTTP 200, or passing unit test is not the live outcome, unless it was the named deliverable.
- **DOD-9 A blocker parks one item, not the run.** Blocked names the exact outside condition and who can clear it. The fleet moves to the next item.
- **DOD-10 Reconcile unknown writes before retrying.** If a write returned an error, read back whether it happened before trying again, and retry with an idempotency key. (One publishing API in my fleet saved each post and then returned an error. The agent retried. 17 duplicate articles went live.)

## Part 2: AI agent governance, running agents in production

Governance is who can make an agent act, what it may do without asking, and how you prove what it did. Most governance guides stop at policy documents. These rules are enforced in the runner, across many agents, many model harnesses, one queue, and nobody watching in real time. Every rule below is one I run.

- **GOV-1 One task, one owner.** One agent or harness is responsible from claim to verdict. Handing off does not complete a task.
- **GOV-2 The outcome ledger is the truth.** Every settlement is appended to a log that is never edited. The board is a projection derived live from that log, never a set of cards someone pushed.
- **GOV-3 No blind writes to shared state.** Queue and board writes are locked merges. One agent never overwrites another's status fields.
- **GOV-4 Every task has a time cap and the fleet has a kill switch.** I use 30 minutes per task and a single pause file that stops every runner.
- **GOV-5 Gate what can't be undone.** Sending, publishing, spending, provisioning and migrating wait for a person's approval. Approval is not delivery. Routing or testing never removes a hold.
- **GOV-6 Check consent and do-not-contact before contact, not after.** The check runs before the action. A pass is permission to proceed, not proof of delivery.
- **GOV-7 Report held, shipped and done separately.** A held run is the gate working. It is also zero deliveries. Both are true, so count both.
- **GOV-8 Log cost per attempt.** Tokens and dollars per run, so you can compute cost per verified task, not cost per claim.
- **GOV-9 Every loop gets a tripwire.** When a loop breaks, a watcher queues its own repair task. Green exit codes prove nothing.
- **GOV-10 Failures of the harness are not failures of the task.** Expired auth or a usage limit releases the task back to the queue and rotates to a healthy harness. It is never settled as done or failed.
- **GOV-11 Weakening a gate needs its false positive as a test.** Any change that loosens a check lands together with the case that justified it.
- **GOV-12 Publish the counts.** Proof rate, hold rate, cost per verified task, and revenue you can trace. Anecdotes are not a scorecard.

### The governance scorecard

| Metric | Formula |
|---|---|
| Proof rate | done at P3 or above ÷ done claimed |
| Hold rate | held ÷ settled |
| Cost per verified task | total cost ÷ done at P3 or above |
| Verified revenue | dollars traced to P4 receipts |

My own scorecard for 2026-10-01 to 2026-11-06: 585 done claimed, 1 with enforced read-back, 223 held, token usage logged on 8% of attempts, verified revenue from fleet work $0. v2 will report cost per verified task in dollars.

## The receipt

Every settled task ends with a receipt that a different process can check. JSON, one object per task (schema: https://connorgallic.com/agent-dod/receipt.schema.json):

```json
{
  "dod": "1.0",
  "task_id": "publish-pricing-page",
  "owner": "worker-a",
  "outcome": "Pricing page is live at its URL and shows the new plan name",
  "target": "https://example.com/pricing",
  "claimed_status": "done",
  "report": "Merged the change and confirmed the page.",
  "exit_code": 0,
  "proof": [
    {"kind": "pull_request", "ref": "https://github.com/example/site/pull/12", "checked_by": "actor", "result": "pass"},
    {"kind": "http_contains", "ref": "https://example.com/pricing", "expect": "Team plan",
     "checked_by": "runner", "checked_at": "2026-11-07T01:00:00Z", "result": "pass"}
  ],
  "approval": {"required": false},
  "business_outcome": {"class": "visible_content", "ref": "https://example.com/pricing", "verified": false},
  "cost": {"input_tokens": 412000, "output_tokens": 9100, "usd": 0.84},
  "verdict": "done",
  "verdict_by": "runner",
  "settled_at": "2026-11-07T01:00:05Z"
}
```

Read-back proof kinds: `http_contains`, `provider_object`, `sent_log`, `call_log`, `payment`, `deployment`, `record`. Artifact proof kinds: `commit`, `pull_request`, `file`, `test_run`, `screenshot`, `log`. Anything else is an assertion.

## Run the checker

```bash
curl -sLO https://connorgallic.com/agent-dod/agent_dod.py
python3 agent_dod.py check receipts.jsonl          # offline: scores what the receipts say
python3 agent_dod.py check receipts.jsonl --live   # re-reads http_contains proofs itself
python3 agent_dod.py check receipts.jsonl --json   # machine-readable report
```

Python 3.10+, standard library only, no credentials. It accepts loose logs too: a record with only `{"status": "done"}` scores P0, so you can point it at whatever your agents write today and get your proof rate. Exit codes: 0 every done claim meets the bar, 1 at least one doesn't, 3 invalid input.

This standard is the check after an action. For the check before an outbound action (consent, approval, quiet hours, opt-out, idempotency) see the open source rails in KaiCalls smb-voice-bench: https://github.com/KaiCalls/smb-voice-bench/blob/main/docs/RAILS.md

## Changes

- 1.0 (2026-11-07): first public version.

Corrections and counter-examples are welcome. A proposed change to a rule should come with the case that breaks it.
