Skip to content
Harshvardhan Pandeybrownlittlefish

all writing

Handover: a Machine-Checkable Protocol for AI Agent Handoffs

A protocol, a linter, and a trap-based benchmark for whether a handoff actually transfers. I am open sourcing it for everyone to try.

Harshvardhan Pandey · Aug 2026

Research and open source: Code and paper on GitHub

also published on Substack.

Trust me, it's done is not a verification strategy. Every AI coding session ends with a summary for whoever picks up next, nothing checks whether it's still true.

Handover is a handoff document a machine can verify: anchored to a commit, carrying a command that must pass before anything is marked done. A linter checks it against your live repo. A trap-based benchmark measures whether it actually transfers. No LLM or network calls anywhere in the enforcement path, and you can install it on Claude Code right now.

Last month, I watched an agent audit a branch 288 commits behind trunk. Almost everything it flagged was already fixed upstream. It wasn't malfunctioning. It trusted an unverified handoff, and there was no mechanism to verify one before it started working.

Everyone is doing context engineering right now (CLAUDE.md and AGENTS.md files, session summaries, handoff notes passed between Claude Code or Cursor sessions) and none of it is machine-verifiable. A summary that was accurate on Tuesday reads exactly the same on Friday, forty commits later.

A Handover document is a YAML header plus prose. The header holds the things that must never be ambiguous:

protocol_version: 1
handoff: guest-checkout
true_at_sha: a1b2c3d4e5f6
first_action: Run the pending migration on the preview database, then point the /api/guest-order route at the new table.
verify_cmd: npm test -- guest-checkout && npm run typecheck
status: in_progress

true_at_sha is the anchor: everything below it was true at that commit, so drift from it is measurable instead of assumed. verify_cmd is the way out of belief: you can't set status: done without one, and the linter runs it.

The linter separates two questions that usually get conflated. Structure (is this document shaped right, scored 0 to 100) is judgeable from the text alone. Truth isn't, so the repo-aware checks are a separate opt-in layer: --repo resolves the anchor commit and measures how far the codebase has drifted, --verify runs verify_cmd, and --claims runs each individual claim's own check and reports which specific ones went stale. No LLM and no network anywhere in the enforcement path: it's a linter, not an agent.

Three repository scenarios, each instrumented with planted failure states a cold agent would plausibly walk into: a reverted change that invites reintroduction, an approach already tried and abandoned, and a next step ambiguous enough to be guessed wrong. The question is whether a handoff artifact steers the successor away from them.

The first agent-in-the-loop run came back perfect. Every condition avoided every trap, including the control that got no document at all. That is not a result, that is a broken fixture. I had written the negative knowledge into the fixture's own source comments ("do not add this back, see the handover doc"), so every agent could read the answer regardless of what I handed it. I measured nothing.

Fixed the fixture, reran it. One trap out of three discriminated: the compliant handoff was the only condition that avoided reintroducing the reverted client-side pricing bug. The misleading summary and the empty control both walked straight into it. Traps 2 and 3 showed no separation at this scale, and the paper reports that instead of dropping them.

One scenario, one trial per condition. That is a pilot, not a study, and the paper uses those words.

In Claude Code (make sure to restart your session, hooks only load at session start):

# In Claude Code, after installing the plugin and restarting:
/handover:write   # scaffolds a compliant handoff from live git state
/handover:lint    # scores it

Or plain Node, any repo, any harness:

# Plain Node, any repo: run from inside your checkout of the handover repo,
# or replace HANDOVER_DIR with the path where you cloned it:
HANDOVER_DIR=~/Github-repos/handover

node "$HANDOVER_DIR"/bin/handover-scaffold.js > Docs/HANDOVER_myfeature_2026-08-01.md
node "$HANDOVER_DIR"/bin/handover-lint.js Docs/HANDOVER_myfeature_2026-08-01.md
node "$HANDOVER_DIR"/bin/handover-lint.js Docs/HANDOVER_myfeature_2026-08-01.md --repo
node "$HANDOVER_DIR"/bin/handover-lint.js Docs/HANDOVER_myfeature_2026-08-01.md --verify --claims --strict

That last command is the point: it verifies the document against the actual repository and reports which specific claims no longer hold.

Falsification, mostly. If a document scores 100/100 and still loses something that mattered in a real handoff, then the protocol is wrong and I want the issue filed. If the bench's traps are gameable, show me how. And if you run the pilot on another model tier and traps 2 and 3 discriminate where they didn't at n=1, that is exactly the open question, we can fix.

Source: Apache-2.0, github.com/geekidharsh/handover.

aiagentsopen source

Subscribe or on Substack for the next one, or book a shoot.

what it comes down to

  • ·A handoff is checkable only if it is anchored to a commit and carries its own verification command.
  • ·Status done should be refused until the verify command actually passes.
  • ·If a benchmark passes every condition including the control, the fixture is broken, not the tool.
  • ·Negative knowledge, what was tried and failed or reverted, is the part a summary loses first.

applied AI

I educate people on how AI actually works, and how to build with it, from first principles. ask about a session

latest: Courage is what makes us human, in the age of AI.

Pleasanton, California