npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@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.

Readme

@agentguard-run/burn

npx agentguard-burn why

See 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 share

Press 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 out

install 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,codex or --skip hermes chooses hosts (claude, codex, cursor, hermes).
  • --json prints the plan, and after --yes each host's result, for an agent to read. An agent shows the plan to its person and runs --yes only 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.json or ~/.claude/settings.json is 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-status in a Claude Code or Codex session, agentguard-burn status for Cursor, /agentguard status in Hermes. The mode install prints is read from local files; a paid license whose check fails falls back to shadow, which only agentguard-status can 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 run agentguard-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 es

See 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:

  1. 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.
  2. 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 --commits stays local. Manager per-seat detail is shares and cause only, with no absolute tokens or dollars.
  3. Copy describes where tokens went and what to change, never rates the person. A seat is one machine, not a person.
  4. Only the person changes weekly sharing, locally in the plugin: off by default, totals for team totals only, or seat for 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.
  5. 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 --json

Omit 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.gif

The 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.json

The 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 --rank

Only --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 reap

ps 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 ps

The 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 json

A 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 json

ttl 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 json

Compare 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 pricing

A 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, or model: haiku in 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 /compact before a break. Reloads from switching models: how many, and switching at a break right after /compact. Any other reload cause: the dollars and agentguard-burn rewrites.
  • The conversation re-read on every message: its median per message, and /compact at a natural break or /clear between 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 --commits

why 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's session_meta and turn_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-dir to find the repository (for this session, and for each other directory found running at the same time), then one git 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-by trailer 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 appends Co-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 of why; a Codex sub-agent keeps its own rollout, which why reads 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, or by 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 says tokens per landed commit. why json carries both, tokensPerCoAuthoredCommit (null when the agents co-authored none) and tokensPerLandedCommit, and perCommitBasis (coAuthored or landed) 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 json

Run 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 json

Every 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 why

The 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.png

One 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 all

Each 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 all

Both 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 replay

Runs 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 decisions

Without 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