A hard limit on what coding agents may spawn

One session spawned 171 subagents to check one thing.
Provenrail asks you at the 21st.

Every subagent starts a fresh context that is billed and metered on top of the one you are already in, and nothing anywhere caps how many of them a session may start. Claude Code refuses at three levels deep; it has no opinion about width. Provenrail counts the spawns and asks you before the twenty-first, from one policy file that is enforced identically in Claude Code, Codex, Gemini CLI, Copilot and Cursor. Where there is no permission prompt to answer, an unattended run or CI, the question becomes a refusal.

Said plainly, because you are going to install this: only the Claude Code adapter is driven with a payload captured from the running CLI. The other four are written from each vendor's published hook contract and are not yet driven against a live install. The fixture for every host is in the repository and each one says which it is.

It starts by reading, not by blocking. pr report --fanout goes over the transcripts already on your disk and tells you how wide your own sessions spread and what their subagents cost, before you arm anything. Measured on the 915 sessions it was built against: the widest spawned 93 times and spent $253 on subagents alone.

Free and MIT. No account, no server, and no network call in the decision path. Read every rule.

Honest scope: the policy sees the tool calls your agent routes through its hooks, and a record is tamper-evident once it reaches a sink. Completeness is never claimed: a process that never calls the hook will not appear. Anthropic documents that a hook's permissionDecision is ignored in bypassPermissions mode, so under --dangerously-skip-permissions Provenrail records and advises rather than blocks. The full limits are below.

Before you change anything

One command tells you
how wide your own sessions spread.

A guard only pays out on a day that has not happened yet. The transcripts of the work your agents already did are sitting in ~/.claude/projects right now. pr report reads them, offline, and says what they cost, what they ran, what they touched, and which of their commands these rules would have stopped.

uv tool install provenrail && pr report

Nothing to set up, no account, no config file, and no network call. It is useful the first time you run it, which is the one thing no guard can be. Four flags: --since for a window, --project to narrow by name, --json for the versioned machine-readable document, and --share for the version that is safe to post, which drops the root path, replaces every project name with a short hash, and reduces each command to its verb and flags so nothing left in it is an operand.

The dollar figure is estimated at API list price, and notional on Pro and Max flat-rate plans, where there is no per-token charge at all. It is also a floor. Over the 49 sessions in the run below where Claude Code had recorded its own total, this estimate came out about 12 per cent under it. Two known causes are not modelled because neither is visible in a transcript: fast mode bills Claude Opus 5 at $10/$50 per million tokens against the standard $5/$25, and web search bills $10 per 1,000 searches. No multiplier is guessed at to close that gap, so the number misses low rather than high.

pr report reads Claude Code transcripts. No other agent host is read.

Every flag, and what each number means
pr report --share
$ pr report --share

PROVENRAIL REPORT

  942 sessions across 23 projects, over 31 days,
  ran 79,883 tool calls and spent an estimated
  $7,863.51.
  517 of those would have been stopped: 23 refused,
  494 sent to you to approve.

  2,163 transcripts, 3.79 GB, 128.0s

COST
    estimated total              $7,863.51
    model calls priced           69,573
    by model
      claude-opus-5       $6,646.54  41,554 calls
      claude-sonnet-5       $600.45  15,412 calls
      claude-sonnet-4-6     $471.85  11,305 calls
    Claude Code recorded its own total for 49 of
    these sessions: $5,704.12, against $5,015.01
    estimated here for the same ones.
    Spend is estimated at API list price, and
    notional on Pro and Max flat-rate plans.

ACTIVITY
    tool calls                   79,883
    bash commands                51,494
    files written or edited      7,027 distinct

RISK   replayed offline through these rules
    would have been refused      23     0.03%
    would have been sent to you  494    0.62%
         138  ask  production.deploy-command
         119  ask  access.disarm-the-guard
         104  ask  destructive.force-remove

# One machine on 16 September 2026. This is a run,
# not a benchmark. Run it, and the numbers are yours.
Where the classifier runs

The classifier is part of auto mode.
Most unattended runs do not start in auto mode.

Quoted from Anthropic's own documentation, read 16 September 2026. Where the classifier is absent, hooks are still loaded, so a deterministic policy is what is left deciding.

How the agent is startedBuilt-in starting permission modeAnthropic's classifierProvenrail's rules
Interactive session, Pro, Max or Team auto mode Runs Runs
claude -p, the headless and CI entry point Manual, on every plan Not in this mode Runs
The Agent SDK default Not in this mode Runs
Amazon Bedrock, Google Cloud's Agent Platform, Microsoft Foundry, Claude Platform on AWS default Not in this mode Runs

Sources, quoted rather than paraphrased. Starting modes and the auto-mode behaviour: code.claude.com/docs/en/permission-modes. "For -p, the built-in starting permission mode is Manual on every plan" and "Without --bare, a -p session runs the hooks in a project's .claude/settings.json": code.claude.com/docs/en/headless. The Agent SDK runs settings-file hooks by default through setting_sources: code.claude.com/docs/en/agent-sdk/hooks. A starting mode is a starting point, and anyone can switch modes mid-session.

What auto mode already does, and does well

In an interactive session, Claude Code "runs git status itself before a command that would discard uncommitted work, such as git reset --hard or rm -rf", and it "never lets a permissions.allow rule or a PreToolUse hook that returns 'allow' approve an rm or rmdir command that targets a critical path". If an interactive session on Pro, Max or Team is the only place you run agents, you already have most of what a destructive-command guard sells, free, and did not have to install it.

What it is not is a cost control, and it is not present when the session did not start in auto mode. Those two gaps are what this product is for.

Limits, stated plainly

Anthropic's hooks documentation says the permissionDecision field on PreToolUse and PermissionRequest hooks "is ignored in bypassPermissions mode, when the classifier hasn't finished running (indicated by pendingClassifier: true), or when the API has denied the call". So under --dangerously-skip-permissions Provenrail journals the decision and tells the agent, and does not stop it. permissions.deny rules are a different mechanism and do block in every mode; a hook is not one of those, and we will not imply otherwise.

A rule matches text. A command written to defeat a pattern, a delete hidden inside a script or a one-liner, is not caught. That is a property of every hook of this kind, this one included. What target resolution buys is precision on the commands agents actually emit, not immunity to one written to get past it.

One command

A day cap the agent
cannot talk its way past.

No vendor stops an agent on a dollar figure. Claude Code reports total_cost_usd at the end of a -p run, which is the invoice, not a brake.

The hook payload already carries transcript_path. Provenrail reads that transcript from where it last stopped, prices every new assistant message from its reported model and token usage, adds the delta to a ledger that survives across hook processes, and refuses the next tool call once the day is over budget.

pr guard budget 25

There is no default cap, because a cap you did not choose is a claim about your money. Set one and pr guard status prints what has been spent against it. Two things this page will never soften: the figure is estimated at API list price and is notional on Pro and Max flat-rate plans, where there is no per-token charge to cap; and the transcript is written asynchronously, so the cap stops the agent within a turn rather than at the exact dollar.

How the cap is priced
budget.day
# Arm a cap. Nothing is capped until you choose the number.
$ pr guard budget 25
  Spend cap: $25 per day, written to .provenrail.json

# The session runs. The hook prices the transcript as it grows.
> npm test
  denied  budget.day

  estimated day spend is $25.5000, over the $25.0000 cap,
  so this tool call is refused. Stop here and tell the
  person what happened rather than working around it.
  Spend is estimated at API list price, and notional on
  Pro and Max flat-rate plans.
.provenrail.json
# One file at the repo root, reviewed in a pull request
  {"policy": {"use": ["git-worktree", "destructive",
                      "secrets", "production"],
              "budgets": [{"scope": "day",
                           "limit_usd": 25}]}}

# A delete inside the project runs without a word
> rm -rf ./build
  allowed

# A delete that leaves it does not
> rm -rf ~/Projects
  denied  destructive.recursive-force-remove
The policy

It screens where a command points,
not what it is called.

Nobody has ever lost work to the letters rm -rf. They lost it to what came after them. rm -rf .next comes back in twelve seconds. rm -rf ~/ is the end of a laptop. A pattern cannot tell those apart, because the difference is not in the text, it is in where the text points. So the rules resolve the target against the working directory the host hands them.

We measured that against one frozen corpus: 36,977 Bash commands pulled from 1,247 real agent sessions, replayed offline in the directory each one actually ran in. Verb matching interrupted 923 of them. Target resolution interrupts 222. On 40 commands taken from public data-loss reports, it stops 40 of 40. Run the same measurement over your own transcripts with python tools/measure_guard.py, which makes no network call.

Every rule, and what it does

The record

A rule name is not evidence.

When a model-based classifier stops something, what survives is a line in a chat log and a label such as [Data Exfiltration]. Nothing a third party can recompute. Every Provenrail decision is Ed25519 signed and hash-chained to the one before it, so a client, an auditor or the other side of a dispute can check it without trusting the agent, the server, or us. Below is a real record, verified live in your browser. Flip one character and watch it break.

Verifying the record...

Recomputing every hash, signature, Merkle anchor, and witness cosignature locally.

Open the full verifier

Runs entirely in your browser via the open-source verifier. Your data never leaves your device, not even to us.

How it works

Decide, record, check.

Three moving parts, because fewer parts to trust means less to audit.

01Decide

The verdict is computed locally

The hook reads the tool call, resolves its target against your working directory, prices the transcript against your cap, and answers. No network call is in that path, so an unreachable server can never turn a refusal into an allow.

02Record

Each decision links to the last

Allowed, refused or escalated to a human, every decision is signed and carries a hash of the one before it. Reorder or delete one and the chain stops matching. pr guard receipt exports the lot as a portable bundle.

03Check

Anyone can check it without you

The open-source verifier reconstructs the chain offline. A Python implementation and a browser one are held to frozen public conformance vectors in CI, so verification never depends on running our code. An RFC 3161 anchor adds a public authority's time.

Install

Two commands interactively.
The same file in CI.

The Claude Code plugin carries its own dependency-free engine, so 45 rules are armed on the next tool call with no package, no account and no config file. /guard-status shows what it has actually stopped, and /guard-budget sets a cap without the CLI installed.

/plugin marketplace add pofky/provenrail
/plugin install provenrail-guard@provenrail

For headless and CI, pr guard install writes the same hooks into the project's .claude/settings.json, preserving any hooks already there. Anthropic's documentation states that "without --bare, a -p session runs the hooks in a project's .claude/settings.json", so that one file is the whole CI setup. Installing the CLI on top signs the local history in place rather than starting a new one.

uv tool install provenrail/npm install provenrail

Read the quickstart guide
quickstart.sh
# 1. Install and wire the hooks (nothing leaves the box)
$ uv tool install provenrail
$ pr guard install && pr guard budget 25

# 2. Run the agent the way you already run it
$ claude -p "upgrade the test suite"
  denied  budget.day  (the cap held, no classifier here)

# 3. The decisions are signed. Check them yourself.
$ pr guard receipt
  1 DENIED  budget.day
$ pr verify guard-receipt.json
  RESULT: VERIFIED
See it in action

Watch it work, end to end.

Real terminal sessions, no mockups. Every command and every output below is captured verbatim from a live run.

Start here · 25s Guard a coding agent Two commands, then a delete outside the project is stopped and the decision becomes signed evidence.
Tutorial 01 · 16s Install, record, verify Four commands: install, pr quickstart, pr demo, pr verify.
Tutorial 02 · 20s Verify it yourself Witnessed verify, then catch a one-byte tamper with a non-zero exit code.
Pricing

Everything that stops the agent is free.

One paid option, and it buys an artefact rather than a subscription to your own tooling.

Free
$0
MIT, forever, no account
  • The whole policy engine, 45 rules armed by default
  • Day, session and total spend caps at the tool boundary
  • /guard-status, /guard-card and the local decision journal
  • Signed, hash-chained receipts (pr guard receipt)
  • pr spend, and pr reconcile against a provider invoice
  • Both open-source verifiers, offline or in the browser
  • One independent RFC 3161 timestamp, free, so you can see what an outside party's receipt looks like on your own run
  • Community support
Install the plugin

Nothing that refuses a tool call is behind a payment. The paid option adds an outside party's signature on the time, which is the one thing you cannot issue to yourself. We host no agent records. 14-day refund.

What is free, what is paid, and why →

FAQ

Common questions.

Run uv tool install provenrail then pr report. It reads the Claude Code transcripts already in ~/.claude/projects, prices every assistant message from the model and token usage the transcript records, and prints a total per model, per project and per day. It needs no account, no config and no network call. The figure is estimated at API list price, and notional on Pro and Max flat-rate plans, where there is no per-token charge at all, and it is a floor rather than an exact number: fast mode and web search bill extra and neither is visible in a transcript.
Run pr report. Claude Code writes a transcript of every session, and the report reads them offline and says how many sessions ran, over how many projects and days, how many tool calls and bash commands they made, how many distinct files they wrote or edited, which tools they reached for most, and which of their commands the Provenrail rules would have refused or sent to you to approve. Add --share to get a version safe to post, with the root path gone, project names replaced by hashes and every command reduced to its verb and flags.
In an interactive session on Pro, Max or Team it does, and we would rather say so than argue with it. Anthropic's documentation states that Claude Code runs git status itself before a command that would discard uncommitted work, and that it never lets a permissions.allow rule or a PreToolUse hook that returns "allow" approve an rm or rmdir command targeting a critical path. What that classifier does not do is run in claude -p, the Agent SDK, Amazon Bedrock, Google Cloud's Agent Platform or Microsoft Foundry, which start in the permissive default mode, and it does not cap spend anywhere. Hooks run in all of those places.
The PreToolUse payload carries transcript_path. Provenrail reads that transcript from where it last stopped, prices each new assistant message from its reported model and token usage, adds the delta to a local cross-process ledger, and refuses the next tool call once the day cap is crossed. Set one with pr guard budget 25. There is no default cap, because a cap you did not choose is a claim about your money.
Claude Code reports cost; it does not stop on it. A claude -p run prints total_cost_usd when it finishes, which is the invoice arriving after the spending. Provenrail adds the ceiling Claude Code does not take: pr guard budget 25 writes a $25 day cap into .provenrail.json, and the PreToolUse hook refuses the next tool call once the day is over it. The figure is estimated at API list price, it is notional on Pro and Max flat-rate plans where there is no per-token charge to cap, and because the transcript is written asynchronously the cap lands within a turn rather than at the exact dollar.
Auto mode is the built-in starting permission mode for interactive sessions on Pro, Max and Team. A headless run does not start in it: Anthropic lists claude -p, the Agent SDK, Amazon Bedrock, Google Cloud's Agent Platform, Microsoft Foundry and Claude Platform on AWS as starting in the permissive default mode, with no classifier in front of the tool call. Hooks do run in all of them: without --bare, a -p session runs the hooks in a project's .claude/settings.json, and the Agent SDK runs settings-file hooks by default. A deterministic policy in that hook is what is left deciding in CI and headless.
It is estimated at API list price, and it is notional on Pro and Max flat-rate plans, where there is no per-token charge to cap. The transcript is written asynchronously, so the cap stops the agent within a turn rather than at the exact dollar. A model with no verified rate is reported as unpriced rather than counted as zero, and an unreadable transcript says so once a day instead of reading as $0.00 spent.
The hook runs outside the model's context and the model does not get a vote on the verdict. Two documented limits are on this page rather than in fine print. Anthropic's hooks documentation says the permissionDecision field is ignored in bypassPermissions mode, when the classifier has not finished running, or when the API has denied the call, so under --dangerously-skip-permissions Provenrail records and advises but does not block. And a rule matches text, so a command written to defeat a pattern is not caught, which is a property of every hook of this kind.
A cooperative agent cannot silently alter records once they reach a sink: the hash chain makes any tampering detectable. A hostile agent that never calls the hook will not appear at all. Provenrail detects tampering and deletion of records that were written; it cannot force an uncooperative process to write in the first place. That limitation is a documented part of the threat model, not fine print.
The policy engine, the spend cap, the journal, the signed local receipts and both verifiers are MIT licensed and free, with no account. One paid option exists at $9 a month, Anchored statements: unlimited RFC 3161 timestamps from an independent authority on the root of your receipts, and a public receipt page a third party can check without an account. We never receive a record, only a 32-byte fingerprint of one.
Install the verifier with uv tool install provenrail (or pip install provenrail inside a virtualenv), export the decisions with pr guard receipt, then run pr verify guard-receipt.json. The tool recomputes the hash chain, every Ed25519 signature and every anchor locally, trusting neither the agent nor the sink. A second verifier written in JavaScript runs the same algorithm in the browser, and both are held to frozen public conformance vectors in CI.