How it works

Verfy sits in the path of every tool call

It runs on the developer's machine, decides locally and quickly, and never waits on the network. The web platform collects evidence; it is never in the critical path.

The tool-call path

Verfy in the tool-call pathThe agent sends a tool call to the Verfy hook or gateway. Verfy checks policy and the lock, writes a signed receipt to the local ledger, and only then lets the call reach the tool. Denied calls stop at Verfy. A separate sync process uploads receipts to Verfy Team.Coding agentClaude Code, Cursor, MCP clientVerfy1. policy check (allow · ask · deny)2. verfy.lock digest check3. signed receipt → local ledgerTool / MCP serverruns only if alloweddenied: stops here, receipt still writtenverfy sync (separate process) → Verfy Team

Claude Code hook

verfy hook pre-tool-use receives each call as JSON. Verfy answers deny or ask with the rule and reason, or stays silent so Claude Code's own permissions decide. It never answers allow on its own.

MCP gateway

verfy proxy wraps a stdio MCP server: it scans tools/list, hides poisoned or drifted tools, checks every tools/call and can ask the user through MCP elicitation.

Failure modes

Bad input, a broken policy, an unreadable lock or a full disk all become ask (or deny with fail_mode). Verfy never fails open.

Receipts and the hash chain

Receipt hash chainEach receipt stores the SHA-256 of the whole previous receipt in its prev field and is signed with the device key, so changing, removing or reordering any receipt breaks every link after it.receipt #0prev = nullverdict, rules, tool digestsig = Ed25519(device key)receipt #1prev = sha256(#0)verdict, rules, tool digestsig = Ed25519(device key)receipt #2prev = sha256(#1)verdict, rules, tool digestsig = Ed25519(device key)receipt #3prev = sha256(#2)verdict, rules, tool digestsig = Ed25519(device key)

The signature covers the canonical JSON of every field (sorted keys, no whitespace, JavaScript number formatting), so the Python CLI and the TypeScript server produce byte-identical input. The repository ships shared test vectors that both implementations must verify.

Team sync

An admin creates a one-time enrollment code (valid one hour).
verfy team enroll sends the device's public key; the server returns a device token stored only as a hash.
verfy sync uploads receipts in batches of up to 500. The server checks schema, signature, sequence and links, and stores them idempotently.
verfy team pull fetches the team policy and team-approved locks.

Lock drift

First use: Verfy locks the digest of every tool the server lists.
Later, a description changes (for example, a hidden instruction is added).
The tool is hidden and its calls are denied with VFY-TOOL-004.
A person reviews verfy lock diff, then approves locally or proposes the change to the team.

Inside a receipt

One record from the published test vectors. Point at a part to see what it proves.

{  "v": "verfy.receipt/1",  "seq": 1,  "prev": "sha256:5912be441c…",  "issued_at": "2026-10-11T09:00:01.000Z",  "action": {    "tool": "Bash",    "args_sha256": "sha256:73f3292934…"  },  "decision": {    "verdict": "deny",    "rules": ["VFY-SH-001"],    "policy_sha256": "sha256:66ed6885f8…"  },  "kid": "atl_65b60673d6ed884b",  "sig": "ktPSqLCI62CgjCYVZ1mNz…"}
Verfy only sees calls that pass through its hook or gateway. Tools an agent can reach another way, or what a server does internally, are outside what Verfy can check or prove.