Two things run, both self-hosted, both auditable by a stranger in an evening. A DePIN node that signs its own readings on-chain and sells them per request, and a merchant terminal that takes an order in Portuguese and settles in USDC. The reading comes from a keyless public weather API on that host rather than from a physical probe; a Raspberry Pi with a DHT11 is the hardware path, and the on-chain half is identical either way, because what is signed is the value and the device key rather than the enclosure.
Every claim on this page is checkable with one command or one link. Nothing here is a screenshot of something that used to work. Start with the shortest one:
curl -i https://x402.perfpilot.dev/price
A live node answering HTTP/1.1 402 Payment Required with a single-use nonce that
changes on every request. That is the whole machine-commerce claim, in one request, against a
node that is running right now. The node is an Ampere ARM instance on Oracle's free tier;
its signing key was generated there and has never left it.
On Windows that can fail with curl: (35) schannel: … CRYPT_E_REVOCATION_OFFLINE.
The node is fine; Schannel could not reach a certificate-revocation responder and treats that
as fatal for every HTTPS host. Add --ssl-revoke-best-effort, which downgrades an
unreachable responder from fatal to non-fatal and still validates the certificate.
Two minutes fifteen, one take, no slides. Also on YouTube in 4K. Everything it shows is exercisable below without a wallet.
Read at 2026-08-15T19:41Z, and carried as a floor because the ARM node publishes every twenty minutes or so; the second device's count is final. Re-derive both rather than believing this page. It is an unauthenticated call against a public devnet RPC, no key and no account:
python3 scripts/verify-proof.py # stdlib only, no install, no key
Two devices, not one, and that is the DePIN claim rather than a gadget claim. The same on-chain oracle program serves both, each with its own device key, each on its own machine. Neither can sign for the other.
JEtuZk…Vveg
the ARM node. Publishing since 25 July, 1,514+ so far, 0 failed, median gap
20.5 min. Its key was
generated on that box and has never left it, so this workstation cannot forge a reading for
it.3aMsPj…Vx8K
a second device, 778 publishes, 0 failed, over a completed 12.4-day
run ending 2026-08-06. Deterministic publisher, no model in its path. It was laptop-hosted
and it has stopped, which is why the continuity claim below rests on the node alone.
To count either history directly, the underlying call is getSignaturesForAddress on
the feed account.
Zero failures is exact and covers both devices: no transaction has ever errored. Continuity is where they differ. The ARM node's largest gap is 61.5 minutes across the run since 25 July, so "every twenty minutes" is true at the median with one hour-long interruption. The second device was laptop-hosted, so it slept, and its largest gap inside its run was 36 hours. It has since stopped for good, and the command cannot tell you that: it measures gaps between consecutive publishes, so once a feed stops its largest gap freezes at the last value it reached instead of growing to reflect the silence. Re-run it in a month and it still reports 36 hours, with nothing in the number marking the device as gone. Its job was to show the same program accepting signed readings from a second independent device with a second key, and a completed run of 778 publishes at zero failures did that. Continuity rests on the node alone. The command above shows you both anyway, which is the only reason either is worth writing down: a number you can check beats a rounder one you cannot.
An approval prompt is not a boundary. The sentence a human reads before approving was written by the model, so influencing the model influences the description. An attacker needs no key, only an operator who reads one plausible sentence and says yes.
Being key-free is what every careful entry in this space says, and it is a claim about what our own code declines to do, which is only ever as good as our code. The load-bearing difference is where the limit is enforced. Ours is not in the plugin, not in the host, and not in the prompt: it is a deployed, audited on-chain program.
Demonstrated on mainnet, and the program that does the
refusing is not ours. Solana Foundation's audited
Allowances program (De1egAFMk…, on mainnet since June 2026, audited by Cantina) rejected an over-cap transfer with custom error 0x12c, signed by a
freshly generated agent session key. The same key moved a within-cap transfer normally, settling
0.4 USDC. Three mainnet transactions in all, captured as raw bytes in the repo, verifying offline
with no network and no dependencies:
python3 scripts/verify_proof_offline.py
Prompt-inject every layer we wrote and the ceiling is still there, because it was never ours to remove.
The selling side is capped too, which the brief makes mandatory in both directions. The node sells its readings behind an x402 paywall, and a per-payer per-day ceiling is enforced in the gate's own code rather than by the protocol: a payer who drains the cap in many small buys is refused the same as one who tries it in a single large one. The ledger is durable, so restarting the process does not re-open a spent allowance. An earlier version restarted the day on every boot, which is a cap in name only. Check the fix:
curl -s https://x402.perfpilot.dev/health | jq '.ledger'
That paywall has taken real money, and the precise claim is a split one.
Reading the feed and settling the payment are separate concerns on separate RPC endpoints, so the
gate settled a genuine mainnet payment of 1.000000 USDC while serving a reading
from our devnet feed. The settlement is
3gSg3mQE9vA5X9CmFBxGEY2EFSAMXGhaC1HrUDbH8uA3MQhuaVjCdHjb1kshyzTqWKRALa9EQPeKja2Hk2rWcF2f,
finalized on mainnet-beta. The goods stay on devnet because a DeviceFeed account is
owned by our zeroclaw_oracle program, deployed on devnet only, so a mainnet feed is a
program deployment rather than a config flag. The hosted endpoint above runs the devnet default.
The exchange rate is off the model as well. A Brazilian order carries one money-touching number a language model could simply state, with nothing checking it: the rate. It is now fetched in code from Brazil's central bank (BCB PTAX) and refused unless the ECB's published figure agrees within a stated band. Both sources are keyless, and there is no last-known value to fall back on, so an unreachable source stops the quote instead of ageing one. On 2026-08-14 the two sat 0.91% apart, which is the margin a single source would have carried silently.
python3 scripts/rate_crosscheck.py # the corroborated rate, or a refusal
python3 scripts/check-pay-link-rate-agreement.py # the pay path's copy still matches
What this does not close: the order value is still supplied by the caller. An implausible one is refused in code, so "table 4, R$ 0.05" no longer produces a link, but a plausible wrong amount still does. That band is wide on purpose, because this shop has no catalog and a narrow one would refuse legitimate orders. One free parameter of two is gone and the second is narrowed. The shop on the node has not picked either change up yet, so the enforcement is in the repo and the deploy is what remains.
Every layer above is still something the agent composes, and an agent talked into a different
recipient composes a perfectly well-formed link to it. So the checkout page pins the one address
it will ever pay and does not trust the link that opened it. Change a single character of the
recipient and the card is replaced by RECUSADO, the pay button is gone rather
than disabled, and both addresses print in full, because a truncated
C331…iLHJ is exactly what lets a swapped address survive a glance.
python demo/verify-merchant-invariant.py
That harness covers the swapped recipient. Six more cover the rest of the page, each written after a failure we actually hit rather than one we imagined, and each drives the live page:
python demo/verify_wallet_picker.py # the customer can choose a wallet, at no layout cost
python demo/verify_qr_scannable.py # the QR decodes, under two independent decoders
python demo/verify_no_cdn_dependency.py # the pay path loads its code from this origin, never a CDN
python demo/verify_paid_link_refused.py # a reference that already settled is refused, both directions
python demo/verify_pay_path_rpc.py # the desktop path reaches its RPC from a browser
python demo/verify_settlement_poll.py # the page polls for settlement, not only on load
One more covers a different surface. Those checks decode the QR off the page; what a viewer actually scans is a frame of the shipped video, and an h264 encode is precisely what degrades a QR's sharp module boundaries through chroma subsampling and deblocking. A code that decodes off the page can fail off the tape, and only the tape ships:
python demo/verify_qr_in_encoded_cut.py # the pay QR still decodes after the lossy encode
Or exercise it yourself, right now, with no wallet and no funds. These are the live checkout page, opened with three different orders. Nothing is sent by loading any of them.
5.00 and the card shows
0.39, because 0.39 is what the chain recorded. The page reads the chain, not the link.
The control is the point. A page that refused everything would produce an identical screenshot, so the harness drives both directions: the pinned address must stay payable while a one-character variant is refused. It reads the pinned address out of the shipped page rather than restating it, so the two cannot drift, and neutering its tampering makes it exit non-zero instead of quietly passing.
The page localises from navigator.language and renders pt-BR end to
end. The refusal a Brazilian customer actually reads:
"Este link paga um endereço que não é desta loja. Nada foi enviado."
git clone https://github.com/belumume/zeroclaw-solana && cd zeroclaw-solana
python3 scripts/verify-proof.py # 10 static + up to 5 live claims, stdlib only
python3 scripts/verify_proof_offline.py # the custody proofs, no network at all
python3 scripts/certify_publish_tx.py # seven injection shapes, all refused
No install step, no virtualenv, no credentials. The offline verifier refuses to report at all if its own positive control stops passing, so a green result cannot come from a broken checker.
These are not extras bolted on for a demo. Each one exists because a specific claim elsewhere on this page would otherwise rest on our word, and each is exercisable by a stranger.
Where the cap's boundary sits today, on mainnet, with no key and no funds. The captured refusal above proves the program said no once. This finds where it says no today: it reads the remaining allowance off the delegation account and replays the captured message at amounts either side of it. It requires at least one amount to be refused and at least one to be accepted, so a program that had stopped working and a check that had stopped checking both fail it rather than printing a clean result over nothing.
python3 scripts/replay_allowance_probe.py
A second program reads the feed on chain, which is the difference between an oracle and a
memo. Publishing signed bytes proves only that bytes were published. A separate deployed
program, consumer_example, CPI-reads the feed account, checks the owner and gates on
freshness, so the data is consumable by something other than a human squinting at an
explorer. It last read the live ARM feed in transaction
4CRapo3AEFBFLh7Y7byJR9XDYZEa95MEioUQMzUhJVxTB9HaDTRtX2X47pVgxaSu8KNfYsPyugeQ6FjN8hBzi54L.
The sanitizer, in your browser, compiled from the code that ships. Untrusted
on-chain text reaches a model through our plugins, so it is sanitized and labelled first. The page
below is not a JavaScript reimplementation demonstrating the idea. It compiles
solana_core::sanitize itself to wasm, so what you are typing at is the same function
the plugins call. Paste a right-to-left override or a zero-width joiner and watch what the model
would actually receive.
Open the sanitizer microworld — it runs in this browser, no clone and no build. Six presets, and one of them strips zero invisible characters and still labels the input, which is the case a canned demo would not think to include.
sanitizer-microworld/index.html # or open it from a clone, no build step
A fuzzer graded by someone else's decoder. Every other correctness gate here
tests a property we thought to write down. The differential fuzzer seeds from real serialized
transactions, mutates them with correlated perturbations rather than uniform byte flips, and
scores each result against solana-sdk's own deserializer as an external oracle
so it can find disagreement we did not predict. It is deliberately isolated from the
plugin workspace, because that oracle cannot compile to wasm and must never be reachable from the
shipped crates.
-D warnings on host and wasm0x12c refusal, byte-for-byte