How to verify an AI agent's execution record
6 min readTo verify a Provetrail record, you rehash its events into a Merkle root, check the cryptographic signature on that root against a published key, and confirm that each claimed outcome is bound to committed evidence. You need the record and the public key, nothing else: no access to the system that produced the record, and no call back to it. The integrity check (signature and Merkle root) runs client-side; the governance and ground-truth checks need a verifier for the governance level (L4).
Each step below reuses an existing standard: Ed25519 for keys, COSE for the signature, and Certificate Transparency’s Merkle tree for the events. The specification is a draft (0.1.0-draft), and its wire format is not yet frozen.
Step 1: the published key
Verification starts from identity. The emitter signs with an Ed25519 key, and the corresponding public key is published under a stable key identifier. The sample record on the home page, for instance, is signed by provetrail-conformance-root.
Because the key is public and named, “who emitted this” has a definite answer that anyone can resolve. A record signed by a key you do not recognise is a record you do not accept. This is deliberately the same shape as the key-based identity schemes the rest of the ecosystem uses, so a record can reference an external agent identity instead of minting a private one.
Step 2: the signature
The signature itself is a COSE_Sign1 structure, the CBOR-native signing standard also used by content-provenance and receipt standards in this space. COSE_Sign1 wraps a single signature over a payload, using Ed25519 as the algorithm.
Signing over CBOR is a practical choice. A signature covers exact bytes, so two verifiers must encode the same record to the same bytes. CBOR has a deterministic encoding defined in its own standard (RFC 8949, section 4.2), and it carries 64-bit integers and raw byte strings natively, where JSON needs conventions for both.
Checking the signature tells you the record was emitted by the key holder and has not been altered since. That is authenticity and integrity, together, in one check.
Step 3: the chain
Provetrail commits the events to a Merkle tree and signs the root, using the mechanics from Certificate Transparency (RFC 6962, carried forward in RFC 9162). Certificate Transparency logs have used the same tree construction since 2013.
Change one byte of one event and the recomputed root no longer matches the signed root, so verification fails. A signature over the whole record as one blob would catch that too. The tree adds two things a flat signature cannot: each event is committed individually, so one event can be proved to belong to a signed record without handing over the others, and two checkpoints of the same log can be proved consistent, so a later root shows the log was only appended to. This is what the “tamper a byte” button on the home page demonstrates. Flip a byte, and the proof breaks in front of you.
Step 4: governance and ground truth
Integrity and authenticity establish that the record is intact and came from the key holder. Two further checks establish that the run was governed:
- Governance. Each side-effecting action carries the authorization decision that admitted it. A verifier can confirm that no such action appears without a matching admission, which makes “nothing ran without authorization” a checkable property of the record.
- Ground truth. A claimed success carries a commitment to the check that backs it. A record that asserts an outcome with no bound evidence is rejected. An authorized holder can re-run the check against the committed observation.
In the reference runtime, Flynn, these are reported per tier by flynn spine verify, alongside the integrity check. The browser demo runs the integrity and signature checks; the governance and ground-truth tiers are checked by the full verifier.
Step 5: conformance vectors
A verification standard is only worth as much as the agreement between independent verifiers. Provetrail publishes conformance vectors: valid records a conforming verifier must accept, and malformed or tampered ones it must reject, including a broken chain, a bad signature, a non-monotonic sequence, and a record whose carried bytes disagree with their logical content.
A verifier in any language is conformant at a level if and only if it passes that level’s vectors. That is what turns “trust our verifier” into “run yours against the same vectors and see that they agree.” The sample record on the home page is one of these vectors. For what conformance means in full, and which tiers an implementation can reach, see what makes an implementation Provetrail-conformant.
Try it
- Verify in your browser. The home page runs the integrity verifier client-side against a signed vector. It is the
provetrailnpm package, its COSE_Sign1 and Merkle checks, with nothing uploaded. - Verify it yourself. Download the record and run it through your own verifier.
- Read the standard. The spec and reference implementation live in the Provetrail repository.
For why the runtime that dispatches the actions should be the one to emit these records, see signed versus proven. For the definition and how this fits alongside other standards, see what is verifiable execution provenance.