A JSON receipt for AI handoffs, and a small check for "done"
An AI saying "done" is a claim. Work is complete only when something outside that AI has checked it.
I run my personal website, akiohirayama.com, in nine languages with ChatGPT/Codex and Claude. Several AIs touch the same work: one drafts, another reviews, a third checks how pages actually render. The weak point is the handoff. The next AI usually receives a summary it has to believe.
This post shows the fix I use: a small, structured receipt that travels with the work, and a check that reads it.
The card
The Multi-AI Handoff & Approval Card has eight fields. If any of them is empty, the work has only been reported. It is not done yet.
{
"task": "what was asked, in one sentence",
"claimed_result": "what the AI says it did",
"risk_tier": "auto | auto-then-verify | human-approval",
"risk_reason": "why this tier",
"evidence": [
{
"check": "what was checked",
"checked_by": "script / fresh-context run / human (not the same AI run)",
"result": "pass | fail | unclear"
}
],
"changed": ["pages, files or systems touched"],
"rollback": {
"how": "how to undo it",
"who": "who can undo it"
},
"open_items": ["anything unverified, ambiguous or skipped"],
"approved_by": "a human, or the rule that allowed auto-approval"
}
Three fields do most of the work:
evidencerecords who checked the result, and that checker cannot be the AI run that did the work. It can be a script, a separate run with a fresh context, or a person.rollbackforces the question "can we undo this, and who would do it?" to be asked before the work is accepted.open_itemsis where honest uncertainty goes. An empty list is a claim too, so it should be true.
Risk tiers decide who has to look
Not every step needs a human. Approving everything trains people to click "yes" without reading.
| Tier | Examples | Default |
|---|---|---|
| auto | Draft a translation, generate a design option | Run automatically, log it |
| auto-then-verify | Change a live page, update shared text | Run, then verify before it counts as done |
| human-approval | Publish, delete, spend, touch credentials, message anyone | Stop and ask a human, with a one-screen summary |
A small check that refuses to say "done"
A receipt is only useful if something reads it. This script returns DONE only when every field is filled, every piece of evidence passed and has a named checker, the rollback says both how and who, and no open items remain.
import json
import sys
REQUIRED = ["task", "claimed_result", "risk_tier", "risk_reason", "evidence", "changed", "rollback", "open_items", "approved_by"]
TIERS = {"auto", "auto-then-verify", "human-approval"}
def check(card):
problems = []
for key in REQUIRED:
if key not in card:
problems.append(f"missing field: {key}")
for key in ["task", "claimed_result", "risk_reason", "approved_by"]:
if key in card and not str(card[key]).strip():
problems.append(f"empty field: {key}")
if card.get("risk_tier") not in TIERS:
problems.append("risk_tier must be auto, auto-then-verify or human-approval")
evidence = card.get("evidence") or []
if not evidence:
problems.append("no evidence: the work is reported, not done")
for item in evidence:
if item.get("result") != "pass":
problems.append(f"evidence not passing: {item.get('check', '?')}")
if not str(item.get("checked_by", "")).strip():
problems.append(f"evidence without a checker: {item.get('check', '?')}")
rollback = card.get("rollback") or {}
if not rollback.get("how") or not rollback.get("who"):
problems.append("rollback needs both how and who")
if card.get("open_items"):
problems.append(f"{len(card['open_items'])} open item(s) still listed")
return problems
if __name__ == "__main__":
with open(sys.argv[1], encoding="utf-8") as f:
card = json.load(f)
found = check(card)
for p in found:
print("-", p)
print("DONE" if not found else "NOT DONE")
sys.exit(0 if not found else 1)
Here is a card that fails:
{"task":"Publish the article","claimed_result":"Published","risk_tier":"human-approval","risk_reason":"public","evidence":[{"check":"links work","checked_by":"","result":"unclear"}],"changed":["note.com"],"rollback":{"how":"unpublish"},"open_items":["image credits"],"approved_by":""}
- empty field: approved_by
- evidence not passing: links work
- evidence without a checker: links work
- rollback needs both how and who
- 1 open item(s) still listed
NOT DONE
The exit code is non-zero, so the same check can gate a pipeline step or a handoff to the next agent.
What this does not solve
- Risk tiers drift as the context changes. A "safe" edit on a page nobody reads becomes risky on the homepage.
- Verifiers can be wrong too. A passing check is evidence, not proof.
- A different AI is not automatically an independent one. Two models given the same flawed summary can agree on the same mistake.
Use it
The card, card.json and a longer field guide are free under CC BY 4.0:
- Template: github.com/akiohirayama/multi-ai-handoff-card
- Field guide: akiohirayama.github.io
- Notes: Multi-AI Control Notes
I am also hiring an AI Engineer, at a monthly salary of USD 30,000, to build this kind of control layer across multiple AIs: role details.
- AKIO HIRAYAMA (akiohirayama.com)
Comments
No comments yet. Start the discussion.