Synthe

Synthe docs

How the commit barrier works, and everything you need to check your first handoff with the public checker. The full spec and threat model live in the repo.

Checker v0.5 · packet schema 0.1 · docs October 2026

The commit barrier

Synthe sits between your agents and the systems they change. Agents never hold the credentials for real-world actions; Synthe does. An agent proposes an action, and Synthe decides at the moment of commit, not when the plan was written.

  1. ClaimThe receiving agent claims a signed handoff. The checker validates it and records the claim under its idempotency key, so the same work can't be claimed twice.
  2. Work and proposeThe agent does the work, then proposes the effect, for example a push of its commits to an approved branch. It never touches the GitHub token.
  3. Re-check at commitSynthe checks the signed handoff and the human approval again, inspects every path the change touches against the agent's allowed paths, and waits for any upstream handoffs to complete.
  4. Compare and swapSynthe pushes only if the branch still points where the approval saw it. If anything moved, it pushes nothing and refuses with non_fast_forward.
  5. Confirm and receiptSynthe re-reads the remote to confirm the effect, then signs a hash-chained receipt. Every refusal gets a receipt too, with its reason.

Public today Step 1, the claim ledger, signatures, approvals and evidence checks, in the public checker.

Public beta Steps 2 to 5, in the commit broker. git_push ships first, with an OpenClaw plugin and a guided setup on macOS that takes a few steps (quickstart). Ask about a pilot.

What it can't do: an action a human approved will do exactly what was approved, and receipts prove which key and connector acted, not which model wrote the work. Synthe is only a barrier if agents can't go around it, so take their own credentials away. The full list is on the status page. To watch the rules play out, race two agents for one commit.

Getting started

Clone the public checker and run it against the example packets. Two minutes, nothing to install beyond Python 3.

$ git clone https://github.com/rohansiddam/Synthe.git && cd Synthe

$ python3 src/handoff_check.py examples/v03/packets/valid-signed.json --registry examples/v03/registry.json --workspace examples/v03/workspace --ledger ledger.json
{ "decision": "ACCEPT", "handoff_id": "h-v03-0001", "signature": "verified", "claim": { … } }

Output shortened. Exit code 0 means ACCEPT, 2 means REJECT. Run the same command again and the second claim is refused with idempotency_key_reserved. Leave out --ledger to check a packet without claiming it.

The check order

The checker always runs these seven checks in the same order. If the structure is broken it stops right there. Otherwise it keeps going and reports every problem it finds, and the verdict takes its state from the first one, so the earliest broken link comes first.

  1. StructureRequired fields, types, full-length hashes, and declared actions when the receiver requires them. missing_field:id, bad_schema_version, planned_actions_missing
  2. Identity and signatureSender and receiver resolve in the registry by their canonical ids, and the packet's Ed25519 signature verifies. unknown_agent:from, signature_invalid
  3. Duplicates and conflictsThe idempotency key is looked up in the ledger. Wait-for cycles and overlapping live claims are refused. idempotency_key_reserved, duplicate_idempotency_key, claim_conflict
  4. FreshnessThe handoff hasn't expired. handoff_expired
  5. AuthorityPlanned actions against allowed tools, forbidden actions, signed approvals and budget, with the receiver's policy as a ceiling. approval_missing, authority_exceeds_receiver_policy
  6. ArtifactsEach input file exists inside the workspace and still matches its pinned SHA-256. artifact_hash_mismatch
  7. EvidenceRequired evidence is present, verbatim quotes are marked verbatim, and pinned evidence matches its file. evidence_not_verbatim, evidence_hash_mismatch

Core concepts

The packet

A handoff is a typed JSON packet: who sends, who receives, what to do, what evidence backs it, and what the receiver may do next. Nothing free-form.

The registry

Each receiver holds a registry of agent identities, public keys and its own policy. A packet's signature is verified against the registry, and the policy is a ceiling: authority can only narrow as work passes along.

The ledger

An ACCEPT is a claim, recorded under the handoff's idempotency key. The receiver marks it completed only after the effect is real. The same work can never be claimed twice, even across restarts.

Approvals

Actions that need approval must carry a human's signed approval. An approval can pin the exact target, like a branch, and it can arrive after work has started; nothing commits without it.

Receipts

At the commit barrier, every push and every refusal is written as a receipt that carries the hash of the one before it and a signature. Change or delete one and verification shows where the chain breaks. Receipts are part of the commit broker beta.

Reason codes

Every REJECT names its reasons. Each one has a state that says who should act. This is the complete list for the public checker v0.5, from section 10 of the spec.

invalid · the sender fixes the packet
missing_handoffThe packet has no handoff object.
missing_field:nameA required field is absent or empty, for example missing_field:purpose.
bad_schema_versionOnly packet schema 0.1 is accepted.
bad_on_failureon_failure is not one of reject, retry_with_budget, escalate or request_human.
malformed:fieldA field has the wrong type or shape, for example a depends_on that isn't a list of keys.
bad_sha256:fieldA hash is not a full 64-character SHA-256. Shortened or placeholder hashes are refused.
planned_actions_missingThe receiver's policy requires declared planned actions, and there are none.
unknown_agent:from / :toThe sender or receiver is not in the registry.
alias_not_canonical:from / :toAn alias was used where the canonical agent id is required.
signature_missingThe receiver requires a signed packet, and there is no signature.
signature_malformedThe signature block is not an object with a sig string.
signature_alg_unsupportedOnly Ed25519 signatures are accepted.
signature_signer_mismatchThe signer named in the signature is not the packet's sender.
signature_key_unknownThe registry has no Ed25519 key for that signer and key id.
signature_invalidThe signature doesn't verify: the packet was changed after signing, or the wrong key was used.
signature_unsupportedThe checker can't verify signatures because synthe_crypto.py is missing next to it.
bad_expires_atacceptance.expires_at is not a valid timestamp with a time zone.
artifact_path_escapes_workspaceAn input path points outside the workspace.
evidence_path_escapes_workspaceAn evidence reference points outside the workspace.
evidence_not_verbatimEvidence of a verbatim kind, like a quote, is marked as a paraphrase or summary.
verbatim_evidence_unpinnedEvidence claims to be verbatim but pins no SHA-256, so it can't be checked.
workspace_requiredA receiver policy is in force but no workspace was given, so pinned hashes can't be checked. Run with --workspace.
packet_unreadableThe packet file can't be read or isn't valid JSON.
registry_unreadableThe registry file can't be read.
registry_malformedThe registry isn't in the expected shape.
ledger_corruptThe ledger file is not valid JSON.
ledger_requiredCompleting a claim needs --ledger, because the claim lives there.
missing_idempotency_keyThe handoff has no idempotency key to claim.
completion_unknown_keyCompletion was asked for a key with no live claim.
claim_token_requiredThe entry point requires the claim token to complete, and none was given.
release_not_reservedA release was asked for a key that has no reserved claim.
dependency_cycledepends_on would close a wait-for cycle through live claims.
blocked · an owner or approver acts, or the work waits
tool_not_allowedA planned action uses a tool outside the handoff's allowed_tools.
tool_not_allowed_by_receiverA planned action uses a tool the receiver's policy doesn't allow.
forbidden_actionA planned action is forbidden by the handoff's scope.
approval_missingAn action that needs approval has none.
approval_expiredThe covering approval has expired.
approval_expires_invalidAn approval's expiry is not a valid timestamp.
approver_not_trustedThe approval comes from someone the receiver doesn't trust to approve.
approval_unsignedThe receiver requires signed approvals, and this one is unsigned.
approval_signature_invalidAn approval's signature doesn't verify for its approver on this handoff.
approval_params_mismatchThe approval pins a target, like a branch, that the plan doesn't match.
authority_exceeds_receiver_policyThe handoff asks for more than the receiver's policy allows.
budget_exceededEstimated tokens, dollars or minutes exceed the budget.
dependency_incompleteAn upstream handoff in depends_on hasn't completed yet. The commit waits; the claim stays.
dependency_unknownAn upstream handoff in depends_on was never claimed in this ledger.
claim_conflictUnder exclusive paths, the files this handoff owns may overlap another live claim.
incomplete · the sender supplies what's missing
artifact_missingAn input file named in the handoff isn't in the workspace.
evidence_missingA required kind of evidence has no entry.
evidence_unreferencedAn evidence item has no reference, so there's nothing to verify.
evidence_ref_missingAn evidence reference points to a file that isn't in the workspace.
stale · the sender refreshes
handoff_expiredThe handoff expired before it was checked.
artifact_hash_mismatchAn input file changed after the handoff was made.
evidence_hash_mismatchAn evidence file changed, or was swapped, after it was pinned.
duplicate, conflicting or unknown · don't run it again
idempotency_key_reservedAnother claim on this key is still running.
duplicate_idempotency_keyThis work already completed. With a different handoff behind it, the state is conflicting and a human resolves it.
completion_handoff_mismatchThe key was claimed by a different handoff than the one being completed.
completion_packet_mismatchCompletion must present the exact packet that was claimed.
claim_token_invalidThe claim token doesn't match the claim.
release_claim_freshThe claim is younger than its time limit and its holder may still act. Wait, or force it if you know the holder is gone.
unknown_outcomeThe claim was never completed within its time limit. Reconcile before sending the work again.
effect_already_executedThis effect already ran for this handoff.
effect_outcome_unknownThis effect started but its outcome was never confirmed. Reconcile before retrying.

Try it interactively

Every check above runs in your browser, no install needed.

Full references