Missing evidence is itself evidence.
Agents can already pay on open rails such as x402 and AP2. Cedulon sits above those rails as an audit layer: a signed spend receipt, a chained epoch checkpoint, and a reconciliation of the rail extract. If a spend left no receipt, the gap is the finding. Bookkeeping moved from single-entry records to Pacioli's double-entry; Cedulon is the later step where an external rail extract is machine-checkable.
A signed spend record checks as valid or tampered. That is the easy half.
A spend that never issued a receipt leaves no object to verify. The books still look clean.
The companion audit compares the rail extract to the receipt chain. A bypass in this repository prints audit: 1 settlement without receipt → FAIL
A spend is one kind of effect. The companion profile applies the same reconciliation to a decision log: a Decision Record is a signed allow, deny or defer over a request hash and a policy hash, and an Effect Extract is what the channel actually carried. The audit pairs the two by reference and by content hash, and publishes the counts that have to close.
Spend audits have no word for it: an aborted receipt and a settlement under its reference read as "settlement without receipt". Here it is a finding with its own name. effect-against-refusal → FAIL
An allow names what it allowed and what kind of thing it is. A row that carries the allowed hash under another class is effect-class-mismatch, not a match.
A frozen leaked-refusal fixture was read by this audit and by a second reader written elsewhere in its own vocabulary; both refused it. The run, its digests and its limits are in the external review log.
import { PolicyEngine } from "@cedulon/core";
import { generateReceiptKeys } from "@cedulon/receipts";
import { gatedSettle } from "@cedulon/x402-adapter";
const engine = new PolicyEngine({
maxAmount: 10n, maxCumulative: 30n, maxPayments: 3, windowMs: 3600000,
});
const keys = generateReceiptKeys();
const result = gatedSettle(engine, {
req: { amount: 1n, currency: "USD", payee: "q", nonce: "n1", nowMs, tool: "spend" },
payer: "p", paymentHeader: "mock",
}, { receiptPrivatePem: keys.privateKeyPem, receiptPublicPem: keys.publicKeyPem }, nowMs);
The same gated spend and extract audit are also five MCP tools on stdio, published on npm as @cedulon/mcp-server. Point Claude Desktop, Claude Code, or Cursor at it; there is nothing to clone or build. Step-by-step: Cedulon in 5 minutes.
{
"mcpServers": {
"cedulon": {
"command": "npx",
"args": ["-y", "@cedulon/mcp-server"]
}
}
}
Cedulon sits above payment rails such as x402 and AP2 as an audit layer. It writes a signed spend receipt, a chained epoch checkpoint, and a reconciliation of the rail extract. If a spend left no receipt, the gap is the finding. The design is specified in IETF Internet-Drafts and published as open source under Apache-2.0.
A signed spend record checks as valid or tampered. That is the easy half. A spend that never issued a receipt leaves no object to verify, and the books can still look clean. The companion audit compares the rail extract to the receipt chain so a missing receipt becomes a finding.
Cedulon does not take custody and does not operate escrow. An optional third-party escrow role may appear in the protocol as an interface. This repository uses mock keys and a mock rail. The published packages do not touch money: no real wallets and no network rails.
The gated spend and extract audit are five MCP tools on stdio, published on npm as @cedulon/mcp-server. Point Claude Desktop, Claude Code, or Cursor at that package. There is nothing to clone or build. A five-minute path is in the repository Quickstart document.
Cedulon does not take custody and does not operate escrow. It does not judge delivery quality beyond a hash compare against the manifest acceptance criteria. Payment rails may succeed even if Cedulon is skipped. Production key storage is out of scope in this repository. Completeness checking does not replace prevention.