Abstract
Software agents increasingly act on behalf of people and organizations: they call tools, move money, and touch private data with little or no human in the loop. Yet the only record of what an agent did is a log its own operator can silently edit, so accountability rests on trusting whoever keeps the record. We propose a transparency log for agent actions. Each agent holds a cryptographic identity and receives scoped, expiring authority from its owner through a signed delegation certificate. Every action becomes an Ed25519-signed, hash-chained receipt that records only a hash of the payload, never the payload itself. Receipts are appended to a Merkle transparency log in the manner of Certificate Transparency; the log periodically signs a compact commitment to its entire history and writes that commitment to a public blockchain, so not even the log operator can rewrite the past. Anyone can then verify, offline and without trusting any party, what an agent did, under whose authority, and that the record was neither altered nor reordered. We call this primitive proof-of-action.
The protocol described here is not a design sketch. It ships as a reference
implementation with byte-for-byte cross-language parity: @zanii/core and
@zanii/sdk on npm, and zanii on PyPI, sign and verify identical objects, so a
receipt built in one language verifies in the other. Sections 3 to 17 specify the
protocol; sections 18 to 20 describe the software surface that makes it usable — how
an agent is instrumented in a line, how a verifier checks a proof with no network,
and how a compliance team reads an audit bundle against the obligations they carry.
1. Introduction
Bitcoin showed that a ledger can be trustworthy without a trusted keeper [1], and Ethereum generalized that ledger into a platform for arbitrary state [2]. Both solve a problem about value: who owns what, and who may move it. The rise of autonomous software agents raises a different problem, about behavior: an agent invokes a payment API, sends an email as you, or reads a customer record, and afterward the only evidence is an application log. That log is mutable by the very party who would be blamed if the action were improper. When an auditor, a counterparty, or a court later asks "what did your agent actually do, and who authorized it?", the answer "trust our database" is not an answer.
The observation of this paper is that the machinery built to make the web's certificate authorities accountable, Certificate Transparency [3], solves exactly this shape of problem, and can be pointed at agent actions instead of certificates. A certificate authority can, in principle, issue a fraudulent certificate; CT makes every issued certificate appear in a public, append-only, cryptographically verifiable log, so misissuance is detectable. An agent operator can, in principle, misreport what its agents did; a transparency log of signed agent actions, anchored to a public blockchain, makes misreporting detectable in the same way.
We combine three well-understood components, none of them novel in isolation: digital signatures and scoped delegation for authority, a Merkle transparency log for tamper-evident ordering, and periodic on-chain anchoring for global immutability. The contribution is their composition into a single primitive for agent accountability, and a protocol precise enough that a receipt can be verified by anyone, with no call back to us.
2. Design goals
- No trusted operator. Verification must never require trusting Zanii, the log, or the agent's operator. The math is the trust.
- Offline-verifiable. A receipt plus a small proof must be checkable with no network access and no registry lookups.
- Payload-private. The log records only a hash of an action's payload; the underlying data never leaves the operator's systems.
- Least authority, provable. An agent must never be able to act beyond what its owner delegated, and that boundary must be checkable.
- Cheap and portable. Anchoring must cost a fraction of a cent, and an agent's entire history must export as one self-contained, independently verifiable file.
3. Identity
Every participant, owner, delegating team, agent, and the log itself, is an Ed25519
keypair. An identity is expressed as a did:key decentralized identifier:
did:key:z<base58btc(0xed 0x01 || publicKey32)>
The defining property is that the identifier is the public key: to verify a signature you decode the key directly from the DID, with no registry, no lookup, and no certificate authority. All hashing in the protocol is SHA-256, and all signatures are Ed25519, each computed over the RFC 8785 JSON Canonicalization Scheme (JCS) [4] form of the relevant object, UTF-8 encoded. Canonicalization matters: it guarantees that two systems serialize the same logical object to the same bytes, so a signature made by one verifies byte-for-byte on another.
4. Delegation
Money needs no notion of agency, you own a coin and you spend it. Agents do: an agent acts for a principal, and must not exceed what that principal allowed. Zanii represents authority as a delegation certificate, signed by the issuer over the JCS of the certificate without its signature:
{
"v": 1,
"issuer": "did:key:z6Mk…",
"subject": "did:key:z6Mk…",
"scopes": ["stripe.*", "gmail.send"],
"exp": "2026-08-01T00:00:00.000Z",
"sig": "ed25519:…"
}
A scope is an exact string (gmail.send) or a wildcard prefix (stripe.*,
where a.* covers a, a.b, and a.b.c). Certificates compose into a delegation
chain, root first, e.g. organization → team → agent. A chain is valid for agent
A at time t against an expected owner O if and only if:
- every certificate's signature verifies against its
issuerkey; chain[0].issuer = O(when the verifier pins an owner);chain[i+1].issuer = chain[i].subjectfor all links;chain[last].subject = A;- every certificate satisfies
t < exp; - no certificate's hash is in the verifier's revocation set (§10).
The chain's effective scopes are the last certificate's scopes, intersected with every ancestor's, so a delegate can only narrow authority, never widen it. The result is a provable permission slip that travels with every action and always resolves back to a human principal.
5. Action receipts
The atomic unit is the receipt: one signed record per action. It is analogous to a Bitcoin transaction, but instead of transferring value it attests behavior.
{
"v": 1,
"agent_id": "did:key:z6Mk…",
"delegation": [ /* cert chain, root first */ ],
"action": "tool_call",
"target": "stripe.charges.create",
"payload_hash": "sha256:…",
"ts": "2026-07-02T16:00:00.000Z",
"prev": "sha256:… | null",
"sig": "ed25519:…"
}
The signature is Ed25519 by the agent's own key (the key inside agent_id) over the
JCS of the receipt without sig. Two design choices carry most of the weight.
First, payload_hash is a hash of the action's data, never the data, so the log and
its proofs leak nothing: the email body, the customer record, the amount, all stay
with the operator, while the receipt still binds to that exact payload. By default
the commitment is salted — payload_hash = sha256(nonce ‖ payload) with a fresh
per-receipt 16-byte nonce kept operator-side — because a bare hash of a low-entropy
payload ("phone X, amount 500") is dictionary-attackable from the public anchored
log and may itself be personal data; the operator reveals (payload, nonce) to prove
a payload later. A deterministic bare sha256(payload) remains an explicit opt-out
for content-addressing. Second, prev is the hash of the agent's previous receipt
(or null for the first), forming a per-agent hash chain: removing, reordering, or
altering any receipt breaks the linkage of every receipt after it.
Three optional fields, present only when set and covered by the signature, carry
provenance without changing the schema: runtime_hash (the deployed runtime image),
model_id, and manifest_hash (the hash of the tool/scope rulebook that governed
the action — receipted per deploy and stamped on each action, so any receipt answers
"which compliance rulebook governed this"). A further optional subject_tag field
scopes a receipt to the data subject or physical item it was about (§13).
6. Receipt verification
A receipt R verifies at time t if and only if:
R.sigverifies against the public key insideR.agent_id;R.delegationis a valid chain forR.agent_idatR.ts(§4);R.targetis covered by the chain's effective scopes;- in a sequence,
R.prevequals the hash of the preceding receipt.
This check is pure: no network, no trusted party, no clock beyond the timestamps in the objects themselves. It establishes that a specific, authorized agent attested a specific action. What it does not yet establish is that the receipt is part of an immutable, ordered history; that is the job of the log.
7. The transparency log
Receipts are appended to an append-only Merkle tree, following the construction
of Certificate Transparency (RFC 6962 [3], RFC 9162 [5]). The Merkle Tree Hash (MTH)
of a list of leaves D is defined with explicit domain separation between leaves and
interior nodes:
MTH({}) = SHA-256()
MTH({d(0)}) = SHA-256(0x00 || d(0))
MTH(D[n]) = SHA-256(0x01 || MTH(D[0:k]) || MTH(D[k:n])), n > 1
where a leaf's data is the JCS bytes of the full receipt (including its signature),
and k is the largest power of two strictly less than n. The 0x00 prefix on
leaves and 0x01 on nodes is not decorative: it gives second-preimage resistance,
preventing an attacker from passing an interior node off as a leaf or vice versa.
Periodically the log publishes a Signed Tree Head (STH), a compact, signed commitment to its entire history at a given size:
{ "v": 1, "log_id": "did:key:z6Mk…", "size": 12345,
"root": "sha256:…", "ts": "…", "sig": "ed25519:…" }
The STH's signature is Ed25519 by the log's key over the JCS of the STH without
sig; the log's identity is itself a did:key. The root is a single 32-byte hash
that fixes the exact content and order of every receipt in the tree: change one bit
of one receipt and the root changes.
8. Inclusion and consistency proofs
The Merkle structure buys two proofs, each logarithmic in the size of the log.
An inclusion proof for a receipt at leaf index i in a tree of size n is the
audit path: the O(log n) sibling hashes along the path from that leaf to the
root. A verifier recomputes candidate roots by folding the leaf hash with each
sibling and checks that the result equals the root in a signed STH. For a log of one
million receipts, that is roughly twenty hashes, not a million. This is how a
receipt is proven to be in the log without downloading the log.
A consistency proof between an earlier size m and a later size n is a set of
at most ⌈log2 n⌉ + 1 hashes demonstrating that the size-n tree is an append-only
extension of the size-m tree, that the earlier history was preserved intact and
only grew. Together, inclusion and consistency proofs make deletion and reordering
mathematically detectable: any such tampering yields a root that no longer matches
the signed, and later anchored, tree head.
A receipt is fully proven when it verifies per §6, its leaf has a valid inclusion proof against an STH, and that STH's signature verifies against the log's DID.
9. On-chain anchoring
Signatures make the log's claims attributable, but not singular. A dishonest log could sign two different histories and show each to a different party, a "split-view" attack, since it holds the key and can sign both. To remove this, the log periodically writes its current STH outside its own control, onto a public blockchain.
An anchor is an EIP-1559 transaction on a public EVM chain (Base / Base Sepolia
in the reference deployment) whose calldata is the JCS bytes of the STH; the anchor
record stores the transaction hash and block number as its reference. Once anchored,
the root is a single value visible to everyone on a ledger the log does not control,
and changing it would require rewriting the blockchain itself. A receipt at leaf
index i is anchored once any anchor exists with size > i; consistency proofs
then tie every later tree back to the anchored one. Third-party verification is
direct: fetch the transaction's calldata from the chain, decode the STH, verify its
signature, and demand an inclusion proof against it.
This is the same defense Bitcoin uses, made cheap. Bitcoin makes history expensive to rewrite through proof-of-work; Zanii does not run a chain of its own, it rents an existing chain's immutability by committing a 32-byte root for a fraction of a cent per anchor. An "average" verifier need not understand any of this: they open the anchor transaction on a public block explorer, a site the operator does not run, and see the log's fingerprint recorded there, permanently, at a known time.
Deployment note. The protocol is chain-agnostic; any public EVM chain suffices, with a mainnet the production target so that rewriting history carries real economic cost. A
filebackend (a local append-only file) exists for development and is explicitly not tamper-proof. Anchoring to a chain Zanii itself operates would be circular, so the trust claim rides a chain we do not control.
10. Revocation
Authority must be withdrawable, and the time of withdrawal must itself be provable. A revocation record embeds the full delegation certificate being revoked and is signed by that certificate's issuer, the only party that could have granted the authority in the first place:
{ "v": 1, "type": "revocation", "cert": { /* full cert */ },
"ts": "…", "sig": "ed25519:…" }
The log appends valid revocation records as their own Merkle leaves and adds the
certificate's hash to its revoked set. Thereafter any delegation chain containing the
revoked certificate is invalid (§4, rule 6): the log rejects new receipts under it,
and verification of existing ones flags it. Key rotation is not a separate mechanism
but a composition: issue a new certificate to the new key, then revoke the old one.
In the reference implementation an issuer produces a revocation with createRevocation
and any party checks one offline with verifyRevocation — a valid record is one whose
embedded certificate signature verifies and whose own signature verifies against that
certificate's issuer. Revocation is never performed server-side, because the server
must never hold an issuer's key.
11. Cross-organization receipts
When an agent of organization X interacts with an agent of organization Y, neither
organization's word should be the record. An A2A receipt is a single statement
signed by both parties over an identical signing base (the receipt with both
signature fields removed), so the two signatures are order-independent and neither
countersigns the other. The receipt's hash enters both agents' hash chains, and the
log advances both heads atomically on ingest (POST /v1/interactions). The result is
one neutral proof of a bilateral interaction that both sides, and any third party, can
verify with verifyA2AReceipt, offline. The construction is aligned with the emerging
ERC-8004 model for trustless agent identity [6], so a Zanii did:key and an ERC-8004
identity denote the same agent. For teams of three or more agents, a swarm receipt
generalizes this to a genuine M-of-N Ed25519 threshold over a shared body, with
distinct-owner segregation enforced by default.
12. Reputation and payments
Reputation in Zanii is evidence, not assertion. A reputation view over an agent
reports only its verifiable history, receipt count, activity span, cross-party
interaction count, distinct counterparties, revocation status, and anchored
coverage, and every figure resolves to receipts anyone can re-verify from the agent's
exported audit bundle. Where a numeric rating is wanted, it is posted through the
standard ERC-8004 reputation registry with a link back to that verifiable bundle, so
the score is backed by history rather than claimed. A portable, signed AgentCV
(@zanii/cv) carries this same distinction to a reader: its summary is the log's
un-inflatable aggregate, while curated entries each point at a verifiable receipt or
certificate hash — a CV proves its entries are real, and warns when they are
incomplete.
Payments are a convention, not a rail: a receipt with action: "payment" and a
target such as payment.x402 or payment.ap2, whose payload carries the payment
rail's own settlement reference. Zanii proves who initiated and received a payment;
the rail settles the money. This lets agent-to-agent commerce inherit the same
tamper-evident, anchored accountability as every other action.
13. Data custody
Sections 3 to 12 answer what an agent did. They are silent on what happened to the data it touched, and that is the question a person asks before letting an agent near their bank statement.
A custody record is not a new object. It is an action receipt carrying an additional
subject block, on the same per-agent chain, in the same Merkle batch, under the
same anchor. Because the receipt's target is data.<class>.<op>, the ledger's
existing scope check enforces purpose: a read-scoped certificate physically cannot
record an export.
"subject": {
"ref": "hmac:v1:…", /* which object, keyed per tenant */
"class": "pii.financial",
"op": "read | export | transform | share | store | delete",
"before": "sha256:…", /* content hash entering the touch */
"after": "sha256:…", /* content hash leaving it */
"n": 1,
"dst": "…" /* required when op = export */
}
ref is keyed and deterministic, so touches of one object are linkable inside a
tenant and opaque across tenants. This is deliberately unlike payload_hash, which
is salted precisely so that it is not linkable.
The before/after pair forms a second hash chain, per data object, running
sideways to the per-agent chain of §5. It yields a property the per-agent chain
cannot give: if a record left an object at X and the next recorded touch reports
before = Y, something modified that object outside every observed path. The gap
is detectable although nothing witnessed the write.
That detection is only meaningful once anchored. Absence of a record proves nothing while the operator can delete a record and re-sign the chain; once the tree head is public (§9), deletion changes the root and becomes visible. Anchoring is what converts absence into evidence.
Three composable primitives extend custody into the data-sovereignty questions
regulators ask, each a client-side receipt builder and verifier over the existing
receipt path, with no server change: residency (@zanii/residency) binds an
injected region attestation to each touch and confirms it stayed inside a declared
jurisdiction, with detectCrossings finding exit/return border events;
subprocessor (@zanii/subprocessor) records the onward-transfer graph and flags
any transfer to a party not on the declared list as a provable Art. 28 violation; and
minimization (@zanii/minimization) commits the declared minimum field set and
proves accessed ⊆ declared, catching a set widened after the fact. Each states its
limit plainly: they prove recorded touches, transfers, and accesses, not that no
off-record copy was taken — which needs an attested enclave (@zanii/attest).
14. Subject-scoped auditability
The verifier of a custody record is not primarily an auditor. It is the person the data is about.
A subject holds their own Ed25519 identity. Their view is addressed by a
platform-scoped pseudonymous tag derived from their DID and the platform identifier,
so one person carries a different tag at each platform and two operators holding
both datasets cannot correlate them. The reference implementation is @zanii/subject:
subjectTag(subjectDid, platformId) computes the tag identically in TypeScript and
Python, and fetchSubjectHistory pulls the subject's slice from
GET /v1/subjects/{tag} and offline-verifies every receipt — signature, delegation,
tag match — treating a server-truncated slice as a failure rather than computing a
confident green over a partial history.
The subject fetches their slice and verifies it offline: signature, delegation chain, scope, object-chain continuity, Merkle inclusion, signed tree head, anchor. No account with the operator is required for any step after the first, and the operator cannot substitute a different history without breaking the anchored root.
This inverts the usual arrangement. Conventional audit logs are actor-scoped because the buyer is the enterprise. Scoping the record to the subject lets one record serve three readers — the subject, the deploying business, and a third party receiving a derived output — without forking the format.
15. Proving a negative
The valuable claims about personal data are negative ones, and a log alone cannot
carry them. Each requires a distinct mechanism, and each fails to a stated limit.
The reference implementation collapses these into one verifier
(@zanii/custody-verdicts, called by both the subject page and zanii audit), which
computes five verdict rows from an offline-verified slice in four first-class states —
proven, not covered, failed, cannot determine — where a missing proof is
never rendered as a clean result.
"No human read it." Every access emits a receipt, but that only covers observed paths. The claim additionally requires evidence that no human-usable path to the data exists, and a hardware attestation binding the executing code image to each receipt. Absent either, the honest rendering is not covered.
"It was never used to train a model." The training set is committed to a
sorted-Merkle manifest (@zanii/train) whose root is anchored before the run
executes; the subject then receives an offline non-membership proof for their ref.
Ordering is the claim: a manifest anchored afterwards could have been written to
exclude them, so a manifest anchor later than the run attestation renders cannot
determine.
"No copy was kept." Each object is encrypted under its own key; deletion
destroys the key and the key store signs the destruction (@zanii/retention
crypto-shredding, verified by verifyKeyDestruction). Key destruction is provable —
the verifier even catches a lie, failing if the caller can still produce bytes
matching the commitment. Byte deletion is not, and no system should claim otherwise.
Three properties govern how these are presented. Verdicts are computed at read time from the evidence, never persisted as fields, since a stored boolean is an assertion wearing the costume of a proof. Every verdict carries the four states, and the three non-proven states are rendered as prominently as the first, because an unqualified clean result is the most damaging output such a system can produce. And no deployment should claim that data is safe: safety is a prediction about the future. The provable statement is narrower and stronger — a breach cannot be concealed.
16. Security analysis
We consider four adversaries: a malicious agent, a malicious operator (including us), a network attacker, and a colluding log.
Forging a receipt. To produce a receipt that verifies as some agent A, an
adversary must produce a valid Ed25519 signature under A's key. Ed25519 provides
roughly 128-bit security, so absent the private key the probability of forging a
single signature is on the order of 2^-128 ≈ 3 × 10^-39. Delegation bounds the
blast radius of a stolen key: a compromised agent can still act only within its
unexpired, unrevoked scopes, and revocation plus short expiries cap the exposure
window.
Altering logged history. Changing, deleting, or reordering any receipt changes
the leaf or node hashes above it and therefore the Merkle root. Because the root is
signed by the log (forging that signature is again ~2^-128) and, once anchored,
fixed on a public chain, undetected tampering of anchored history reduces to rewriting
the blockchain, whose cost is the chain's own security budget.
Split view. A colluding log could sign two histories, but the moment either is
checked against the single on-chain anchor, the fork is exposed: at most one root can
match the anchored value. Continuous auditors — the independent watchdog @zanii/monitor
fetches each new STH and demands a consistency proof to the last — shrink the detection
window to the anchoring interval, and @zanii/federation turns two validly signed STHs
of the same size with different roots into a self-contained, offline equivocation proof.
Thus the log's remaining power is limited to delaying an entry or withholding a
proof, both of which are visible as a failure to produce a valid proof, never to
silently rewrite the past.
Privacy of the analysis. None of the above requires exposing payloads, because verification operates entirely on hashes, signatures, and proofs.
17. Privacy
The log stores, per action, only payload_hash, the action's target, timestamps,
identities, and signatures. The action's data never leaves the operator, yet the
receipt still binds to it: to later prove what happened, the operator discloses the
payload and anyone recomputes its hash and matches it against the anchored receipt.
Payload commitments are salted by default (§5), so a low-entropy payload cannot be
recovered from the public log by dictionary attack. Identities are did:key public
keys, which are pseudonymous unless independently linked to a real-world entity.
Selective disclosure is natural: an audit bundle can be scoped to a single agent, and
individual payload fields revealed with per-field inclusion proofs (@zanii/redact,
the sd-v1 convention) so a cross-org auditor verifies the one field that matters
without seeing the rest.
18. The reference implementation
The protocol ships as two parallel libraries with locked cross-language parity:
@zanii/* on npm and zanii on PyPI. A receipt, certificate, STH, or bundle
produced by one verifies byte-for-byte under the other, because both sign and hash
over the same RFC 8785 canonical bytes.
The core four. @zanii/core (zanii.core) is the protocol as pure functions with
no I/O: identity, delegation, receipts, the Merkle log, inclusion and consistency
proofs, signed tree heads, and self-contained audit-bundle verification.
@zanii/sdk (zanii) is the client — ZaniiAgent with record, wrapTool, and a
batched flush — and re-exports the full verification surface so one install can both
build and verify. @zanii/runtime (zanii.runtime) is the deterministic agent rails:
the model proposes and tested code disposes, status is earned from a tool's result
(no external receipt ⇒ attempted, never sent), and irreversible actions pause at a
human confirmation gate bound to the exact action hash. @zanii/mcp-proxy
(zanii.mcp_proxy) fronts any MCP server so every tool call is receipted with no
change to the agent or the upstream server.
One-line instrumentation. @zanii/ai wraps a whole tool set —
withZanii(tools, { agent }) receipts every tool's execute (Vercel AI SDK shape,
framework-agnostic structural typing). Framework adapters do the same inside an
existing runtime: @zanii/langchain (a callback handler), @zanii/openai-agents
(lifecycle run hooks), zanii.crewai (a step callback), and @zanii/gateway /
@zanii/otel for transparent HTTP proxying and OpenTelemetry spans.
Verification for humans and systems. @zanii/react ships drop-in components —
VerifiedBadge, ProofViewer, AgentProfile, LedgerTicker — that verify
client-side in the browser, so a "Verified by Zanii" badge is not a claim the site
makes but a proof the visitor's own machine checks. @zanii/webhooks verifies the
X-Zanii-Signature header (HMAC-SHA256, timing-safe) and dispatches typed
receipt.recorded / receipt.rejected events. @zanii/testing is an in-memory ledger
with real Merkle proofs, so tests verify against it exactly as against production.
@zanii/monitor (zanii.monitor, plus a zanii-monitor CLI) is an independent
watchdog: it verifies STH signatures, proves the log is append-only via consistency
proofs, and checks that anchored checkpoints hold — the piece that makes "no trusted
operator" operational rather than aspirational.
19. Offline verification surface
The design goal that verification never calls back to us is enforced by making the
entire check a set of pure functions, re-exported from @zanii/sdk (and available at
the top level of zanii):
verifyReceipt— signature, delegation chain, scope for one receipt (§6).verifyChain— the per-agentprevlinkage across a sequence.verifyCertSignature— a single delegation certificate against its issuer.verifyRevocation— a revocation record and its embedded certificate (§10).verifySTH— a signed tree head against the log's DID (§7).verifyInclusion— a leaf's audit path against a root (§8).verifyConsistency— that a later tree extends an earlier one (§8).verifyA2AReceipt— a cross-org co-signed receipt (§11).verifyAuditBundle— a complete self-contained export, offline, in one call (§20).
Two supporting helpers close the payload loop: saltedPayloadHash produces the
default salted commitment, and verifyPayload reproves a disclosed (payload, nonce)
against a recorded hash. None of these touch the network, read a clock the caller did
not supply, or throw on malformed input — a bad object yields an honest negative
result with a reason, never a crash.
20. Audit bundles and compliance
GET /v1/export/:agentDid produces a self-contained, offline-verifiable bundle of one
agent's complete history: the STH at export time, every receipt with its inclusion
proof, every revocation record, and every anchor with a consistency proof to the
bundle STH. verifyAuditBundle() checks the whole thing offline — the STH signature,
each receipt's signature/delegation/scope and inclusion, the unbroken prev chain
from null, each revocation, and that the bundle tree is an append-only extension of
everything anchored. Verification depends on none of Zanii's continued existence.
A bundle is the artifact a compliance team hands an auditor. @zanii/compliance
(zanii.compliance) wraps the verifier and renders an auditor-ready report: offline
verification status, an action breakdown mapped to the team's own controls, on-chain
anchoring coverage, and flags. The mapping below is an engineering mapping, not
legal advice — a starting point for counsel, not a claim of certification.
- EU AI Act, Art. 12 (record-keeping). The receipt stream is the required event log; each event carries a timestamp, acting identity, action target, and payload hash, and the hash chain plus inclusion proofs demonstrate it was not altered after the fact. Art. 19 / 26 retention is satisfied by the deployer holding self-contained bundle files on their own storage; Art. 14 human-oversight evidence is the delegation chain — which human or org authorized the agent, with what scope, and when revoked.
- GDPR. Receipts carry payload hashes, not payloads, so the ledger stores no tool-call
personal data; erasure applies to the operator's systems of record, and
@zanii/retentionemits an Art. 17 deletion attestation referencing the subject by a salted commitment. The custody suite (§13) evidences Art. 5(1)(c) minimization and Art. 28 subprocessor control. - SOC 2 / ISO 27001. Bundles are tamper-evident audit-trail evidence for change-management and logging controls (CC7.x), and the offline verifier gives auditors independent validation in place of screenshots.
- UAE (Zanii is a Dubai company). Salted hash-only payloads address PDPL (Decree-Law
45/2021); Ed25519-signed, hash-chained, anchored receipts are the tamper-evident electronic
record the Electronic Transactions & Trust Services law (46/2021) recognises, the basis for
treating a Zanii proof as admissible evidence — for which
@zanii/admissibilityrenders a bilingual Arabic/English evidence pack. Per-product walls (@zanii/walls) turn each product's permitted conduct into a scope the delegation never grants plus a gate on the risky action, so the compliance rulebook is the tool manifest and every receipt carries themanifest_hashthat governed it.
The claim discipline is deliberate: a product is "provably wall-abiding," never flatly "compliant." Compliance is stacked layers — counsel-validated walls, walls proven never crossed, lawful behaviour inside them, and audit-ready paperwork — and each is claimed by name. What the ledger proves is the second and third: that every action stayed in scope, and which rulebook governed it.
21. Related work
Certificate Transparency [3, 5] pioneered append-only Merkle logs with public
auditing for TLS certificates; Zanii adopts its tree construction and proof
algorithms and applies them to agent actions, adding identity, scoped delegation, and
on-chain anchoring. Sigstore/Rekor [7] applies transparency logging to software
artifacts. The Ethereum Attestation Service provides on-chain attestations but
places data on-chain; Zanii keeps payloads off-chain and anchors only a root.
ERC-8004 [6] defines trustless-agent identity and reputation registries, with
which Zanii's identities and reputation feedback align. The W3C Verifiable
Credentials 2.0 Data Integrity suite eddsa-jcs-2022 is, by construction, exactly
Zanii's did:key + Ed25519-over-JCS signature, so a Zanii credential bridges to a
spec-conformant VC a standards wallet verifies with no Zanii code (@zanii/vc).
Foundational to all of these are Merkle's hash trees [8] and the Bitcoin [1] and
Ethereum [2] ledgers, whose core insight, a record made trustworthy by structure
rather than by a trusted keeper, this work carries into agent behavior.
22. Conclusion
We have described proof-of-action: a way to make what AI agents do provable to anyone, without trusting the parties involved. An agent's authority is a signed, scoped, expiring delegation that resolves to a human principal; each action is a signed, hash-chained receipt that reveals only a hash of its data; receipts live in an append-only Merkle log whose signed head is anchored to a public blockchain; and every claim, who did what, under whose authority, in what order, unaltered, is checkable offline by anyone. None of the parts are new. Their composition gives AI agents something they have lacked and increasingly need: a record they cannot fake, and that no one has to be trusted to keep. In v2 that composition is no longer only a protocol — it is a set of libraries an operator can adopt in a line, a verifier any third party runs with no network, and an audit bundle a compliance team reads against the obligations it already carries.
References
[1] S. Nakamoto. Bitcoin: A Peer-to-Peer Electronic Cash System. 2008. [2] V. Buterin. Ethereum: A Next-Generation Smart Contract and Decentralized Application Platform. 2014. [3] B. Laurie, A. Langley, E. Kasper. Certificate Transparency. RFC 6962, 2013. [4] A. Rundgren, B. Jordan, S. Erdtman. JSON Canonicalization Scheme (JCS). RFC 8785, 2020. [5] B. Laurie, E. Messeri, R. Stradling. Certificate Transparency Version 2.0. RFC 9162, 2021. [6] ERC-8004: Trustless Agents. Ethereum ERC draft, 2025. [7] Sigstore. Rekor: Software Supply Chain Transparency Log. 2021. [8] R. C. Merkle. Protocols for Public Key Cryptosystems. IEEE S&P, 1980.