Tamper-evident receipts for autonomous agents.
jaredklopstein.github.io/provenant ·
@provenant/core ·
@provenant/verifier
Agents write structured receipts of every consequential action they take. Provenant hash-chains and signs them, so anyone can later prove the record was not altered — and see exactly which record was, if one was.
Agents are the users. Humans read this during incidents, audits and security reviews. The write path is designed for agents; the read path for humans.
provenant init --json
provenant record --action refund.issue \
--action-detail '{"customer_id":"c_8812","amount_usd":42.50}' \
--side-effect-class irreversible \
--idempotency-key refund-c_8812-0001 --json
provenant chain verify --jsonFree — Provenant Core (MIT):
- Receipt recording with RFC 8785 canonicalization, SHA-256 chaining, Ed25519 signatures
- Self-registration with trust-on-first-use identity; RFC 9421 HTTP Message Signatures
- Local chain verification that names the exact broken receipt and proves the rest intact
- Derived agent reliability, with unmeasurable rates reported as
nulland a stated reason — never as a flattering0 - Idempotency replay (argument-checked), dry-run on every mutation, cursor pagination, field projection
- A CLI with
--jsonon every command, and a self-describing manifest
Commands: init, keygen, agent register, agent list, record,
chain verify, chain head, receipts query, anchor now, anchor list,
discover. Unknown options are rejected, not ignored — a mistyped flag
could otherwise change what gets recorded — so the documented shorthands
(--agent, --from, --to) are real aliases and every alias is listed in
discover.
Free — provenant-verify (MIT): standalone offline bundle verification,
including full RFC 3161 timestamp checking. Verifying is never paywalled.
Paid — Provenant Cloud: RFC 3161 anchoring against a real timestamp authority, and evidence bundle export (JSON, PDF, HTML).
Partly built, and not to be presented as working — the collector
authenticates correctly (RFC 9421, with replay and body-swap rejection tested)
but POST /receipts is a documented "not implemented"; and invoice computation
is real while nothing has ever called Stripe. Details in
packages/cloud/README.md.
Not built yet: contracts and approvals (Phase 3); leases and fencing tokens (Phase 4); MCP adapter (Phase 5).
# free: record and verify locally
provenant record --action refund.issue --action-detail '{"amount_usd":42}' --json
provenant chain verify --json
# paid: anchor to an authority you don't control, then export evidence
provenant-cloud anchor now --backend tsa --json
provenant-cloud bundle export --format both --out evidence.json --json
# anyone, offline, with no Provenant server and no commercial code
npx @provenant/verifier evidence.json --trust digicert-root.pemA self-hosted chain is self-attested. It proves internal consistency. It does
not prove the operator left history alone — an operator with database access
could rewrite everything, including the verification output that says everything
is fine. chain verify says so in its own response, every time.
That gap is the product boundary. External anchoring (paid) commits the chain head to an RFC 3161 timestamp authority the operator does not control, which is what turns a log into evidence. We are not withholding a feature; we are selling the one property a local system physically cannot provide about itself.
How seriously we take this: packages/cloud/test/forgery.test.ts models an
adversary with full database access, the append-only triggers dropped, and the
agents' signing keys. It rebuilds the entire chain — every hash relinked, every
receipt re-signed — and confirms local verification is completely fooled. Then it
confirms the anchored bundle still fails, because the one thing the adversary
cannot forge is the authority's signature. See
ADR 0003.
The local append-only database triggers stop application bugs and accidents, not a determined operator. Do not oversell them.
- This does not make you compliant with anything. Provenant produces tamper-evident records that support logging obligations such as EU AI Act Article 12. It is not a compliance product, we are not lawyers, and this is not legal advice. Compliance claims are legal exposure.
- Do not adopt this on a regulatory timetable alone. A Digital Omnibus proposal to delay parts of the EU AI Act has been under negotiation, and enforcement dates may move. Adopt Provenant because you need to debug and prove what your agents did; treat any compliance benefit as a consequence, not a reason.
- The standard we align with is a draft with no IETF standing.
draft-sharif-agent-audit-trailmay change. We pin the version we implement and document exactly where we diverge (see ADR 0002) — notably we default to Ed25519 where the draft specifies ECDSA P-256, so we claim alignment, not conformance. - Web Bot Auth / RFC 9421 agent identity drafts are individual submissions with no working group adoption. The wire format may shift.
- An anchor does not prove completeness. Truncating the un-anchored tail
leaves a valid chain. Anchor cadence bounds the forgeable window; it does not
eliminate it. The verifier reports
anchored_through_seqand warns about un-anchored receipts rather than letting "anchored: true" imply more than it should.
agent list derives per-agent contract-violation, lease-expiry and
approval-escalation rates. Two design choices worth knowing:
Unmeasurable is null, never 0. Contracts are Phase 3 and leases are
Phase 4, so those rates cannot be computed yet. Reporting 0.0 would render a
flawless compliance record for an agent nobody has ever checked — precisely the
flattering false signal this product exists to prevent. A null carries a
plain-language reason instead.
The numbers describe self-reported conduct. They are derived from receipts the agent chose to write. An agent that silently declines to record its failures will look perfect. Receipts make recorded behaviour tamper-evident; they cannot make unrecorded behaviour visible. Useful for spotting a degrading agent, useless against a deliberately deceptive one — and that caveat ships inside the response, not just here.
| Local chain | Anchored chain | |
|---|---|---|
| Detects casual tampering | yes | yes |
| Detects a full rebuild by the operator | no | yes |
| Detects backdating after the anchor | no | yes |
| Detects truncation of the un-anchored tail | no | no |
That last row is why anchor cadence is a pricing tier rather than a checkbox:
daily anchoring bounds the forgeable window to a day, monthly to a month. The
CLI says so in anchor list output rather than leaving you to work it out.
packages/
core/ MIT. Receipts, chaining, identity, CLI, local verify.
verifier/ MIT. Standalone offline verifier. Zero cloud, zero core.
cloud/ Commercial. Anchoring, bundles, collector, billing.
core must never import cloud. verifier must never import either, and must
not import a network module. This is enforced by
scripts/check-boundaries.mjs as the first CI step, not by convention — see
ADR 0001 for why the verifier's
independence is stricter than it strictly had to be.
- CLI is the reference surface. MCP and HTTP are generated adapters, not the contract. CLI beats MCP on reliability and token cost for developer-shaped workflows.
- One typed action registry. Every capability defined once — name, description, Zod input/output schemas, handler, side-effect class. A test fails the build if the surfaces expose different action sets.
- Descriptions are load-bearing. Each action's description is a structured type with five required fields — what, when, when-not, cost, returns — so an incomplete description is a compile error, and a stub one is a test failure.
- Every error teaches its own fix. Errors carry a
fixblock with ready-to-execute arguments and state whether the action executed. - Every success states what's legal next.
next_actionscarries fully-formed calls with ids filled in, not endpoint names. - Token-budgeted by default. Cursor pagination,
--fields,--depth, explicittruncated. - Idempotency and dry-run on every mutation. A replay returns the original receipt. A dry run returns the exact receipt that would be written, applying nothing.
Everything needed to operate this service is in one unauthenticated call:
provenant discover --jsonIt returns the full action list with input/output JSON Schemas, the error code
table with fix shapes, pagination conventions, and a literal ordered quickstart
from nothing to a first verified receipt. If an agent needs this README, the
manifest is incomplete — that is a bug in the manifest.
Reference clients: TypeScript · Python
pnpm install
pnpm run ci # boundaries, typecheck, testsTest-first is mandatory for anything touching the hash chain, fencing tokens, idempotency or signature verification. Those are the only places correctness genuinely matters, and the places where a bug destroys the product's credibility.
core and verifier are MIT. cloud is commercial — see
packages/cloud/LICENSE.commercial.