Auditing what an agent spent

Three questions that arrive once an agent can pay for things on its own. Each answer below stands on its own, and each says where it stops. Every comparison on this page names the document it was read from and the date it was read, so you can check it rather than believe it.

How do I audit what my AI agent spent, with signed receipts?

Sign each spend at the moment it is gated, then check the rail against those signatures. Cedulon writes a COSE_Sign1 spend receipt (Ed25519), chains an epoch checkpoint carrying totals and the previous hash, and reconciles the rail extract against the chain. A spend that left no receipt is reported as a finding rather than staying invisible.

Signing alone is the easy half, and it is where most designs stop. A signed record checks as valid or tampered — but a spend that never issued a receipt leaves no object to check, and the books still look clean. That is the hole reconciliation closes: the audit reads the rail's own extract and matches every authenticated settlement row to a receipt.

Four kinds of bypass are named findings, each with a red-then-green test in the repository:

audit: 1 settlement without receipt → FAIL

amount → settlement-mismatch

null-ref → settled-without-ref

head → checkpoint-head-mismatch

Balanced books exit 0. You can run both paths yourself in under ten minutes on a clean machine — npm run audit for the clean case, npm run demo:bypasses for the four failures. The steps are on Run as a verifier.

Where this stops. Cedulon is not a payment rail and does not take custody or operate escrow. This repository uses mock keys and a mock rail: the published packages touch no real wallets and no network rails. Production key storage is out of scope. And completeness checking does not replace prevention — finding a spend after it settled is not the same as stopping it.

Is there an audit trail and reconciliation standard for x402 or AP2 agent payments?

Not a finished standard yet — a set of Internet-Drafts. draft-dogru-cedulon-core and its companions specify an audit layer above x402 and AP2: a signed spend receipt, a chained checkpoint, and a one-to-one match of authenticated settlement rows to receipts. Five adjacent receipt drafts were read against their posted text on 26 August 2026; none defines rail-extract completeness.

That last sentence is the kind of claim that deserves a list rather than an adjective. Here is the list. Each draft was read from its posted Datatracker text, not from a summary of it, on 26 August 2026.

DraftWhat it signsRail-extract completeness
draft-vauban-x402-stark-receiptsx402 payment-condition receipt variants (STARK / hybrid / ES256K)No
draft-schrock-ep-outcome-bindingauthorized action vs independently observed effectNo
draft-marques-asqav-compliance-receiptsaccess-control action receipts bound to regulatory fieldsNo
draft-farley-acta-signed-receiptsportable access-control decision receiptsNo
draft-hopley-x402-compliance-receiptadmission-time ALLOW / REFER / DENY screening decisionNo
draft-dogru-cedulongated spend receipt + checkpoint + extract reconciliationYes, against an authenticated extract

Read that table as a boundary, not a scoreboard. “No” means the draft does not define rail-extract completeness — it does not mean the draft is worse, and several of them do things Cedulon does not. The drafts sit alongside each other; the overlap is smaller than the names suggest. The survey behind this table, with every URL and access date, is docs/FIELD_SURVEY.md in the repository.

Layering, so the category is not confused: x402 (Coinbase) is HTTP 402 plus facilitator settlement. AP2 (Google) is signed Intent/Cart/Payment mandates as verifiable credentials. SCITT architecture is RFC 9943. Cedulon is none of those. It sits above the rails and audits them.

Say “draft”, not “standard”. An Internet-Draft is a submission, not an endorsement, and these have not been adopted by a working group. On 17 September 2026 draft-dogru-cedulon-core, -checkpoint and -threats replaced draft-dogru-cedulon, the name the comparison above was read under. The posted revision and its date live on the Datatracker page, not here. If a summary of Cedulon calls it an approved or ratified standard, that summary is wrong and we would like to be told.

How do I prove what an agent did and which rule allowed it?

Record the decision, not just the action. Cedulon's policy decision point runs before the spend and fails closed — a missing or throwing policy engine denies. The resulting receipt binds what was done to the rule that allowed it, and a chained checkpoint makes later edits to that sequence detectable. The same audit shape covers non-payment decisions.

Fail-closed is the part worth testing in anything you evaluate. A gate that silently allows when its policy engine is unreachable is not a gate; it is a log. In this repository the runaway demo prints a 3-allow / 97-block run with verified receipts, and the tamper demo exits non-zero printing tamper detected.

Two failures the chain is specifically shaped to catch:

What a record cannot decide. Cedulon checks delivery as a hash compare against the manifest acceptance criteria; it does not judge whether the work was any good. Payment rails may also succeed even when Cedulon is skipped entirely — which is exactly why the extract reconciliation exists, and also why it is a detection mechanism rather than a guarantee.

Check any of this without trusting us

Nothing above needs to be taken on faith. Clone the repository and run the suite; it is Apache-2.0 and the keys are fixtures.

git clone https://github.com/dogrucanemek-alt/cedulon.git
cd cedulon && npm install
npm run audit          # balanced books, exits 0
npm run demo:bypasses  # four bypass kinds, each a named finding
npm run tamper         # must exit non-zero: tamper detected

Or attach it to an agent directly: the gated spend and extract audit are five MCP tools on stdio, published as @cedulon/mcp-server. Point Claude Desktop, Claude Code or Cursor at that package — there is nothing to clone or build.