
Allowance
A spending limit for AI agents — signed by a human, enforced before payment, and receipted forever.
Demo
About
AI agents can spend money autonomously now. The x402 standard lets an agent hit an API, get told it costs a cent, pay, and carry on — no card, no human. That works beautifully, and it's the problem: x402 answers how money moves, and nothing answers whether it should. An agent reads a poisoned webpage and sends 500 HBAR to an attacker. Or it loops overnight and buys the same call four thousand times. Every one of those payments is correctly signed and correctly settled. The money is just gone. Spending limits do exist — Hedera's Agent Kit ships policies, x402 ships SpendControls — and they solve real problems. But in every case the limit is a setting the agent itself can reach. The thing being restricted holds the restriction. That's not a limit; it's a suggestion. Allowance is the layer that fixes it. A human writes spending rules — per-payment cap, rolling hourly budget, which counterparties are acceptable — and signs them as an EIP-712 message. The agent receives a sealed envelope it can read but cannot rewrite; change a digit and the signature breaks. Before every payment a guard checks the amount, the running spend, and the recipient's on-chain reputation from the ERC-8004 registry. Every decision is written to a Hedera Consensus Service topic — including the refusals. That's the part everyone skips. If your agent is attacked at 3am and the guard holds, a success-only log shows you nothing, and nothing looks exactly like no attack happened. At $0.0001 per message, logging every denial is free, so the trail is complete instead of sampled. In the live demo the allowlist is deliberately empty. The agent pays an account its owner has never approved, because three independent reviewers on-chain rate it 910/1000 — then gets refused on the fourth call when the hourly budget is spent. The run finishes by replaying the topic from a public mirror node and recomputing the spend from scratch: it matches. The audit trail isn't a log kept beside the system; it is the system's memory.
How it's made
TypeScript monorepo, npm workspaces, no build step — tsx runs sources directly. 94 tests, none requiring a network, because the evaluator is a pure function: no I/O, no clock, every fact passed in as an argument. Hedera does settlement, evidence, and reputation. HCS is the reason the project works at all — our claim is a complete audit trail, and on an EVM chain each log line is a gas-costing contract event, so denying a $0.002 payment would cost more than the payment. You'd batch or log off-chain, and the verifiability claim collapses. HCS is a native service at $0.0001/message and 10,000+ TPS, so recording every refusal stops being a cost decision. x402 — we didn't wrap the library. It publishes an async BeforePaymentCreationHook that runs before a payment payload is built and can abort with a reason; that signature is almost exactly our evaluator's, so our guard is an x402 hook. Settlement goes through the Blocky402 facilitator, which co-signs and submits every transfer — which is why our payment requirements advertise their fee-payer account. ERC-8004 answers "should we pay this stranger?" The registries turned out to be deployed on Hedera testnet at the same deterministic CREATE2 addresses used everywhere else, so reputation and settlement share a chain — no cross-chain hop on the payment path. We count distinct clients, not feedback entries: fifty five-star ratings from one address is one endorsement. Three things worth flagging as hard-won. ExactHederaScheme exists three times on different subpaths — /exact/client, /server, /facilitator — and the bare import gives you the client one, which fails on a server with a useless error. Two Hedera SDKs coexist (@hashgraph/sdk for receipts, @hiero-ledger/sdk transitively via x402), and instances can't cross that boundary. And a Hedera transfer can pass execute() and still fail at consensus, so the ALLOW receipt is written in onPaymentResponse after settlement confirms — writing it at authorization time would put a payment on a permanent audit trail that never happened. We also rewrote the reputation layer once. It originally scanned NewFeedback logs, on the belief getSummary() couldn't aggregate without a client list. getClients() returns exactly that list — and Hedera's mirror node caps topic-filtered queries at a 7-day window, so the log approach would have meant ~30 windowed queries per lookup on the payment path. Two eth_calls replaced all of it. The console is a single self-contained HTML file — no framework, no backend — so a judge can double-click it and see live receipts without running an install. Not finished: the owner's key still lives in .env, so "human-authorized" currently means a string on the same machine as the agent — the same weakness we criticise above. LedgerTrustRoot is written against Ledger's Device Management Kit and typechecks against their real packages, but never ran: no physical device, and Ledger's own Ethereum app doesn't build against their own SDK (C_chain_1_14px_bitmap undeclared, reproducing on both Nano targets). Details and the full error are in the README.