@agentguard-run/burn
v0.7.1
Published
Local session usage and runaway-agent circuit breaker. Explain tokens, cache rewrites and API list cost, track pace, warn on heavy turns, and gate agent fan-out with signed receipts. Developer command ranking requires explicit --rank.
Maintainers
Readme
@agentguard-run/burn
npx agentguard-burn whySee where a coding session's tokens went and what the next heavy turn could cost in time and limits. Burn explains recorded usage, warns about large cache rewrites and keeps its existing runaway-session circuit breaker. Runtime observation and enforcement stay on this machine. The developer review command below has an explicit external-ranking option.
Start here
npx agentguard-burn why # your last session
npx agentguard-burn calendar # every day
npx agentguard-burn card # an image to sharePress y if npm asks to install Burn. Plain npx agentguard-burn shows these three starting points. Use npx agentguard-burn --help all for every command and option.
Burn prints its installed version on the first line of every why and calendar text report, including the empty message. JSON reports include a version field. npx agentguard-burn --version (or -v) prints only the installed version.
Install AgentGuard on every agent host
npx agentguard-burn install # the plan; nothing changes
npx agentguard-burn install --yes # carry it outinstall finds Claude Code, Codex, Cursor and Hermes on this computer by their command on PATH and their config folder. It decides by reading files and starts nothing to look. Without --yes it prints the plan: each host it found, the exact commands it would run and the files they change. With --yes it runs them, reads each host again, and prints one line per host: installed, already installed, skipped, or failed with the reason, with the mode AgentGuard runs in there.
| Host | What --yes does |
|---|---|
| Claude Code | claude plugin marketplace add agentguard-run/agentguard-codex-plugin (unless an agentguard marketplace is already added), claude plugin install agentguard@agentguard, and npm ci in the plugin folder only if the dependencies are missing. An older plugin: claude plugin marketplace update agentguard, then claude plugin update agentguard@agentguard |
| Codex | codex plugin marketplace add agentguard-run/agentguard-codex-plugin (unless already added), codex plugin add agentguard@agentguard --json, then npm ci in the plugin folder Codex reports if the dependencies are missing. An older plugin: codex plugin marketplace upgrade agentguard, then the same plugin add and npm ci |
| Cursor | merges the AgentGuard hook into ~/.cursor/hooks.json after a timestamped backup: the same entry as init cursor --write |
| Hermes | uv pip install --python <the Python environment Hermes runs from> agentguard-spend-hermes, then hermes plugins enable agentguard-spend |
--only claude,codexor--skip hermeschooses hosts (claude, codex, cursor, hermes).--jsonprints the plan, and after--yeseach host's result, for an agent to read. An agent shows the plan to its person and runs--yesonly after they agree.- Run it again at any time. A host that already has AgentGuard is reported as already installed and nothing runs for it; a host that failed is tried again.
- An installed plugin older than what is available shows as "update available" and is updated through the host's own plugin commands; plugin files are never edited by hand. Available means the newer of what the host's local copy of the marketplace lists and plugin 0.5.0, since that local copy refreshes only when asked. A marketplace still added from the plugin's old repository (MerchantGuard/agentguard-codex-plugin, which GitHub forwards to agentguard-run/agentguard-codex-plugin) is left in place: Claude Code and Codex refuse to add the new source under the same name while it exists, and updates come through it.
- Where the plugin is installed (or being installed) and enabled, a standalone Burn hook in
~/.codex/hooks.jsonor~/.claude/settings.jsonis removed after the plugin steps succeed: a timestamped backup first, then only the Burn gate entries go and every other hook and setting keeps its exact bytes. The plugin includes the same gate; in Codex it does not hand launch checks to a standalone hook, so both would check every launch. With the plugin turned off, or its install failed, the standalone hook stays. - A failed host command does not stop the other hosts, and the exit code is 1. A host that is present but missing something it needs (its command on PATH, npm, uv, a readable
hooks.json) shows in the plan with the reason and is reported as failed. A usage error exits 64. - It never pipes a downloaded script to a shell, never uses sudo, never installs a host itself, never asks for or stores a key, and never writes
burn-policy.json: the plugin writes enforce into a fresh one, and a file written first would keep a new install in shadow. - Afterwards: start a new session in each host. In Codex, open
/hooks, review the AgentGuard hooks and trust them yourself; an agent must never approve its own hooks. Restart Hermes. Then check the effective mode:agentguard-statusin a Claude Code or Codex session,agentguard-burn statusfor Cursor,/agentguard statusin Hermes. The modeinstallprints is read from local files; a paid license whose check fails falls back to shadow, which onlyagentguard-statuscan see. - Run through
npx, the Cursor hook points into the npx cache, which npm can clear. For a lasting hook, install Burn globally first (see "Optional global install and hooks" below), then runagentguard-burn install.
Simple and detailed views
statusline, why and live default to simple; compact-replay defaults to detailed so its table shows. Save a preference with agentguard-burn mode simple or agentguard-burn mode detailed. It lives in AGENTGUARD_HOME/burn-config.json, normally under ~/.agentguard. AGENTGUARD_BURN_MODE overrides it. Per-command simple and detailed flags, prefixed by two hyphens, override both. Detailed output and JSON stay unchanged.
Subscriptions show real host percentages, reset times and time left at the observed pace, or "limit not available". They never show dollars. Explicit API or usage-credit sessions show today's host-reported dollars and the recent pace per hour, never a projected day total. Missing evidence stays unavailable. There is at most one next step, in English, Spanish or Portuguese.
Existing users see this once on stderr: "Showing the simple view. For tokens and cache detail: agentguard-burn mode detailed". See evidence, projections and verification for the supported metadata and limitations.
No sessions yet
With no sessions, why, calendar and card print the same guidance to stdout and exit 0. This is a normal first run. No card image is created. Burn lists the actual folders it checked, then prints:
No Claude Code or Codex sessions found on this computer yet.
Burn looked in <the actual folders it checked>.
Next: if you use Claude Code on another computer, run this there.
If Claude Code is new here, use it for a few minutes, then run npx agentguard-burn why again.By default Burn checks ~/.claude/projects and ~/.codex/sessions. When CLAUDE_CONFIG_DIR is set, it checks CLAUDE_CONFIG_DIR/projects instead of the Claude default. When CODEX_HOME is set, it checks CODEX_HOME/sessions instead of the Codex default. Unset or empty variables keep the home-folder defaults.
npx agentguard-burn why --json always writes JSON to stdout. No sessions gives found: false, looked_in, message, next and version, with exit 0. A successful session report includes found: true and version. Invalid arguments exit 64; a missing requested session or a read failure exits 4. Both errors include an error field in JSON mode. calendar also returns the empty JSON object when asked for JSON on a machine with no sessions.
week
agentguard-burn week
agentguard-burn week --week 2026-09-28 json
agentguard-burn week --lang esSee your own machine's last completed week first: useful work, waste causes,
unattributed usage, the largest cause that stands out and one concrete fix.
Weeks start Monday at 00:00 UTC and end the next Monday at 00:00 UTC.
An explicit date must be a Monday. English, Spanish and Portuguese are supported.
With no transcripts, week uses the same first-run guidance as why.
Shares lead with API list price, not a bill. Cache reads usually cost about a
tenth of fresh input. If any response has no list price, every dollar field is
null and shares use tokens instead. Useful work is instruction stack, tool
output, conversation and output. Waste causes are re-sent history, re-read files,
sub-agent fan-out and full reloads. Unattributed tokens remain separate.
Sub-agents on the main model are an overlapping subset, never another partition
bucket. The only counterfactual reprices that subset on claude-haiku-5-5.
The headline describes what was spent on waste causes and promises no savings.
Burn uses the midpoint of each dollar range and rounds each leaf bucket once to integer micro-dollars. Useful, waste, reload and overall totals sum the rounded buckets. Reload leaves are idle, model switch and other. Fan-out stands out at 20% of tokens, reloads at 15% of known spend, re-sent history at 30% of tokens and re-read files at 10%. The largest at list price wins, or tokens when unpriced, with ties in that order. Fan-out becomes the main-model cause when at least half of sub-agent tokens belong to that subset. Reload ties prefer idle, then model switch, then other.
After displaying the figures, Burn atomically saves
AGENTGUARD_HOME/week/YYYY-MM-DD.json (default ~/.agentguard/week/), with
directory mode 0700 and file mode 0600. Only complete, nonempty weeks started
within the last 28 days are saved, since Claude Code normally keeps transcripts
for 30 days. Older or partial weeks can be viewed locally. The saved file has
exactly schema, weekStart, viewedAt and figures; see the
v1 fixture. Local diagnostics, including excluded
forks, undated tokens and unpriced model ids, never enter it. week json prints
those diagnostics under local, and saved reports whether the file was written.
Five hard lines apply to weekly sharing:
- Content-free: only integer counts, fixed enum codes, a UTC week date, the existing hashed seat id, a public key and signature leave in a weekly upload. No prompts, completions, file contents, file names, paths, usernames, project names, session ids, model ids or free text. Share changes contain only their schema, seat id, choice and UTC timestamp, signed the same way. Fix sentences are looked up locally from the cause code.
- No per-person measures or comparisons of effort or productivity. No composite measures, grades, percentiles, ordering of people, team-average comparisons, session counts, active hours, commits or tokens per commit.
why --commitsstays local. Manager per-seat detail is shares and cause only, with no absolute tokens or dollars. - Copy describes where tokens went and what to change, never rates the person. A seat is one machine, not a person.
- Only the person changes weekly sharing, locally in the plugin:
offby default,totalsfor team totals only, orseatfor that seat's top waste cause and its fix (never its shares, tokens or dollars). Org policy cannot set it. Turning it off sends a removal request immediately to delete that seat's stored weeks; a failed request is retried. Turning it on applies at the next upload. - You see the exact week on this machine before it can be uploaded. The plugin sends this saved file's figures, with no recomputation. Burn itself uploads nothing for
week.
Launch tree and signed approval tally
agentguard-burn tree SESSION
agentguard-burn tree SESSION --json
agentguard-burn tally SESSION
agentguard-burn tally SESSION --jsonOmit SESSION to use the current or latest local session, or pass its transcript path. tree shows recorded parents, each agent's model, own and subtree tokens, token share, recorded duration and unfinished status. Missing parent links stay under parent not recorded. The terminal view fits 80 columns and collapses large fan-outs; JSON keeps every node. why includes a short tree when children were recorded.
tally verifies signed plugin receipts and their complete hash chain before counting launch decisions. Missing or invalid receipts print a reason instead of a number. Approvals are a subset of asks; policy refusals and unrecorded approval outcomes remain separate. Codex blocks launches until allowed and never receives an ask count. See the field definitions, arithmetic and verification limits.
For Claude Code, configure its statusLine command as agentguard-burn statusline. It receives the host JSON on stdin. Codex 0.154.0 has no external status command slot. Use agentguard-burn statusline SESSION_ID in a companion terminal and the native Codex limit indicators. See host fields and setup.
Import a DisciplineBench run
Burn 0.3.3 can verify and replay a signed DisciplineBench bundle offline. This is a post-run display, outside benchmark scoring. It does not run an agent or change a benchmark result.
agentguard-burn import-bench ./run-bundle --out ./burn-import
agentguard-burn replay ./burn-import/replay.json --pricing ./burn-import/bundle/pricing.json
agentguard-burn replay ./burn-import/replay.json --pricing ./burn-import/bundle/pricing.json --json
agentguard-burn render ./burn-import/recording.jsonl --mp4 ./run.mp4 --gif ./run.gifThe importer uses the bundled, unchanged DisciplineBench verifier to check the manifest signature, every declared artifact hash, the Ed25519 ledger chain, and the recomputed run.json. Only manifest-listed artifacts are copied into a new directory. The source bundle is unchanged. Existing output directories are refused. The default output is the bundle path with .burn appended.
Embedded keys prove integrity, not the publisher's external identity. Obtain a publisher fingerprint through a trusted channel and supply --publisher-key-id ID to import or replay when that identity matters. Publisher and measurement fingerprints remain separate. No AgentGuard license, provider credential, model call, or network request is required.
Replay requires --pricing on every invocation. Its bytes must match the signed round's pricing artifact exactly. Current Burn prices, local overrides and prices from another round are never substituted. Cache durations and long-context rates use the harness pricing rules. The display rounds the final list-price exposure to cents; JSON keeps the unrounded reducer value. List price is a comparability convention, never a bill.
The replay file keeps every canonical event, the complete spawn tree, rule IDs, enforced:false, all native and normalized token categories, and the usage reconciliation. Missing measurements remain null and render as unknown. A STOP in this recording is a would-STOP classification, not an execution block. Burn does not invent a spawn ceiling or an active window absent from the bundle.
Each event produces a frame at its original timestamp. Frames contain cumulative observations through that event, not a synthetic 15-minute enforcement window. The final frame agrees with the verified reducer. replay ... --record frames.jsonl also writes those event frames. render uses the existing local PNG, MP4 and GIF pipeline and records source SHA-256 provenance. Frames are display derivatives, not newly signed measurements; replay re-verifies the retained bundle and checks the conversion before producing new frames.
Imports are limited to 128 MB of declared artifacts and 10,000 events, matching the local renderer's frame limit. No task code or modules from the bundle are executed. The exact vendored verifier sources, Apache-2.0 license and source hashes are in vendor/disciplinebench/.
The bundled fixtures/bench-run is an authored fixture, not a scored host run. Its reducer and Burn both report $0.0155, displayed as $0.02. It declares two child agents, maximum depth two, and a would-STOP observation for GP001 and GP006. See the rendered frame, MP4, GIF, and artifact hashes. The original harness's burn-postrun.json marker remains unchanged as signed evidence, including its older unsupported-import message.
Developer guard candidates
guard-candidates reads local ledgers and writes a review file. It never executes a recorded command or changes a rule, policy, hook, or ledger.
agentguard-burn guard-candidates --out ./commands.review.json
agentguard-burn guard-candidates --ledger ./local-ledger.ndjson --out ./explicit.review.jsonThe default scan covers all named decision, receipt and ledger NDJSON/JSONL files under AGENTGUARD_HOME (default ~/.agentguard), plus PLUGIN_DATA and CLAUDE_PLUGIN_DATA when provided. Numbered/date suffix rotations are included. Nested symlinks are not followed. Use repeatable --ledger to choose other local ledger files. The command reads each file up to its opening size, across every session, including a complete last line without a newline. It does not read transcripts or shell history.
Commands are deduplicated by exact text, with occurrence counts. Whitespace, quoting, multiline programs and long strings stay intact. Recognized shell tool records can carry command, cmd or script in tool input, including signed decision.plugin envelopes and JSON function arguments. Non-shell tools, responses and incidental command fields are excluded.
Current Burn and plugin ledgers omit command text. They store metadata and input hashes. Those shell records are counted as missing text; hashes cannot reconstruct commands. This command does not enable new content logging. A metadata-only ledger produces an empty review, not invented candidates. Malformed rows are reported by file and line; ranking refuses an incomplete scan.
To rank, first install the optional jsort CLI, distributed as jev-sort under MIT. The adapter targets 0.1.3 (reviewed source). Burn does not install it automatically.
uv tool install 'jev-sort==0.1.3'
# Set TYPESAFE_API_KEY or OPENROUTER_API_KEY in your environment first.
agentguard-burn guard-candidates --ledger ./local-ledger.ndjson --out ./ranked-input.review.json --rankOnly --rank with a nonempty environment key can start jsort or a provider request. TypeSafe takes precedence when both keys are present. Key files and gateway/model overrides do not enable ranking. With no key, or fewer than two unique commands, the raw review is kept and ranking is skipped.
The exact criterion is how likely is this command to destroy data, leak a secret, escalate privilege, or change infrastructure. Before jsort starts, the command prints the provider, endpoint, criterion and complete command texts as escaped JSON. Each exact outgoing JSON request body is then printed and flushed before it is forwarded. Authentication keys are never printed or stored in review files. Recorded command text is sent verbatim, including any secrets inside it, so inspect the local review before choosing --rank.
jsort receives only command strings through stdin. A local forwarding gate permits only comparisons between those strings, using that criterion and the selected provider/model. It rejects unexpected request data and redirects. The provider key stays in Burn; jsort gets a temporary local token. No cache is written. The adapter uses jsort's $1 budget, a 15-second comparison timeout and a five-minute process timeout. Incomplete, failed or malformed rankings leave the raw review intact and return a nonzero exit status.
Successful ranking creates ranked-input.ranked.review.json beside the raw file, with each command's score, standard error and comparison count, highest first. Scores are relative Bradley-Terry logit values, not calibrated risk probabilities. All outputs have owner-only permissions. Existing outputs, non-review output names and --record are refused. These commands have no automatic connection to Guard Pack rules and are never installed or called by hooks.
Local idle audit
Burn 0.3.0 reports held memory and disk cost exposure on this machine:
agentguard-burn ps
agentguard-burn ps --json
agentguard-burn reapps lists Claude Code and Codex sessions with their Node children, leftover plugin daemons, automation-owned Chrome browsers, and candidate workspaces. Process rows are ranked by resident memory, then workspace rows by disk size. Normal Chrome profiles are excluded. Browser rows show their process count, total resident memory and available window count. Unknown values are explicit. RSS can count shared memory more than once; it is not a bill.
Session idle time uses the controlling terminal's access time when readable, otherwise transcript file-write metadata. The table labels the method. A transcript fallback can warn but cannot prove that a terminal has been inactive for 24 hours. Workspace rows show size, last modification, dirty status and open-handle evidence. No transcript content or process arguments are printed or uploaded. Swap is reported only: swap is only released by the operating system on reboot. Burn does not touch it.
The audit opens with free disk on the volume holding your home folder and swap use:
[WARN] Disk: 13.8 GB free of 994.7 GB (1.4%) on the volume holding /Users/you.
Under 10 GB or 10% free, the next large build or agent log can fill it.
[WARN] Swap: 14.1 GB of 15.0 GB in use (94.1%).
Over 80% used, memory is short and the machine slows down.Disk is [WARN] under 10 GB or 10% free and [CRIT] under 5 GB. An AGENT DATA section then shows how much ~/.claude/projects and Codex's sessions folders and history files hold, the five largest files (marked [WARN] over 1 GB, which usually means a runaway loop or very large tool output), and any session with more than 500 subagent transcripts. Sizes and counts come from file metadata only. Linked git worktrees of the repositories behind live sessions appear as workspace rows. Like every workspace row, all of this is information only and never deleted.
The Claude Code PreToolUse hook adds one line per session when the home volume drops under 5 GB free. It reads free space at most once a minute and never denies or asks:
AgentGuard WARN: 3.2 GB free on the disk holding /Users/you. Under 5 GB, builds, installs and agent logs start failing. Run agentguard-burn ps to see what agents are holding.reap prints the same numbered audit, then requires an interactive terminal and numbers typed at the prompt. There is no --yes flag and piped confirmation is refused. It sends only SIGTERM to the selected eligible processes, waits, and reports whether they exited. It never sends SIGKILL and never deletes files or directories.
Reap refuses:
- Any session with terminal input in the last 24 hours, or unavailable terminal-idle evidence. Changing a warning threshold does not change this safety limit.
- Any process whose working directory has modified or untracked files, or whose directory safety cannot be verified.
- Every workspace, including any workspace with open file handles. Workspace rows are information only.
- The process running reap and all its ancestors, including a selected group containing one of them.
- A process whose identity, ownership or safety evidence changed while confirmation was pending. New or replaced PIDs are never added to the confirmed selection.
It rechecks the selected processes before signaling. Permission errors and processes that ignore SIGTERM are reported. They are not force-closed.
Add these fields under thresholds in the existing ~/.agentguard/burn-policy.json (or AGENTGUARD_HOME/burn-policy.json):
{
"thresholds": {
"idle_session_warn_hours": 24,
"idle_browser_warn_minutes": 60,
"orphan_workspace_warn_days": 2
}
}Merge the fields into your existing policy. Missing or invalid values use the shipped defaults. A local teamPolicyFile can point to a JSON file containing thresholds; relative paths resolve from the Burn home. Team threshold values take precedence over local threshold values, including these three audit settings. Neither policy loading nor the audit rewrites your policy.
The Claude Code and Codex hook snippets now include SessionStart. Review the new agentguard-burn init claude or agentguard-burn init codex output to update existing installations. At session start, a fresh five-minute local audit cache is checked. A cache miss gets a bounded scan with a 150 ms budget; timeout or unavailable evidence skips the advisory. A warning is one line, never a table and never a deny:
N idle agent sessions holding X GB, run agentguard-burn psThe line is WARN-only in both shadow and enforce modes. If only browser or workspace rows cross their thresholds, the session count can be zero; run ps for those details. The full ps command refreshes the cache. All collection and caching stays local.
macOS uses local process, file-handle and swap metadata. Linux uses /proc and available local tools, and says what could not be read. Windows prints not supported on this platform yet and exits successfully. See the docs page draft for the audit boundary and limitations.
Name every cache miss
agentguard-burn rewrites
agentguard-burn rewrites SESSION_ID
agentguard-burn rewrites all
agentguard-burn rewrites SESSION_ID jsonA full-prefix rewrite writes more than 150,000 tokens and more than half the actual input context. Every rewrite gets one row: when it happened, the session, the host, the model, the cause, the idle gap before it, the cache-write tokens, the list-price equivalent of that write and a one-line explanation. The by-cause summary follows, and the last line is the rewrite total as a share of the same session list total that why prints. Without a session, rewrites reads the newest top-level session plus its stored child transcripts, exactly as why does.
Causes are named in a fixed order, so a rewrite with several signals gets the first one that applies: model_switch (the model differs from the previous usage turn), version_upgrade (Claude Code's recorded version differs), compaction, first_spawned_turn, idle_ttl_expired (the idle gap exceeds the lifetime recorded for the write), image_pruning (an earlier message was re-recorded with fewer image or PDF blocks), then a host-reported prefix_change. What remains is prefix_change as a residual, or unknown_ttl when the lifetime is absent or mixed. Codex transcripts carry the model on turn_context and mark compaction with compacted; a Codex rewrite with neither signal is unknown, with the reason stated, never prefix change by default.
Three causes in Claude Code's cache-invalidation list are not written to the transcript, so Burn never names them: effort changes, fast mode and tool definition changes (MCP connect or disconnect, plugin toggles, denying a whole tool). Claude Code also does not persist image pruning; the image_pruning rule only fires when a message is re-recorded without its images. The explanation column says which of these could not be observed instead of guessing.
The synthetic fixture in tests/fixtures/rewrite-fixtures.ts renders as follows (rows shortened):
AgentGuard rewrites: 10; 1 followed an idle gap over 60 minutes.
When Session Host Model Cause Idle Write tokens List ...
2026-09-24T09:20:00Z synthetic-claude-fixture claude claude-sonnet-5 idle_ttl_expired 20m 180,000 $0.45 ...
2026-09-24T09:22:00Z synthetic-claude-fixture claude claude-opus-5-5 model_switch 2m 180,000 $1.44 ...
2026-09-24T09:24:00Z synthetic-claude-fixture claude claude-opus-5-5 version_upgrade 2m 180,000 $1.44 ...
2026-09-24T09:26:00Z synthetic-claude-fixture claude claude-opus-5-5 compaction 2m 180,000 $0.90 ...
2026-09-24T12:26:00Z synthetic-claude-fixture claude claude-opus-5-5 idle_ttl_expired 3h 180,000 $1.44 ...
...
Rewrites: $9.47, 95.6% of the combined session list total $9.90 (API list equivalent, not a bill).The JSON form is stable: {sessions: [{sessionId, host, records: [{at, model, cause, explanation, idleMs, cacheWriteTokens, usd}]}], totals: {count, cacheWriteTokens, usd, shareOfSessionUsd}}. Rewrite tokens are always a subset of the measured cache-creation tokens; nothing is estimated from text.
Cache lifetime from your own gaps
agentguard-burn ttl
agentguard-burn ttl SESSION_ID
agentguard-burn ttl all
agentguard-burn ttl SESSION_ID jsonttl answers one question from recorded turns: had the cache lifetime been one hour instead of five minutes, what would the same history have been billed at API list rates? A rewrite counts as avoided when it followed an expired five-minute lifetime with an idle gap of at most one hour; under a one-hour lifetime those tokens would have been billed as cache reads. Against that, every other write recorded with a five-minute lifetime would have been billed at the one-hour write rate. The report keeps the main conversation and subagent transcripts in separate buckets because Claude Code sets their lifetimes separately. Unknown lifetimes stay unknown and are excluded, with the excluded count shown.
The same fixture renders as:
AgentGuard ttl: synthetic-claude-fixture, agent-synthetic-child
List-price counterfactual on recorded turns: the result is the net at list price, not a bill. Subscription users: read the token columns; every dollar column is the API list equivalent.
Bucket Rewrites avoided Avoided write tokens Billed at 5m Would have been reads Repriced 5m write tokens Extra at 1h rate Net at list
main 1 of 8 180,000 $0.45 $0.04 751,000 $2.07 -$1.66 (5m)
subagent 1 of 2 170,000 $0.42 $0.03 160,900 $0.24 +$0.15 (1h)
Rewrites avoided: full-prefix writes that followed an expired five-minute lifetime with an idle gap of at most one hour. Under a one-hour lifetime they would have been billed as cache reads, not writes.
Extra at 1h rate: every other write recorded with a five-minute lifetime would have been billed at the one-hour write rate instead. Net = billed at 5m minus reads minus extra.
main: 1 rewrite with an unknown lifetime excluded from the counterfactual
Main conversation: net favours 5m. Leave promptCacheTtl unset; the longer lifetime would have been billed more on these turns.
Subagent transcripts: net favours 1h. Set "subagentPromptCacheTtl": "1h" in settings.json.
On a Claude subscription within plan usage the main conversation already has a one-hour lifetime; API key and usage-credit sessions start at five minutes. Subagents, forks, compaction and titles stay at five minutes unless subagentPromptCacheTtl is set.
Multipliers relative to base input: 5m write 1.25x, 1h write 2x, cache read 0.1x; a model row's verified rates take precedence.Every dollar column is an API list equivalent; on a subscription, read the token columns. The multipliers come from Anthropic's prompt caching pricing (five-minute writes 1.25x base input, one-hour writes 2x, cache reads 0.1x) and only fill rates a model row leaves empty; the verified rates in the pricing table, and any local override, take precedence. The verdict lines name the exact setting: "promptCacheTtl": "1h" for the main conversation (or CLAUDE_CODE_PROMPT_CACHE_TTL=1h) and "subagentPromptCacheTtl": "1h" for subagents, forks, compaction and titles. On a Claude subscription within plan usage the main conversation already has a one-hour lifetime; API key and usage-credit sessions start at five minutes. When the net favours five minutes, the report says so plainly.
Replay compaction windows
agentguard-burn compact-replay
agentguard-burn compact-replay days 7 jsonCompare Claude Code's current auto-compaction window with 600K, 400K, 300K and 200K using local transcripts from the last seven days. The days option changes the lookback, from 1 to 3650 days, and json returns the figures and diagnostics. Both options also accept the conventional two-hyphen flag spelling. No Claude Code call, network request or settings write is made. Claude Code transcripts come from CLAUDE_CONFIG_DIR/projects, or ~/.claude/projects when that variable is empty or unset. Sub-agent transcripts have their own contexts; copied responses count once.
Claude Code's own model configuration, settings reference and commands reference, checked on October 9, 2026, document autoCompactWindow from 100,000 to 1,000,000 tokens and /autocompact 200k. Since Claude Code v2.1.288, the command saves a value for the current model under modelSettings; /autocompact auto returns to its tuned default. Environment and higher-priority settings can override that choice. Burn reads user, project, local and on-disk managed settings, including their environment blocks. When no numeric window is set, the report labels the model window as assumed, normally 1M. It cannot recover old launch flags or remote managed policy.
Each table row gives tokens saved, dollars saved as API list equivalent, extra compactions and the percentage change in tokens, relative to the current-window replay. Negative savings mean more usage. Dollars retain the cache lifetime range where it is unknown; an unknown model stays unpriced. These are estimates for the same recorded work, not a subscription discount or a promise about task quality.
The replay advances context by the measured change between recorded requests. At a recorded automatic compaction it uses compactMetadata.preTokens to recover the growth before the reset, then independently decides whether the simulated context crosses the chosen window. A reset uses the median next-request context after real compactions, first from that transcript and model, otherwise from the same model and main or sub-agent role in the selected transcripts. Manual compactions and recorded clears stay fixed. Missing usage or a missing compaction measurement makes affected results unavailable.
New resets rewrite the cache. Extra summary requests are conservatively charged a full uncached context read plus the measured reset size as summary output, because the transcript does not reliably identify their usage separately. Fewer summaries receive no credit. Other output stays fixed. This assumption is printed with the report.
The caveat immediately under the table gives the replay's error against the recorded token total at the current window. Above 10%, it says the replay is unreliable for this machine and suggests no change. The error is a backtest result, not a statistical confidence interval. With complete evidence, an acceptable backtest and positive conservative dollar savings, the report suggests the smallest tested window within 100K to 1M whose extra compactions are strictly below twice the recorded current count. It keeps every row visible so you can choose, and prints a command such as /autocompact 400k to type in Claude Code for each model you want to change. It withholds that command when an override prevents it from applying.
Why this session
agentguard-burn why
agentguard-burn why SESSION_ID
agentguard-burn pace SESSION_ID
agentguard-burn pricingA session argument can also be a transcript path. Without one, Burn uses the session environment variable when available, then the most recently modified local transcript. Claude child transcripts are included in why. Token shares are shares of recorded tokens, not shares of dollars. Repeated usage records for one provider response count once. Copied Codex history is reconciled before counting new usage.
The table covers instruction stack + system, history re-sent, repeated file reads, subagent fan-out, tool output, conversation, full-prefix rewrites, output and unattributed usage. The fixed-prefix baseline is the first assistant response's measured context. It includes the initial user message, so the label is an operational baseline rather than a direct measurement of instruction files. A rewrite classified as prefix change resets that baseline and is counted in the footer; the new baseline can include history already present at that point.
The report ends with at most one tip: the one action that matters most for this session, from its own numbers. A cause stands out at these shares: sub-agents at 20% or more of session tokens, full-prefix rewrites at 15% or more of the session's API list equivalent (skipped when a model is unpriced), and the conversation Claude re-reads, or the setup it reads before every message, at 30% or more of session tokens. Among the causes that stand out, the largest at API list price wins (the largest in tokens when a model is unpriced), and the tip names one action from Anthropic's own guidance (costs, prompt caching, sub-agents):
- Sub-agents that ran on the main model:
38 sub-agents ran on Opus 5.5.and a smaller model for searching and reading logs (CLAUDE_CODE_SUBAGENT_MODEL=haiku, ormodel: haikuin the sub-agent's definition). Otherwise the sub-agent share, and AgentGuard's free plugin, which asks you before the next sub-agent past your limit starts. - Reloads after a pause outlasted the cache: how many, the longest pause, and
/compactbefore a break. Reloads from switching models: how many, and switching at a break right after/compact. Any other reload cause: the dollars andagentguard-burn rewrites. - The conversation re-read on every message: its median per message, and
/compactat a natural break or/clearbetween unrelated tasks. - The setup read before every message (CLAUDE.md, tools, MCP servers and the first message): its median per message, a short CLAUDE.md and turning off unused MCP servers (
/mcp).
The setup and the re-read conversation split each call's cached reads at the size of the session's first call, so a rewrite that resets the table's baseline never turns re-read conversation into setup. Tips never claim a saving and print no dollar figure except the rewrite dollars the table prints. When nothing stands out there is no tip. agentguard-burn quiet on hides it, quiet off shows it again and quiet says which. why json never contains it.
After a /compact, an automatic compaction, a model switch, or a /clear that the transcript records, why adds one measured line before the tip, for example Measured change: after /compact on 2026-09-27 at 14:02 UTC, Claude read a median of 85K tokens per message, down from 660K in the 20 messages before. It compares the median tokens per message of the main conversation in the N messages after the latest such event with the N before it: N is 20, fewer when the session or the next or previous event leaves fewer, and with fewer than 5 on either side that event says nothing. It states a measurement next to an event, never a saving or a cause, and prints whether or not tips are on.
When the session's transcripts record sub-agents that ended without finishing, why adds one line after the observed calls, for example Sub-agents that ended without finishing: 2 of 5, 275,000 tokens (58.9% of session tokens, $0.75 API list equivalent). A sub-agent counts only when Claude Code recorded its status as failed, killed or stopped, and never as completed or resumed. One launched in the background with no end recorded may still be running, so it never counts. The count is out of every sub-agent transcript in the session's subagents folder, the tokens are their own responses counted once, and the dollars are left out when a model is unpriced. Burn knows whether a sub-agent finished, never whether its work was right. why json lists the ids it counted from under subagents.
why prints in Latin American Spanish or Brazilian Portuguese when your machine is set to that language, and --lang es, --lang pt or --lang en picks one explicitly. The order is --lang, then AGENTGUARD_LANG, then LC_ALL, LC_MESSAGES and LANG (the first one set decides, as POSIX says, so LC_ALL=C means English), then the locale Node resolves. Every other language is English. Figures keep their en-US formatting in every language (1,234,567, $1335.37, 12.3%), so a translated report matches screenshots digit for digit. why, compare, calendar, week and all four simple views are translated. Their JSON output is the same in every language.
Later cache reads up to the baseline go to instruction stack + system. Reads above it go to history re-sent. Fresh input plus cache creation is the measured arriving increment. Burn subtracts the previous response's output before assigning that increment to intervening tool results and user messages. Result byte sizes only split that measured total; bytes are never converted into tokens. A result for a previously read Read path goes to re-read files. Mixed user and tool intervals are marked shared and counted in the footer.
Rewrite tokens and child transcript usage keep their own buckets. Prior output deducted from an input increment remains in the unattributed residual so every recorded input and output token is counted exactly once. Missing event evidence also remains there. Integer allocation preserves every token, and the Method footer explains each row.
Every tool hook updates a local pace file under the Burn home. Pace uses ten wall-clock minutes: cached means cache reads; uncached means fresh input, writes and output. The next-hour projection assumes that pace continues. A time-to-limit estimate requires rising, fresh host percentage samples from the same quota pool and reset window. No token-to-limit conversion or cache weighting is assumed. Without sufficient host data, the line says why the limit is unknown.
The new warnings are advisory in both modes. Cache rewrites warn once when their last-hour API list equivalent exceeds $5. A context crossing 500,000 tokens warns about processing time and compaction, estimates a cache rewrite, and suggests a fresh session with a handoff note. These warnings do not deny a tool call.
Optional settings in your existing burn-policy.json:
{
"insights": {
"rewriteWarnDollarsPerHour": 5,
"heavyTurnTokens": 500000
}
}Merge these fields into the existing policy. All existing thresholds and modes remain supported. Prices are exact-model API list equivalents, not a subscription bill. Unknown models show tokens only. Every rate has a source and verification date. A local override file and full pricing table are documented in Usage and pricing.
What it bought: why --commits
agentguard-burn why --commits
agentguard-burn why SESSION_ID --commits
agentguard-burn why SESSION_ID json --commitswhy shows where a session's tokens went; --commits adds what they bought, counted in commits that landed while the session ran. It is one line after the report's measurements and before the tip:
What it bought: 12 commits landed while this session ran (9 co-authored by Claude Code). 844,000,000 tokens per commit co-authored by Claude Code.It is off by default. Without --commits, why never runs git and never reads a repository, and its output, why json included, is unchanged.
With --commits, and only then, Burn reads:
- From the session's transcripts (the session and the sub-agents stored with it): the time on its first and last records and the working directory the host recorded there (Claude Code's
cwd; Codex'ssession_metaandturn_context). No message content is kept. - From your other local Claude Code and Codex transcripts: the same fields from their first and last records, to find sessions that ran at the same time in the same repository.
- From git, on this computer:
git -C <cwd> rev-parse --show-toplevel --git-common-dirto find the repository (for this session, and for each other directory found running at the same time), then onegit log --exclude=refs/stash --exclude=refs/notes/* --all --since=@<start minus 2 days> --until=@<end> --format=%H%x00%ct%x00%(trailers:key=Co-authored-by,valueonly,unfold,separator=%x01), which prints each commit's hash, committer time and Co-authored-by trailers and nothing else of it. Every git call shares 2 seconds; past that the call is killed.
All of it stays on this computer, and nothing is stored. The line and the json carry counts only, never a hash, an email, a commit message, a file name or a path. why json --commits adds commits: {status, landed, coAuthoredByClaudeCode, coAuthoredByCodex, coAuthored, overlappingSessions, tokensPerLandedCommit, tokensPerCoAuthoredCommit, perCommitBasis, graceMinutes}, with status one of ok, no_repository, unrecorded, git_missing, git_timeout or git_error.
How it counts:
- The window runs from the session's first record through its last record plus 10 minutes, so the commit that closes a session counts. A stored sub-agent's records widen it. A commit counts when its committer time falls inside, both edges included, and each hash counts once, whichever branches, tags, remote-tracking refs or worktrees hold it. git stops following a branch at a commit dated before the time it is asked from, so it is asked from two days before the window and Burn applies the exact window itself: a commit with an out-of-order date (a skewed clock) hides nothing under it unless it is dated more than two days before the window. A stash and git notes are not landed commits. A rebase or cherry-pick inside the window makes new commits, and they count, as does a teammate's commit fetched with its time inside the window. A session resumed days later has a window that spans the days in between.
- A commit is co-authored by Claude Code when a
Co-authored-bytrailer carries Claude's address ([email protected]), or names Claude with no address or an anthropic.com one; a person named Claude with their own address is not. Codex appendsCo-authored-by: Codex <[email protected]>when its commit attribution is on, and those commits are co-authored by Codex. The session's own host is always named; the other only when it co-authored any. - When other local sessions ran in the same repository during the window (in a worktree of it too), the line says
shared with N overlapping sessions: those commits can't be split between sessions, so the line and the json then give no per-commit figure. A Claude Code sub-agent belongs to its session, as in the rest ofwhy; a Codex sub-agent keeps its own rollout, whichwhyreads as a session of its own, so it counts as one here. - The per-commit figure is the token total the report's header prints, divided by the commits in the window that Claude Code or Codex co-authored (a commit naming both counts once), and its label names them:
tokens per commit co-authored by Claude Code,by Codex, orby Claude Code or Codex. So a teammate's commits, fetched or local, count as landed but never lower it. Only when no commit in the window names either agent, as when commit attribution is off, does it divide by every landed commit, and the line then saystokens per landed commit.why jsoncarries both,tokensPerCoAuthoredCommit(null when the agents co-authored none) andtokensPerLandedCommit, andperCommitBasis(coAuthoredorlanded) says which one the line prints. - With no commit, the line says
What it bought: no commits landed while this session ran.A directory that is no repository, a missing git, a git that does not answer within 2 seconds, or a transcript that records no directory or time ends the line with that reason; the rest of the report is unchanged and the exit code stays 0.
A landed commit is a count, not a judgment of the work in it. The line is in Spanish and Portuguese with the rest of why. calendar has no --commits: its daily counts keep no working directory and no session times, by design, so a week's commits could not be counted again once Claude Code deletes a transcript after 30 days.
Compare two sessions
agentguard-burn compare
agentguard-burn compare SESSION_ID
agentguard-burn compare SESSION_A SESSION_B
agentguard-burn compare SESSION_A SESSION_B jsonRun the same task once on each model, then put the two sessions side by side. With no session, compare takes the two most recent top-level sessions in the project of the newest one; with one, that session and the newest other top-level session in its project; with two, those two in the order given. Sessions resolve as they do for why (id, id suffix or transcript path). Sub-agent transcripts and other files Claude Code keeps beside a session are never picked. A Codex rollout's project is the working directory it recorded, and a spawned sub-agent rollout is skipped. Unless you name both, A is the session that started first. Fewer than two sessions exits 1 with one line saying how to pass two ids.
Both sessions are named first: the short id (the last part of the session id, which compare and why accept back), the time of the first recorded response in UTC, the model with the most output tokens (every model with at least 5% of output tokens, with its share, when there are several) and the project path. Each figure is the one why prints for that session, child transcripts included. Change is B against A, only where both values are numbers and A is not zero as printed; a dollar range compares midpoints, and an unpriced model prints unpriced with no change. The fixture in tests/fixtures/compare-fixtures.ts renders as:
AgentGuard compare: B against A
A aaaaaaaaaaaa started 2026-09-25 10:01 UTC
Output by model: claude-opus-5-5 92.3%, claude-haiku-4-5-20251001 7.7%
Project: /synthetic/project
B bbbbbbbbbbbb started 2026-09-25 11:01 UTC
Model: claude-sonnet-5
Project: /synthetic/project
Metric A B Change
Assistant responses 4 3 -25.0%
Input tokens 599,600 543,000 -9.4%
read from cache 200,000 360,000 +80.0%
cache writes 396,000 180,500 -54.4%
fresh input 3,600 2,500 -30.6%
Cache share 33.4% 66.3% +98.8%
Output tokens 6,500 4,000 -38.5%
Sub-agents launched 1 0 -100.0%
Full-prefix rewrites 2 1 -50.0%
List USD $2.13 $0.57 -73.3%
Totals include sub-agents.
Dollar figures are API list-price equivalents, not a bill.
AgentGuard cannot tell whether these sessions did the same task. Compare runs of the same task.compare measures and does not rank models. --lang es|pt and your locale choose the language exactly as for why. compare json is never translated: both sessions with ids, paths, project, models and every metric, and each change as an unrounded fraction of A.
Tokens per day
agentguard-burn calendar
agentguard-burn calendar --weeks 12
agentguard-burn calendar jsonEvery Claude Code and Codex session on this machine on one heatmap, sub-agents included: a column per week, a row per weekday, darker for more tokens. Each response's tokens and API price come from the parser and prices why uses, counted on the local calendar day the response was recorded. A response recorded in two files (a sub-agent's copy of its parent's last reply, a project that moved, a forked session) counts once, merged the way why merges a session. A forked Codex session whose copied history has no verifiable boundary is left out and named in a note, as why reports it unavailable.
The summary is at most four short lines, however wide the terminal: the total tokens and the dollars at API prices (not a bill; from $1,000 in whole dollars, such as $28,252 to $28,254 at API prices, not a bill, and one number when both ends round to the same dollar); the busiest day and the share of tokens sub-agents used (every token of their responses); only when there were any, how many sub-agents ended without finishing, out of all of them, with their tokens, share and dollars, by the rule why uses (each sub-agent counts once, on its first day with tokens, with all of its tokens, and days an earlier Burn counted carry no sub-agent counts); and, only when there were any, how many sub-agent launches AgentGuard held: refused by an enforced STOP, or held for your yes, as the decisions ledger records them. On a narrow terminal a line's two items take a line each. A day is amber when sub-agents used more than half of its tokens, and carries a red mark when AgentGuard held a launch that day. The five shades run from Less to More: a day's level is the quarter of the shown days with tokens that it reaches, so the busiest day shown is always the darkest. Tokens on a model without a verified rate are counted but left out of the dollars, and a note names the model.
With no flag the calendar starts at the oldest recorded day, capped to the weeks that fit the terminal (its width on a terminal, 80 columns when piped, as when Claude Code runs ! npx agentguard-burn calendar); --weeks N shows exactly N weeks, 1 to 53, ending with this week.
Days are big whenever the span fits: two characters a day and one space between weeks, which reads as roughly square. That takes the weekday labels plus three columns a week, so 25 weeks fit 80 columns, 39 fit 120 and all 53 fit 162. When the span does not fit (a long history at 80 columns, or a --weeks span wider than the terminal), each day is one character and one space, as 0.3.20 drew every calendar; the span never shrinks to make the days bigger. A colour terminal draws a big day as ▇▇ and a compact day as ■. The seven-eighths block leaves a thin gap above each day, where full blocks would join a week's days into one bar. Piped, with --no-color or with NO_COLOR set, a big day is a shade pair (·· ░░ ▒▒ ▓▓ ██) and a compact day one shade character (· ░ ▒ ▓ █). The two kinds of marked day are the letters s and H (the red diamond in colour): a big day keeps its shade in the left half and shows the mark in the right (▓s, █H), while a compact day shows the mark alone. The fixture in tests/fixtures/calendar-fixtures.ts prints four weeks, in big days:
AgentGuard calendar: tokens per day, Aug 30 to Sep 26, 2026
696,040 tokens · $7.29 at API prices, not a bill
busiest day: Sep 24 (511,040 tokens) · sub-agents used 7.3% of tokens
AgentGuard held 2 launches
Sep
Su ·· ·· ··
Mo ·· ▓s ··
Tu ░░ ·· ·· ··
We ·· ▒▒ █H ··
Th ·· ·· ·· ██
Fr ·· ·· ·· ··
Sa ·· ·· ·· ▒▒
Less ·· ░░ ▒▒ ▓▓ ██ More
Days marked s: sub-agents used more than half of that day's tokens.
Days marked H: AgentGuard held a launch that day.
From Claude Code and Codex sessions on this machine, sub-agents included.
Claude Code deletes sessions older than 30 days by default.
Burn keeps each day's count whenever you run this, so the calendar grows.
Next: see where one session's tokens went: npx agentguard-burn whyThe last line is the one next step, chosen the way why chooses its tip: when sub-agents took a fifth or more of the tokens it points at the free plugin (or, once AgentGuard has held launches on this machine, at giving related work to one sub-agent); otherwise it points at why, which names the change for one session.
Claude Code deletes transcripts after 30 days by default (cleanupPeriodDays), so each run keeps a daily count per transcript file in calendar/daily.json under the Burn home (AGENTGUARD_HOME, default ~/.agentguard): tokens, sub-agent tokens and dollars per day, with no paths and no content, owner-only and written atomically. A transcript still on disk is always counted from the transcript; a deleted transcript's days come from the daily count; no file-day is counted from both. Run calendar at least once within Claude Code's retention period to keep every day. calendar/cache.json keeps each response's counts, keyed by the transcript's path digest, size and modification time, so a later run re-reads only the transcripts that changed; a new Burn version or a pricing override recounts everything once.
calendar json is never translated: every day of the span with its figures and level, the totals, the busiest day and where the figures came from. --lang es|pt and your locale choose the language exactly as for why. Nothing in the calendar compares you with anyone else.
Share card
agentguard-burn card
agentguard-burn card --weeks 1 --out this-week.pngOne 1200 by 675 PNG with the calendar's totals, made to post: the token total with the Claude Code and Codex split, the dollars at API prices (not a bill), the share sub-agents used, the busiest day, the sub-agent launches AgentGuard held (or the transcripts read, when it held none) and one bar per day in whole weeks. --weeks N takes 1 to 53 and defaults to 4. The image is saved as agentguard-burn-card.png in the current folder unless --out names another file. It is drawn on your machine from the same figures calendar prints; no project, prompt or file name appears on it, and nothing is uploaded. A span with no recorded usage is refused.
Two safety planes
Structural limits use active time rather than the age of the session. The lifetime spawn count warns at 24 but cannot stop a session on its own. The fan-out ceiling permits 40 spawns within the last 120 active minutes and stops the next proposal. The separate spawn-rate rule warns at 8 and stops candidate 16 within 15 active minutes. Depth above 2 still stops.
Economic limits warn at 3.5B and stop at 5B measured tokens per session. Repeated Claude assistant content blocks share one provider response id. Their usage and copied child history count once, including later increases to a response's recorded usage. Old session counters rebuild once from the parent and its available child transcripts, retaining the signed chain head. The rebuild places events chronologically. A child usage record discovered late on a later hook enters the current active-minute bucket, while session and bucket totals remain conserved. The same numeric sustained thresholds now fire later because inflated usage has been removed. Earlier replay figures in the changelog used the old counts.
Existing policy files keep explicit settings. Missing fields are filled in
memory, with a one-time notice. In particular, an old explicit
spawnRate.enforce: false remains advisory until you change it. New policies
default to true; fanout.windowActiveMinutes defaults to 120. Run calibration
only when you want it to write a new shadow policy, or set AGENTGUARD_HOME
to a scratch directory to review fitted values first.
Price a recorded block
agentguard-burn blocks
agentguard-burn blocks SESSION_ID
agentguard-burn blocks allEach WARN or STOP receipt gets one row with its time, session, detector reasons and spawn ordinal. The row includes the session's available child count, median and maximum tokens, and median and maximum API list-price dollars per child. Forks and fresh agents are reported separately. The report reuses the attribution parser and excludes copied provider responses. It reads recorded usage only and makes no network calls.
These are list-price equivalents, not a bill or a claim of money saved.
Economics describe the currently available child transcripts of that session,
not only the children completed before the receipt. Missing child history or
unknown model pricing stays unavailable. Unknown cache lifetimes produce a
price range. A fork is identified by its transcript's fork metadata. Codex child discovery
requires an explicit parent thread id; unknown inherited-history boundaries
stay unavailable. Use blocks all json for structured output. Session
attribution uses local receipt identifiers without copying transcript content
into the ledger.
Local limits and shadow exposure
agentguard-burn limits
agentguard-burn limits SESSION_ID
agentguard-burn limits all
agentguard-burn price-shadow
agentguard-burn price-shadow SESSION_ID
agentguard-burn price-shadow allBoth commands are read-only. They read the existing local host transcripts and
Burn ledgers, use no network or data plane, and do not load or change policy,
create receipts, or record frames. A session can also be a local transcript
path. Append json for structured arithmetic.
limits reports Claude Code plan-window rejections and allowed warnings, plus
HTTP 429 rate-limit errors. Each event shows its recorded time, window, reset,
model when present, and the closest earlier Burn WARN or STOP in that session.
The rollup counts rejected events, not allowed warnings. Reset durations use
the union of overlapping rejection-to-reset intervals, including across
sessions, so retries and shared windows do not multiply minutes. This is the
time until the recorded reset, not a measurement of time unable to work. An
absent reset stays unknown. Fan-out means a fanout, spawn_rate or depth finding
within the preceding 60 minutes. Proximity is correlation. Codex limits remain
unsupported until a verified transcript format is available.
price-shadow prices every explicitly recorded shadow decision using the
shipped API list snapshot, including OK and WARN rows. It includes only children
whose recorded start is strictly after that decision. Claude starts come from
the child's own sidechain user event or a timestamped fork marker; Codex starts
come from session metadata with explicit parent lineage. Existing children
that continue running after a decision do not enter its cohort. Copied parent
responses are excluded; provider response ids reconcile streaming updates and
copies across child transcripts. Medians and maxima use each child's full
available usage. Unknown starts, missing transcripts, unresolved spawn results
and unknown inherited-history boundaries are unpriced. Nothing is imputed.
Decision cohorts overlap. Totals use only the first would-block point per session and label the resulting list-price exposure an upper bound. A known priced subset is separate from an unpriced total. Fable 5.1 and Sonnet 5 reprice the same recorded token categories as sensitivity, never measurement. Unknown cache-write lifetimes produce a range. Dollars are list-price equivalents, not the bill. Neither command changes enforcement.
Cache-read ratio was about 98% in the original calibration, healthy and pathological alike. It is shown as an explanation and never used to decide.
Start with replay, not with the hook
npx @agentguard-run/burn replayRuns the detectors over your existing history and shows what enforcement would have intercepted, when, and the observed tail after each stop. It is an upper bound, labelled as such. Nobody installs a blocker cold.
Optional global install and hooks
A global install pins an old version: npx agentguard-burn why can keep using that global command instead of downloading a newer Burn. To run the latest release explicitly, use npx agentguard-burn@latest why. If you previously installed the scoped package globally, remove it with npm rm -g @agentguard-run/burn; for the wrapper, use npm rm -g agentguard-burn.
npm i -g @agentguard-run/burn
agentguard-burn init --write # merge the hook into ~/.claude/settings.json (backup taken)
agentguard-burn init codex --write # same for ~/.codex/hooks.json
agentguard-burn status # hook health, shadow observations, every live session
agentguard-burn enforce # after 7 days and 50 decisionsWithout the write flag, agentguard-burn init claude and agentguard-burn init codex print hook configuration for review. Merge the relevant snippet into your host configuration. For Codex, review and trust the hook through /hooks. Upgrading an existing hook requires the new snippet: it matches every tool so pace can update on ordinary tool calls, while admission still gates spawns.
The hook installs in shadow mode: every decision is recorded, nothing is
blocked, until you have seen it be right. status shows what it would have
done so far, which sessions are live on every host, and whether each hook's
command still exists on disk (a hook whose script is gone fails open, and
status says so in capitals).
When it stops you and you disagree
In an interactive Claude Code session (Manua
