Docs
How ResultBond works, in detail.
For engineers who will integrate receipts, check them, or settle money on them.
How a job works
- Manifest. Buyer, provider and ResultBond sign one manifest: the repository snapshot, the public and hidden test packs, the acceptance criteria, the runner limits, the price and the stipend. Its SHA-256 digest is the job's identity.
- Hidden tests are proven. Before any agent works, each hidden test must fail on the base commit and must not duplicate a public test. Otherwise the job is not judged automatically.
- Submission. The provider signs one submission: the patch digest and the snapshot it produces. That exact code is what gets judged.
- Sandbox. The base and the candidate run in an isolated sandbox (no network, CPU, memory, process and output limits) with the public tests, the hidden tests and, optionally, the repository's own tests as a regression check. The candidate runs up to three times (three by default).
- Receipt. The policy turns the signed evidence into PASS, FAIL or INCONCLUSIVE and the evaluator signs a Proof Receipt. Every step is an event in a hash-chained log with signed checkpoints.
- Settlement. In bonded mode the receipt settles an escrow contract. In shadow mode nothing moves; you just keep the receipts.
The Proof Receipt
A receipt is a JSON document with four keys: payload, payload_digest, signature and evaluator_public_key_b64url. Unknown keys are rejected.
| Payload field | Meaning |
|---|---|
| receipt_version | Always rb.proof-receipt.v0.3 for this format. |
| job_id, partner_id | The job, namespaced by the partner that hosts it. |
| manifest_digest | The signed terms this receipt is about. |
| candidate_submission_digest | The provider-signed submission: which code was judged. |
| evidence_digest | The signed sandbox evidence the decision was made on. |
| decision_digest | The policy decision. |
| outcome, reason_code | PASS, FAIL or INCONCLUSIVE, and why (see below). |
| settlement | currency (USDC), payment_action (RELEASE_PAYMENT or REFUND_PAYMENT), payment_atomic, stipend_atomic (6 decimals) and requires_manual_review. |
| evaluator_id, evaluator_key_id | Who signed. The key id is also in the signature and must match. |
| event_sequence, previous_event_digest | Where the receipt sits in the job's event log, so a truncated or rewritten log is detectable. |
| issued_at, policy_id, receipt_id | When, under which policy, and a stable id. |
| previous_receipt_digest | Optional: the receipt this one supersedes. |
Digest. payload_digest is sha256: + hex SHA-256 of the payload in canonical JSON: keys sorted, no insignificant whitespace, UTF-8, integers only (no floats), timestamps in UTC with a Z.
Signature. Ed25519 over the bytes RESULTBOND-CANONICAL-SIGNATURE-V0.1\0 + proof-receipt + \0 + canonical payload. The signature's purpose must be proof-receipt.
Outcomes and reasons
| Outcome | Reason codes | Money |
|---|---|---|
| PASS | ALL_CHECKS_PASS | Payment to the provider; its bond is returned. |
| FAIL | HIDDEN_TEST_FAILURE · PUBLIC_TEST_FAILURE · REGRESSION_FAILURE · CANDIDATE_TEST_ERROR · BOUND_TEST_SKIPPED · CANDIDATE_RUNTIME_FAILURE · TEST_HARNESS_TAMPERING | Payment back to the buyer, plus the stipend from the provider's bond. |
| INCONCLUSIVE | BASELINE_NOT_REPRODUCIBLE · CANDIDATE_NOT_REPRODUCIBLE · INFRASTRUCTURE_ERROR · HIDDEN_INDEPENDENCE_NOT_PROVEN · EVIDENCE_BINDING_MISMATCH · EVIDENCE_INCONSISTENT · POLICY_VIOLATION | Held for a person. An independent reviewer signs release, refund, or no-fault (both deposits returned). |
A FAIL needs every candidate replay to fail. Breaking a resource limit in any replay is a FAIL. A good fix is never failed by a test that could not be validated: that case is INCONCLUSIVE.
Verifying a receipt
In the browser
Paste or drop a receipt on /verify. The check runs locally with WebCrypto; nothing is uploaded. Copy share link puts the receipt itself into the link's # fragment, which browsers never send to a server.
JavaScript (browser or Node 20+)
import { verifyReceiptText } from "https://resultbond.com/js/receipt.mjs";
const result = await verifyReceiptText(receiptJson, {
trustedKeys: { "rb:evaluator:2026-10": "k3qnbpbsfVPtAtfgsbMs_H18mKRKJzRSrHUSWnBXDpQ" },
});
// { valid, trusted, outcome, payloadDigest, reasons }
if (!result.valid || !result.trusted) throw new Error(result.reasons.join("; "));
To trust whatever keys ResultBond currently publishes, load them with trustedKeysFromKeySet from the same module (see Keys and trust).
Python
resultbond verify-receipt receipt.json --online --text # fetch the key set from resultbond.com
resultbond verify-receipt receipt.json --keyset resultbond-keys.json # offline, a saved key set
The root key is built into the CLI, so the key set is checked without extra arguments. Exit codes: 0 valid and trusted, 1 invalid or tampered, 3 intact but signed by a key you do not trust, 2 setup error. Pass several receipts at once to check a batch.
The Python package is shared with pilot partners. Both implementations are tested against the same golden vectors for canonical JSON, digests and signatures, and both bind a key-set key to its evaluator identity.
Keys and trust
Verifiers pin one key: ResultBond's offline root key. It signs a key set listing the working keys (evaluator, sandbox runner, test auditor), published at /.well-known/resultbond-keys.json.
| Root key id | rb:root:2026-10 |
| Root public key | k4kS-tpmIN5OQFjdt8Q8AJiaPC_iOa6jfhU5IIz3AUE |
| Evaluator key id | rb:evaluator:2026-10 |
- Expiry. Every key set carries an expiry date (the current one: 5 October 2027) and is re-signed before it. Expired sets are refused.
- Serial. Each set has a serial; remember the newest you have seen and refuse older ones.
- Rotation. A new key is added; the old one stays listed so its receipts remain checkable.
- Revocation. A compromised key gets a revocation time. From then on verifiers refuse everything it signed, whatever date a receipt claims.
Escrow contract
ResultBondEscrow (Solidity 0.8.28), shaped after ERC-8183. One evaluator, fixed when a job is created, decides it once. Money is only credited; each party withdraws its own.
create(manifestDigest, provider, evaluator, payment, stipend, bondBy, decideBy) → jobId // client
cancel(jobId) // client, before the bond
bond(jobId) // provider, before bondBy
complete(jobId, receiptDigest) // evaluator: PASS
reject(jobId, receiptDigest) // evaluator: FAIL
hold(jobId, receiptDigest) // evaluator: INCONCLUSIVE
voidHeld(jobId, reviewDigest) // evaluator, after a no-fault review
expire(jobId) // anyone, after a deadline
withdraw() // anyone with a balance
Job id = keccak256(manifestDigest, client, provider, evaluator, payment, stipend, bondBy, decideBy, chainid, escrow). It commits to every term, so a receipt can settle only the job it was issued for. The same values are in the signed manifest's escrow binding, and the settlement adapter checks all of them before sending a transaction.
| Deadline passed | Who gets what |
|---|---|
| No bond by bondBy | Client: its payment. |
| No decision by decideBy | Client: payment + stipend. |
| Held, no review within 30 days after decideBy | Each side: its own deposit. |
Monad testnet (chain 10143)
| Escrow | 0x07abd499e4708FAf1D09E99fb01f52dB6488A490 |
| Test USDC | 0xb222e08B46D9FC8a0200f9C62E19199c0F72689E |
Testnet only, with test tokens. The contract gets an external audit before it holds real money. See the jobs settled on it →
Running a pilot
From you
- Read access to one Python repository.
- 30–50 real bugs, fixed or open.
- The agent you want judged.
- An engineer for about two hours a week, to review hidden tests and label a sample of verdicts.
From us
- Black-box hidden tests, proven to fail on the old code.
- A signed receipt for every job.
- An agreement report against your reviewers.
- A final go / no-go for bonded mode.