How it works
How Synthe works
Synthe sits between your agents and the systems they change. Here is the path every action takes, what it refuses, and how to check the public part yourself.
The commit path
An agent never touches the credential. It hands Synthe a signed proposal, and Synthe decides at the last possible moment, when the action is about to happen.
-
Propose
The agent sends a typed, signed handoff instead of a blob of text: who it is, what it plans to do, and the exact files it relied on, pinned by hash.
Public checker -
Approve
A human signs the plan. The approval names the exact target, like the branch to push to, so nobody can point it somewhere else later. It can arrive after the work starts; nothing commits without it.
Public checker -
Re-check at commit
When the agent is ready, Synthe checks everything again: the signature, the approval, every path the change touches against the agent's allowed paths, and that nothing moved since the check.
Commit broker · beta -
Re-check, commit, receipt
Synthe performs the action itself, only if nothing changed since you approved, and signs a hash-chained receipt. A used approval can't be replayed. A refusal gets a receipt too, with the reason.
Commit broker · beta
Without Synthe, and with it
Each agent holds a token that can push, deploy or send. A retried task runs twice. An agent acts on files that changed after you approved the plan. When something goes wrong, nothing records who approved what.
Agents hold no production credentials. Every action is checked against a signed approval at the moment it happens, runs once, and leaves a signed receipt, whether it was allowed or refused.
What it stops
Every refusal names its reason, in plain words for you and as a code your tools can read.
-
Work done twiceA retried or duplicated handoff tries to run again. The second claim is refused with a receipt.
REJECTduplicate_idempotency_key -
Stale filesA file the plan relied on changed after it was signed. Its pinned hash no longer matches.
REJECTartifact_hash_mismatch -
Actions nobody approvedThe plan includes an action that needs a human's signature, and there isn't one.
REJECTapproval_missing -
An approval pointed somewhere elseThe human approved a push to one branch. The agent asks to push to another.
REJECTapproval_params_mismatch -
Authority nobody gaveThe handoff asks for more than the receiver's policy allows. Authority can only narrow as work passes along.
REJECTauthority_exceeds_receiver_policy -
A branch that moved BetaAnother push landed first. Synthe pushes only if the branch is still where the approval saw it, and pushes nothing otherwise.
REJECTnon_fast_forward
Every code, with who should act on it: the reason-code reference.
Try to break the public checker
The repo ships one valid signed packet and 8 attacks. Run them all, or step through them below.
$ for f in examples/v03/packets/*.json; do
> python3 src/handoff_check.py "$f" --registry examples/v03/registry.json --workspace examples/v03/workspace --dry-run \
> | python3 -c 'import json,sys; v=json.load(sys.stdin); print(sys.argv[1].ljust(31), v["decision"], *[r["code"] for r in v.get("reasons", [])][:1])' "$(basename "$f" .json)"
> done
attack-exceeds-receiver-policy REJECT authority_exceeds_receiver_policy attack-forged-approval REJECT approval_unsigned attack-paraphrased-verbatim REJECT evidence_hash_mismatch attack-replayed-approval REJECT approval_signature_invalid attack-self-granted-authority REJECT approval_missing attack-spoofed-sender REJECT signature_invalid attack-tampered-after-signing REJECT signature_invalid attack-undeclared-actions REJECT planned_actions_missing valid-signed ACCEPT
Step through the attacks
Use the arrows to step through the attacks.
The keys in examples/v03/test-keys/ are public test keys. Bring your own keys for real use.
Run it yourself
Two minutes, nothing to install beyond Python 3.
$ 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
{ "decision": "ACCEPT", "handoff_id": "h-0001", "claim": { … } }
$ python3 src/handoff_check.py examples/valid.json --registry examples/registry.json --workspace . --ledger ledger.json
{ "decision": "REJECT", "state": "duplicate", "reasons": [{ "code": "idempotency_key_reserved", … }] }
Exit code 0 means ACCEPT, 2 means REJECT. Output shortened here; the checker prints the full JSON verdict. More in the docs.
What it can't stop
- An approved action doing what was approved.Synthe narrows a compromised sender to the one action a human approved; it can't remove that action.
- Which model wrote the work.Receipts prove which key and which connector acted, not which model produced the bytes.
- Agents that go around it.If an agent still holds its own push rights, the barrier is optional. Take those credentials away.
The full list, and what we haven't proven yet, is on the status page.