DEV Community

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:

  • evidence records 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.
  • rollback forces the question "can we undo this, and who would do it?" to be asked before the work is accepted.
  • open_items is 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)
Read on DEV Community ↗ ← Back to News

Comments

No comments yet. Start the discussion.