Verify a vault yourself
Run the open-source verifier on your own machine, with no keys. See a PASS offline, run it live against a testnet vault and learn why that run fails checks d and h, then verify the testnet demo vault, which passes all nine.
In about ten minutes, with git, Node.js 24 or later, pnpm 10 and no wallet or key, you run the Probarion verifier on your own machine: offline on a committed test fixture and live against a NEAR testnet vault. If you can sign in to the console as a member of a vault, or once an owner makes a vault's proof page public, you also run it on the files that page offers. You read its real output, and you see why a live run on v0.probarion.testnet fails checks d and h today.
Key idea
Don't trust us. Run the verifier.
Verifying signs nothing and sends nothing. The offline run reads one file. The live runs read public NEAR testnet data through an RPC node, with no key.
Build the CLI#
The offline run reads a test fixture of the repository, so you build the CLI from a clone of the public repository. Run these lines one at a time, in bash, zsh or PowerShell:
git clone https://github.com/probarion/probarion
cd probarion
pnpm install
pnpm --filter "{packages/cli}..." buildThe last line builds the CLI together with @probarion/core and @probarion/sdk, the workspace packages it needs. Run every later command from the probarion folder. If you cloned it before, run git pull, pnpm install and the build line again. Install has the requirements and the full build. The CLI is also on npm: in a folder of your own, outside the clone, npx probarion verify with the same options runs a live check. Every command on this page runs in the clone.
Run the verifier#
-
Verify the committed fixture, offline.
--offlinechecks a saved snapshot: a signed ledger and the chain data recorded with it, in one file. The file here isvalid-snapshot.json(opens in a new tab), a test fixture signed with test keys. Its vault,x.vaults.probarion.testnet, is a fixture name, not a deployed vault. The run needs no network.Shell node packages/cli/dist/bin.js verify --offline packages/core/test/fixtures/valid-snapshot.jsonIt exits 0 and prints the report below. The
generatedtime is the moment you run it, so it reads<timestamp>here; every other line is as the CLI prints it.Text Probarion verify: x.vaults.probarion.testnet (testnet) entries 5, anchors 3, generated <timestamp> snapshot taken 2026-11-05T12:00:00.000Z: its chain data is the file's and was not read from the chain again a ledger-signatures PASS 5 entries: each body_hash recomputes from its body and carries a valid signature by the ledger key the chain names for its range (1 ledger key(s) named by the anchors and the vault config); check b also verifies every link and the chain b hash-links PASS 5 entries: every body_hash and link recomputes, chained from the zero link c anchors PASS 3 anchors match the ledger; 0 entries after the last anchored count (5) are not chain-attested d spends-have-decisions PASS 2 on-chain spends, each bound to its own allow or hold decision (same invoice, mandate and amount) e attestations PASS 2 attested decisions pass A1–A7; quote not verified offline (run --online for O1; re-take the snapshot live with --online); A8 not run (the request is not checked against the invoice); rules-only or unattested (reported, not failed): seq 4 f vault-locked PASS no FullAccess key; every access key is the ledger key or a spend-only agent key on the vault; code_hash 9xTTGSkSHPbw2DCumDxoraeR7uL8Pc2ANm5XKjhohnWL is version 1 of the canonical factory vaults.probarion.testnet; it is the code of factory version 1 g intents-keys PASS no intents public keys; predecessor auth enabled h burn-memos PASS 1 burned spend has a matched burn pair: the POA ft_burn memo is WITHDRAW_TO:<destination address> and the vault's intents mt_burn is for the spend amount i factory-version PASS created by vaults.probarion.testnet at version 1 9 passed, 0 failed, 0 unproven RESULT: PASSThe third line says where the chain data came from. Offline, the verifier reads the vault's keys, code hash, spends, anchors and burns from the file, as recorded at 2026-11-05T12:00:00.000Z, and does not ask the chain again. Each row after it is one check, a to i, with its status and what it found.
-
Verify a vault live. With
--vault, the CLI reads the vault's chain state itself and checks it against your ledger file.v0.probarion.testnetis the testnet vault of the 2026-11-01 smoke run.Shell node packages/cli/dist/bin.js verify --network testnet --vault v0.probarion.testnetIt exits 1. Below are the lines recorded from a run on 2026-11-07. The first line is a warning on stderr, and
...marks what the record leaves out: the two header lines, the other five rows that passed, and parts of some details. The chain state can change, so run it yourself.Text warning: the ledger file ./.probarion/ledger.jsonl does not exist: verifying the chain against an empty ledger ... d spends-have-decisions FAIL spend 1 has decision_hash 704b0f18..., which is not a decision in the ledger ... f vault-locked PASS ... code_hash 6tbERLAX... is a recorded reproducible build (KNOWN_VAULT_CODE_HASHES) ... h burn-memos FAIL spend 2: no burn event observed; ... i factory-version SKIP not a factory vault 6 passed, 2 failed, 0 unproven, 1 skipped RESULT: FAILThe warning names
./.probarion/ledger.jsonl, the default ledger path, unlessPROBARION_LEDGER_PATHnames another file.This FAIL is expected today
The smoke run sent its spends with the agent key directly, without the SDK, a model or a ledger. So
v0.probarion.testnethas no ledger key and no anchors, and there is no ledger file to give the verifier. Check d fails because spend 1 names a decision hash that is not in the ledger, which here is empty. Check h fails because the run is given no transaction for the burn of spend 2, the smoke run's payout to Base: there is no ledger entry to record it, and the command names none, so the verifier finds no burn for it. The PASS on check f still shows two facts read live from the chain: the vault has no full-access key, since check f fails on one, and its code hash,6tbERLAXWjaVKbSNzaivRDh7H9kCcjtmV1qGrgz7entR, is a recorded reproducible build, listed incontracts/code-hashes.json(opens in a new tab). That build is older than the current source, which gained aset_ledger_keyfix on 2026-11-03, explained in What works today. The vaults the testnet factory creates run the build with that fix,3cQXYDvfGLRMveCVAHmh1exiuZKDXWqD8cUhqdEs9MF1, recorded in the same file.The repository records the burn transaction of spend 2 in
contracts/deployments/testnet.json(opens in a new tab) assmoke.base_burn_tx. To hand it to the verifier, name it with--burn-tx:Shell node packages/cli/dist/bin.js verify --network testnet --vault v0.probarion.testnet --burn-tx 2=3u4ffrwpiwLoNV6cU72NHLVBAMq729NwLs6ixDLdcvYeFrom the code, check h should then pass, with
1 burned spend has a matched burn pair, while check d still fails, so the run still exits 1 and its counts line should read7 passed, 1 failed, 0 unproven, 1 skipped. No recorded run shows it yet.A live PASS on check d would show that each spend is bound to one decision in the ledger with the same invoice, mandate and amount, which allowed it or held it. It would not show that the decision was right: the verifier does not run the policy again.
To try a live run on a factory vault, point the same command at
smoke-embedded.vaults.probarion.testnet, a vault the testnet factory created at version 1, recorded with no access keys incontracts/deployments/testnet.json(opens in a new tab). From the code, a factory vault with no spends and an empty ledger should pass every check, after the same warning, and end inRESULT: PASS. No recorded run shows it yet, and no file records whether this vault has spends. Its owner can still change it, so your result may differ. Even an empty vault that passes proves only facts about its keys, its code, its intents setting and its factory version (checks f, g and i). Checks a to e and h have nothing to look at. -
Verify the files of a vault's proof page. Each vault registered in the console has a proof page at
/proof/<vault>. Signed in to the console with your wallet as a member of the vault, such as its owner, you can open it now: the page reads "Proof, visible to members only". For anyone else it answers page not found until the vault's owner makes it public: on the vault's Overview tab in the console,/console/<vault>, the owner ticks "Public proof page" in the Settings card and clicks "Save settings". The page then reads "Public proof" for every visitor. Either way it offers the same two files for this verifier, and you can check them in two ways.Under its checks, the page also lists each decision of the vault's ledger, newest first, with its rules and what the contract did, and, for a decision made with model output, what the ledger records the TEE saw and signed with checks A1 to A7 run on that snapshot (the TDX quote is not verified there: that needs
--online); each card has an audit link,#seq-<N>or#spend-<N>, that opens it.After the decisions, Check the TEE now checks the TEE that serves a private model on NEAR AI Cloud right now:
NEARAI_MODEL, the model Payables is set to use, or, when it is unset, the first of the SDK's preferred private models that answers. Your browser draws a random nonce and sends it with no cookie, and nothing you typed or uploaded. The card shows whether the TDX quote's report data binds that nonce and the signing address, checked again in your browser, and the results of O1 (Intel DCAP on the TDX quote) and O2 (NVIDIA NRAS on the GPU evidence), which the server runs with the same verifier and policy as--online. A check that cannot run reads "not run", never a pass: an Intel or NVIDIA outage, which fails--online, reads "not run" here, and so does O2 for a report with no GPU evidence, which--onlineskips. It does not check the decisions above again, and the TEE measurement is not pinned: why (opens in a new tab).First, offline: Download snapshot.json saves
probarion-<vault>-snapshot.json, a snapshot of the vault's ledger and chain data taken when you click or shortly before. Put it in theprobarionfolder and run:Shell node packages/cli/dist/bin.js verify --offline probarion-<vault>-snapshot.jsonThe proof page prints the same command as
npx probarion verify --offline <file>, which runs release 0.1.1 from npm in any folder that holds the file, with no clone.The report prints when the snapshot was taken. If it is the time the page shows after "snapshot taken", it is the very snapshot the page's checks used.
Second, live: the page's ledger link saves
probarion-<vault>-ledger.jsonl, the vault's signed ledger. Download it into theprobarionfolder just before you run the command (replace any earlier copy, and fetch it again if the vault has acted since). This run reads the chain half again instead of trusting the file:Shell node packages/cli/dist/bin.js verify --network testnet --vault <vault> --ledger probarion-<vault>-ledger.jsonlA public vault to try
If you are not a member of any vault, use the testnet demo vault,
demo.vaults.probarion.testnet: its proof page is public, and the proof index opens it. Download its two files there and run the commands above with<vault>set todemo.vaults.probarion.testnet.
Read the result#
verify exits with one of these codes:
| Exit code | Meaning |
|---|---|
| 0 | Every check passes. |
| 1 | A check fails (a fail always wins over unproven), or verify could not run. When it could not run, it prints error: on stderr and no RESULT line. |
| 2 | No check fails, but at least one is unproven. |
| 64 | Usage error: a missing, malformed or conflicting flag, or, with --offline, a snapshot whose vault, network or taken_at is malformed. |
Each row has one of these statuses:
| Status | Meaning |
|---|---|
| PASS | The check found what it needs, and it holds. |
| FAIL | The check found something wrong, and its detail says what. When a ledger entry is to blame, the row ends in [first broken seq N], and the result line reads RESULT: FAIL (first broken seq M), where M is the lowest seq any failing row names. |
| SKIP | The check does not apply. Today only check i skips, for a vault that names no factory (one initialized from its own account, as v0.probarion.testnet was). A vault that names an account other than the Probarion factory of its network fails check i. A skip does not fail the report, and the counts line adds , N skipped. |
| UNPROVEN | The verifier could not look at what the check needs. It is not a pass. Today only check h can be unproven: a payout's burn is in a transaction that verify did not read. |
An UNPROVEN row lists the spends, the reason and what to supply. This example is from the CLI's README:
h burn-memos UNPROVEN 0 of 1 burned spend has a proven burn pair; not proven, so the report is not ok: ...
unproven: spend 2 (approver_tx): supply the burn tx with --burn-tx or --proof
8 passed, 0 failed, 1 unproven
RESULT: UNPROVEN (no check failed; what the UNPROVEN rows name is not proven)| Reason | What happened | What to do |
|---|---|---|
approver_tx | An approver paid out a held spend. Its burn is in the approver's transaction, which your ledger does not record. | Pass --burn-tx or --proof. |
not_recorded | The spend is bound to its decision, but no payment entry names its transaction. | Pass --burn-tx or --proof. |
pre_ledger_no_tx | A spend of the mainnet vault v0.probarion.near from before its ledger, with no transaction supplied. | Pass --burn-tx or --proof. |
tx_unavailable | The transaction could not be read right now: no node gave a definite answer, for example because the archival node was unreachable. | Run it again, or add --archival-rpc. |
In the check e row of step 1, A8 not run is expected: the command passes no invoice text. A8 runs only when invoice texts are supplied: through the SDK's verify({ invoiceTexts }), through runChecks from @probarion/core with invoiceTexts, or, in the CLI built from the repository, with --invoice <file> (repeatable) or --invoices <dir> (every .txt file of the folder), live or with --offline. Release 0.1.1 on npm does not have these two flags, and a build from the repository also reports version 0.1.1 until the next release: probarion verify --help lists --invoices when the build has it. The CLI reads the files on your machine, keys each by the sha256 of its bytes, and uses it for A8 only; a file whose sha256 is no ledger entry's invoice_hash is listed under the rows and does not fail the run. A8 accepts only the standard system prompt unless you add another with --system-prompt <file>, the prompt's exact text: a decision made under an agent's own model.systemPrompt, such as the Canary's persona, fails A8 without it. On 2026-11-12, verify --offline docs/evidence/demo-vault/snapshot-2026-11-12-video.json --invoices docs/evidence/demo-vault, run from the repository, passed A8 on the demo vault's five attested decisions (output (opens in a new tab)).
Checks a to i are the verifier's, run off-chain on your machine. They are not the 14 checks the contract runs on every spend, which Payment checks lists. For what each verifier check proves, and what it leaves to trust, see Verifier checks.
Offline is not live#
Offline, a snapshot is checked against itself
verify --offline takes the chain data from the same file as the ledger. An edit that was not signed again fails. A forged snapshot, with entries signed again and chain data edited to agree with them, passes. Only a live run with --vault reads the chain, so take the snapshot yourself or run live.
The fixture of step 1 shows it. Its own chain data lists the code hash 9xTTGSkSHPbw2DCumDxoraeR7uL8Pc2ANm5XKjhohnWL as version 1 of the factory, marked in the file as a test fixture version, and check f accepts it. The real testnet factory lists 3cQXYDvfGLRMveCVAHmh1exiuZKDXWqD8cUhqdEs9MF1 for version 1. Offline, the verifier takes the file's word for the chain.
To take a snapshot yourself, verify live with --snapshot, then check the saved file offline whenever you like:
node packages/cli/dist/bin.js verify --network testnet --vault v0.probarion.testnet --snapshot my-v0-snapshot.json
node packages/cli/dist/bin.js verify --offline my-v0-snapshot.jsonSECURITY.md (opens in a new tab) lists what verify does not prove yet.
Go further#
--snapshot <file>saves the snapshot that was verified to a new file. It refuses a file that already exists, and the ledger file (exit 64).--jsonprints the report as JSON instead of rows: the vault, the network,ok, the checks, the entry and anchor counts,generated_atand the unproven burns.--onlinealso runs O1 (Intel DCAP on each TDX quote) and O2 (NVIDIA NRAS on each GPU payload) for check e, and looks burns up in FastNEAR's transaction index. It needs the network and the optional dependency@nearai/inference-sdk, which declares Node 24.22.1 or newer. Without it, the report saysonline: O1 and O2 did not run (<reason>)and check e keeps its offline result. O2 checks NVIDIA's freshly issued token with no clock tolerance, so on a computer whose clock is a few seconds behind, check e fails withnot_yet_validand the report addsonline hint:with the fix: sync the clock and run--onlineagain. The hint also goes to stderr as a warning, and with--jsononly there.--burn-tx <spend_id>=<tx hash>[@<signer>]names a transaction that holds a spend's burn, for example an approver'sapprovetransaction. Repeat it for more. verify still reads each transaction, and check h fails when none of them holds the burn.--proof <file>takes the vault's burn transactions from an evidence file in the format ofdocs/mainnet-proof.json, after the--burn-txones.--archival-rpc <urls>sets the archival nodes for burn transactions older than about 2.5 days. It defaults toNEAR_ARCHIVAL_RPC_URLS, else FastNEAR's archival node.--ledger <path>names the ledger file. It defaults toPROBARION_LEDGER_PATH, else.probarion/ledger.jsonl.
--offline refuses --vault, --ledger, --evidence, --burn-tx, --proof, --archival-rpc, --online, --rpc and --network (exit 64). For every flag, run node packages/cli/dist/bin.js verify --help or read the CLI README (opens in a new tab).
Next steps#
- Verifier checks: what each check a to i proves, and what it does not.
- Security model: what Probarion protects, and what is not proven yet.
- Ledger and anchors: the signed ledger a live run checks, and the anchors that pin it on chain.
- Evaluate in 5 minutes: watch the verifier catch a one-field edit, and read the testnet vault on chain.
- Testnet and mainnet: why every vault on this page is on NEAR testnet.
- Install: build the packages to use them in your own code.
Built from 4ab41ca · reviewed
packages/cli/src/commands/verify.ts(opens in a new tab)packages/cli/src/report.ts(opens in a new tab)packages/cli/README.md(opens in a new tab)packages/cli/src/owner-tx.ts(opens in a new tab)packages/core/src/verify.ts(opens in a new tab)packages/core/src/index.ts(opens in a new tab)packages/core/src/types.ts(opens in a new tab)packages/core/src/code-hashes.ts(opens in a new tab)packages/core/test/fixtures/valid-snapshot.json(opens in a new tab)packages/sdk/src/probarion.ts(opens in a new tab)contracts/vault/src/lib.rs(opens in a new tab)apps/web/src/components/proof/ProofView.tsx(opens in a new tab)apps/web/src/lib/proof/view.ts(opens in a new tab)apps/web/src/lib/proof/cli.ts(opens in a new tab)apps/web/src/lib/proof/snapshot-file.ts(opens in a new tab)apps/web/src/lib/proof/ledger-file.ts(opens in a new tab)apps/web/src/lib/site/facts.ts(opens in a new tab)README.md(opens in a new tab)SECURITY.md(opens in a new tab)contracts/deployments/testnet.json(opens in a new tab)contracts/code-hashes.json(opens in a new tab)packages/cli/src/errors.ts(opens in a new tab)packages/sdk/src/snapshot.ts(opens in a new tab)apps/web/src/lib/proof/service.ts(opens in a new tab)apps/web/src/app/proof/[vault]/page.tsx(opens in a new tab)apps/web/src/components/console/SettingsForm.tsx(opens in a new tab)apps/web/src/app/console/[vault]/page.tsx(opens in a new tab)apps/web/src/lib/routes.ts(opens in a new tab)CHANGELOG.md(opens in a new tab)packages/cli/package.json(opens in a new tab)apps/web/src/components/proof/DecisionPanel.tsx(opens in a new tab)apps/web/src/lib/proof/decisions.ts(opens in a new tab)