aragora-verify
Verify an Open Decision Receipt offline — no Aragora install, no server, no account.
Action-level receipts (Microsoft AGT, SCITT, in-toto/SLSA) prove what happened and whether policy allowed it. An Open Decision Receipt (ODR) proves the layer above: why it was decided, who adversarially examined it with what model diversity, who dissented, how calibrated the confidence was, and whether an accountable human accepted the risk.
aragora-verify is the free, standalone tool that lets anyone — an auditor, a
customer, a skeptic — check such a receipt is genuine and well-formed:
- Schema conformance to the ODR v0.1 content profile.
- Canonical digest — recomputes
SHA-256(JCS(receipt − signatures))per RFC 8785, the value any detached signature covers. - Ed25519 signature — verifies detached signatures with only the public key.
- Quorum consistency — every supporting/dissenting agent is a disclosed participant (a mismatch is a tamper/malformed signal).
- Hash-chain linkage — when a chain is supplied, the receipt is anchored in it and the links are continuous.
It depends only on the Python standard library plus cryptography.
Install
pip install aragora-verify
Use
# Structural + canonical-digest check
aragora-verify receipt.odr.json
# Full authenticity check against the issuer's published public key
aragora-verify receipt.odr.json --pubkey aragora-odr-signing-key.pem
# Also confirm the receipt is anchored in a hash chain
aragora-verify receipt.odr.json --pubkey key.pem --chain intent-chain.jsonl
# Machine-readable result
aragora-verify receipt.odr.json --pubkey key.pem --json
# Confirm the ACTA-02 projection envelope really carries this receipt
aragora-verify receipt.odr.json --pubkey key.pem --acta receipt.acta.json
# v0.2 signature policy: fix the expiry clock, fail on expiry, demand a signer
aragora-verify receipt.odr.json --pubkey key.pem --now 2026-01-15T12:00:00Z
aragora-verify receipt.odr.json --pubkey key.pem --strict-expiry
aragora-verify receipt.odr.json --pubkey key.pem --require-issuer aragora
A v0.2 signature that carries expires_at and has passed it still verifies, with
an expired at <timestamp> warning; --strict-expiry turns that warning into a
failure. --require-issuer NAME needs at least one signature whose
signer-committed issuer is NAME to verify under --pubkey, and a verified but
expired signature satisfies it unless --strict-expiry is given as well. On a
v0.1 document issuer is not covered by the signature, so --require-issuer can
never pass there.
Exit code 0 means verified (no failed checks, and any present signatures were
checked); 1 means a check failed; 2 is a usage/input error; 3 means the
receipt is structurally OK but carries signatures that were not checked
(no --pubkey supplied) — authenticity is unestablished, so it is deliberately
not reported as 0/VERIFIED.
The public key for receipts emitted by an Aragora deployment is published at
GET /.well-known/aragora-odr-signing-key and GET /api/v2/receipts/signing-key
(both endpoints are live in the Aragora unified server; see #8804/#8809). Verify
that a specific deployment actually serves the key at those paths before relying
on them for automated verification.
Weakening vs. failing
Absent markers ({"status": "absent", ...}) and "undisclosed" model families
are honesty signals — a receipt full of them is visibly weak, not a
strong-looking fabrication. They are reported as weakening signals and do
not fail verification; the policy thresholds (e.g. "require ≥2 model
families", "require human attestation") are yours to apply on top.
Known limitations (v0.1)
The verifier is deliberately conservative and these are documented, not silent:
- Hash-chain (
--chain) is anchoring + self-consistency, not integrity. It confirms the receipt's content digest appears in the chain and that declaredprev_hash/hashlinks are internally consistent, but it does not recompute entry hashes — so it reportschain_linkasWARNwhen links are present. A party who controls the chain file can fabricate consistent-looking linkage; the chain is corroborating evidence, not a tamper proof on its own. - Signature verification is single-key, Ed25519-only. It verifies that at least
one
signatures[]entry validates against the supplied--pubkey(and fails if an entry targeting that key fails). Richer multi-signer / threshold policies are out of scope for v0.1. - I-JSON numeric range. Canonicalization assumes IEEE-754-double-safe numbers (per RFC 8785 / I-JSON). Integers at or beyond 1e21 are not expected in ODR payloads and are not specially handled.
Library
from aragora_verify import verify, load_public_key
result = verify(receipt_dict, public_key=load_public_key(pem_bytes))
print(result.ok, result.odr_digest)
for check in result.checks:
print(check.name, check.status, check.detail)
What this is part of
ODR-3 of the Open Decision Receipt epic. The verifier is free and standalone by design — the emitter (adversarial debate + signed decision receipts) is the product. See the content-profile spec.
License
MIT
Release files for aragora-verify 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| aragora_verify-0.2.0.tar.gz | 61.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| aragora_verify-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 98.8 kB
Release files / aragora_verify-0.2.0.tar.gz
| Download URL | aragora_verify-0.2.0.tar.gz |
|---|---|
| Size | 61.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
1b1550abdd90ab8022b9c8cdeaea31e8025a76e3970de14f05ade0247f01a4d7
|
|
BLAKE2b-256 checksum How to use checksums |
97305b82932817976fc2f77df4c7914d9b219e6c2139d71fb7a1c771b7ad5b3c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / aragora_verify-0.2.0-py3-none-any.whl
| Download URL | aragora_verify-0.2.0-py3-none-any.whl |
|---|---|
| Size | 37.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
042093f598c0b3ef4531af7eb38c4ca3342280fbe9ee0973fed59c77c3a02c4c
|
|
BLAKE2b-256 checksum How to use checksums |
ba33e302e2f50138734167eb49a43594eb9503da559df3465f000b87e9a37e94
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|