Synthe is the bouncer for your AI agents: every handoff gets checked at the door, and the bad ones don't get in.
When one AI agent hands work to another, Synthe validates the handoff as a typed packet before the receiver acts. ACCEPT or REJECT, with a reason. Every accepted handoff is recorded, so the same one cannot be claimed twice.
Try it in two minutes
$ git clone https://github.com/rohansiddam/Synthe.git
$ cd Synthe
$ python3 src/handoff_check.py examples/valid.json --registry examples/registry.json --workspace . --ledger ledger.json
ACCEPT Run the same command again and it is rejected as a duplicate.
$ python3 src/handoff_check.py examples/bad-paraphrase-evidence.json --registry examples/registry.json --workspace . --dry-run
REJECT invalid: evidence_not_verbatim
Python 3 only, no install step. Exit code 0 means ACCEPT, 2 means REJECT.
How it works
-
The sender ships a typed packet, not a blob of text.
-
Synthe checks it against a registry and the actual artifacts it references.
-
ACCEPT records the claim. REJECT comes back with the reason, and replays of an accepted handoff are rejected as duplicates.
What it catches
- Duplicates
- Expired handoffs
- Stale artifacts
- Missing fields
- Actions the receiver is not allowed to take
Proof
Three runs were dispatched back to back on real GitHub runners on October 1, 2026. Exactly one got ACCEPT and flipped to COMPLETED. The other two were both rejected as duplicates, with code duplicate_idempotency_key, checked against the completed entry rather than the claim-time snapshot.
See it run
The same handoff was submitted three times, in three runs back to back on real GitHub runners. The first run got ACCEPT and was recorded as COMPLETED. The second and third runs got REJECT, checked against the completed entry. The receiver never starts the same work twice.
$ run 1: submit handoff
ACCEPT Handoff recorded and completed.
$ run 2: submit the same handoff again
REJECT The work does not start a second time.
$ run 3: submit the same handoff once more
REJECT Rejected again, against the completed entry.
{
"decision": "REJECT",
"state": "duplicate",
"reason": "duplicate_idempotency_key"
}
What this catches
- Duplicate handoffs The same handoff arrives twice. The second copy is rejected, so the work runs once.
- Expired handoffs The handoff sat too long before it arrived. It is rejected instead of acted on late.
- Stale artifacts The artifact changed after the handoff was made. Its hash no longer matches, so the handoff is rejected.
- Missing required fields A field the receiver needs is absent. The handoff is rejected with the gap named.
- Actions the receiver is not allowed to take The handoff asks for an action outside the receiver's permissions. It is stopped before anything runs.
What changes with Synthe
The receiving agent gets a blob of text and takes it on trust. It can redo work another agent already did. It can act on artifacts that changed since the handoff. It can run actions nobody approved.
The handoff is checked at the door, before any work starts. A bad one is stopped with a reason. A good one is recorded, so it cannot be claimed twice.
Updates
-
September 30, 2026
Two-runner verification passed on real GitHub runners. Exactly one ACCEPT across two runs; the second was rejected as a duplicate.
-
September 30, 2026
Public repo is live. Spec, checker, GitHub Action, and tests are all in the open.