Skip to content

This repository, under custody ​

agent-custody is built by an AI agent in Claude Code, and every tool call that agent makes here is a receipt. The hook is committed in the repository; the receipts, the signing key, and the log token stay on the maintainer's machine; and the hash of each receipt is committed to our own tenant on the hosted log within seconds of the call. This page is the live evidence, and how to check it yourself.

What is recorded ​

eventwhat happens
before a Bash, Write, Edit, or MCP tool callthe Cedar policy below decides; a refusal is returned to Claude Code as a denial, and a denied receipt is issued
after the callan executed receipt is issued with the tool, its arguments, and its result
after a failed calla failed receipt

Each receipt is signed with the agent's key and its leaf hash is appended to the log at https://log.agent-custody.dev/t/agent-custody/, hash-only: the log never sees the receipt. The tree head and the checkpoints are public.

The tree size in the head is the number of receipts issued so far. Watch it move.

The policy the agent runs under ​

Everything is permitted and recorded, except three things, which are refused before they run and recorded as refusals:

cedar
permit(principal, action, resource);

forbid(principal, action == Action::"Bash", resource)
when { context.args has command && context.args.command like "*git push*--force*" };

forbid(principal, action == Action::"Bash", resource)
when { context.args has command && context.args.command like "*git push*-f *" };

forbid(principal, action == Action::"Bash", resource)
when { context.args has command && context.args.command like "*rm -rf /*" };

The policy file is policy.cedar; its sha256 is in every receipt, so a change to it shows in the receipts from that moment.

Two receipts you can verify ​

Both were issued when the hook was first exercised on 2026-09-21, and both are in the log.

receiptwhatfile
c92e582bgit status --short, executedc92e582b-681b-47dd-a7d7-a67897f3209e.json
47eb52afgit push --force origin main, denied by the policy before it ran47eb52af-9cd0-4428-bbdc-b44c04a1f266.json

The agent's public key is claude-code.pub. To verify one:

bash
curl -sO https://agent-custody.dev/custody/47eb52af-9cd0-4428-bbdc-b44c04a1f266.json
curl -sO https://agent-custody.dev/custody/claude-code.pub
npx @agent-custody/receipts verify 47eb52af-9cd0-4428-bbdc-b44c04a1f266.json --issuer-key claude-code.pub --log-url https://log.agent-custody.dev/ --log-id agent-custody

--log-url fetches and pins the log's published keys; --log-id requires the tree head to be this tenant's. Or drop the file on the browser verifier with the same key. Every check is listed in verification.

What this does and does not prove ​

These are SDK receipts: the hook runs inside Claude Code's process, so every field is claimed, the agent's own report, and the threat model is explicit that an in-process receipt is history, not evidence against that process. What the log adds is the part the agent cannot fake after the fact: that a receipt with exactly this content existed by the time its leaf was appended, in a tree whose history has not been rewritten since. For the calls that matter in production, use the gateway, which is not the agent's process. For a repository, this is the honest amount of custody, and it is more than any commit log offers.

Running the same on your machine ​

The hook is .claude/custody-hook.sh, registered in .claude/settings.json. It records only when ~/.config/agent-custody/hook.sh exists, so cloning the repository changes nothing for you. To record your own sessions, create that directory with an SDK config, a key from agent-custody keygen, a policy, and a log block pointing at your own log or a tenant of ours; the SDK guide has the config.