{"_id":"@agentguard-run/burn","_rev":"6-ffd7c1ac56804e16cde0295bf57d24f9","name":"@agentguard-run/burn","dist-tags":{"latest":"0.2.3"},"versions":{"0.1.0":{"name":"@agentguard-run/burn","version":"0.1.0","keywords":["agentguard","claude-code","agents","token-budget","circuit-breaker","runaway","fan-out"],"license":"SEE LICENSE IN LICENSE","_id":"@agentguard-run/burn@0.1.0","maintainers":[{"name":"john-mg","email":"john@merchantguard.ai"}],"bin":{"agentguard-burn":"dist/src/cli.js"},"dist":{"shasum":"c2de1fb5fb60258164614f8364ab7477ec80132f","tarball":"https://registry.npmjs.org/@agentguard-run/burn/-/burn-0.1.0.tgz","fileCount":27,"integrity":"sha512-rUSy0sTWBQqBeIMmPBA833Dw4BfHzjMYMlAyfpYTwstHLIR+cjdntk5RjEvhPj1O3p5cLU6jIEKB4XzyPDeVhQ==","signatures":[{"sig":"MEUCIE/2sYdhrqRxuo3QpfWtNqoBuq4mWXjnR4jjDcgSRp4+AiEAgX7wkBPUSHnpjAVfDgRrG6JZ+9iuEG6fzCOMbPDYzwo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":102558},"main":"dist/src/index.js","type":"commonjs","types":"dist/src/index.d.ts","engines":{"node":">=20.0.0"},"gitHead":"f9713c07384f83bbdbbdb9ae2af5f102a55e1155","scripts":{"test":"tsc -p tsconfig.json && node --test \"dist/tests/**/*.test.js\"","build":"tsc -p tsconfig.json","replay":"node dist/cli.js replay","typecheck":"tsc -p tsconfig.json --noEmit"},"_npmUser":{"name":"john-mg","email":"john@merchantguard.ai"},"_npmVersion":"10.9.2","description":"Local runaway-agent circuit breaker for AI coding agents. Detects fan-out storms and sustained token burn, blocks the next spawn, and proves what happened. Nothing leaves the machine.","directories":{},"_nodeVersion":"22.17.1","dependencies":{"@noble/ed25519":"^3.0.0"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.0.0","@types/node":"^22"},"_npmOperationalInternal":{"tmp":"tmp/burn_0.1.0_1788442635937_0.5229765878149413","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@agentguard-run/burn","version":"0.1.1","keywords":["agentguard","claude-code","agents","token-budget","circuit-breaker","runaway","fan-out"],"license":"SEE LICENSE IN LICENSE","_id":"@agentguard-run/burn@0.1.1","maintainers":[{"name":"john-mg","email":"john@merchantguard.ai"}],"bin":{"agentguard-burn":"dist/src/cli.js"},"dist":{"shasum":"7558e8a3281c0779eb18881d5531b22add938574","tarball":"https://registry.npmjs.org/@agentguard-run/burn/-/burn-0.1.1.tgz","fileCount":27,"integrity":"sha512-xWtkzovTNCr6Y40c6f2lHJufyiQIjY6ASvZieLVu+8SpSpRN6ZCxEhQ5qSJPbckG/lFMiYpmj/jzrsgI9qTXaQ==","signatures":[{"sig":"MEUCIQCufJDaNQKON0H1bWaIea2qZ0MPgwRk8Ymj+n4JbxoSqAIgbyj/k+JeQ9CxGnSNvRzJHJX3hLdy3yLfh2rYIjlc4GQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":110435},"main":"dist/src/index.js","type":"commonjs","types":"dist/src/index.d.ts","engines":{"node":">=20.0.0"},"gitHead":"d3de36d33aa06adfcd24e7db4b47a11063d8fbe4","scripts":{"test":"tsc -p tsconfig.json && node --test \"dist/tests/**/*.test.js\"","build":"tsc -p tsconfig.json","replay":"node dist/cli.js replay","typecheck":"tsc -p tsconfig.json --noEmit"},"_npmUser":{"name":"john-mg","email":"john@merchantguard.ai"},"_npmVersion":"10.9.2","description":"Local runaway-agent circuit breaker for AI coding agents. Detects fan-out storms and sustained token burn, blocks the next spawn, and proves what happened. Nothing leaves the machine.","directories":{},"_nodeVersion":"22.17.1","dependencies":{"@noble/ed25519":"^3.0.0"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.0.0","@types/node":"^22"},"_npmOperationalInternal":{"tmp":"tmp/burn_0.1.1_1788446261852_0.1848074600767342","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@agentguard-run/burn","version":"0.2.0","keywords":["agentguard","claude-code","cursor","codex","ollama","vllm","agents","token-budget","circuit-breaker","runaway","fan-out"],"license":"SEE LICENSE IN LICENSE","_id":"@agentguard-run/burn@0.2.0","maintainers":[{"name":"john-mg","email":"john@merchantguard.ai"}],"bin":{"agentguard-burn":"dist/src/cli.js"},"dist":{"shasum":"de0ba35b44d1adffb8eb70473fb3cc8268993f35","tarball":"https://registry.npmjs.org/@agentguard-run/burn/-/burn-0.2.0.tgz","fileCount":50,"integrity":"sha512-iaLxL3O0gRcKvMGUrOiTKqMGPObzwdLAtTsND9cJy56Fn1HXUAacKp8Hfk0lBAFW9lcKLMFHr0fmhZpp/VHApA==","signatures":[{"sig":"MEYCIQC0VC6hq7eHNFT80Ld/j8rIkOvRr1bgn8s/3h3M3i4JqgIhANy0aEURQtBOuF5ZW5XQTwiXpKT1K6nghsL99krTK+87","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":255361},"main":"dist/src/index.js","type":"commonjs","types":"dist/src/index.d.ts","engines":{"node":">=20.0.0"},"exports":{".":{"types":"./dist/src/index.d.ts","default":"./dist/src/index.js"},"./codex":{"types":"./dist/src/adapters/codex.d.ts","default":"./dist/src/adapters/codex.js"},"./proxy":{"types":"./dist/src/proxy/server.d.ts","default":"./dist/src/proxy/server.js"},"./cursor":{"types":"./dist/src/adapters/cursor.d.ts","default":"./dist/src/adapters/cursor.js"},"./middleware":{"types":"./dist/src/adapters/raw-api.d.ts","default":"./dist/src/adapters/raw-api.js"},"./package.json":"./package.json"},"gitHead":"082c926ee7c2b143f9cc91d176141b6c6a6d981c","scripts":{"test":"tsc -p tsconfig.json && node --test \"dist/tests/**/*.test.js\"","build":"tsc -p tsconfig.json","replay":"node dist/src/cli.js replay","typecheck":"tsc -p tsconfig.json --noEmit","conformance":"tsc -p tsconfig.json && node dist/src/cli.js conformance"},"_npmUser":{"name":"john-mg","email":"john@merchantguard.ai"},"_npmVersion":"10.9.2","description":"Local runaway-agent circuit breaker for AI coding agents and local model runtimes. One policy across Claude Code, Cursor, Codex, Ollama, vLLM, LM Studio and raw orchestrators: detects fan-out storms and sustained token burn, blocks the next spawn, and pro","directories":{},"_nodeVersion":"22.17.1","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.0.0","@types/node":"^22"},"_npmOperationalInternal":{"tmp":"tmp/burn_0.2.0_1788479437336_0.658774665477597","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@agentguard-run/burn","version":"0.2.1","keywords":["agentguard","claude-code","cursor","codex","ollama","vllm","agents","token-budget","circuit-breaker","runaway","fan-out"],"license":"SEE LICENSE IN LICENSE","_id":"@agentguard-run/burn@0.2.1","maintainers":[{"name":"john-mg","email":"john@merchantguard.ai"}],"bin":{"agentguard-burn":"dist/src/cli.js"},"dist":{"shasum":"5d182faf1f73653a45d9e203252e5eb6a37b4751","tarball":"https://registry.npmjs.org/@agentguard-run/burn/-/burn-0.2.1.tgz","fileCount":55,"integrity":"sha512-tUbTN0dqYCch8Abf9xtgHrUzqparYyPUKcHVTnqy/vqKfaIz2YDS7oeADyPGVyvOpQL+m9ubnURFcvjTo/v2CA==","signatures":[{"sig":"MEUCIDruJvp2BKmp6A44HBJoNdhqpLV0AkCyvTOrg/XWhs6fAiEAuq/QoFgcpu9bdyvYs5311MM8j2HCITunJ3iVq/Vctv4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":283643},"main":"dist/src/index.js","type":"commonjs","types":"dist/src/index.d.ts","engines":{"node":">=20.0.0"},"exports":{".":{"types":"./dist/src/index.d.ts","default":"./dist/src/index.js"},"./codex":{"types":"./dist/src/adapters/codex.d.ts","default":"./dist/src/adapters/codex.js"},"./proxy":{"types":"./dist/src/proxy/server.d.ts","default":"./dist/src/proxy/server.js"},"./cursor":{"types":"./dist/src/adapters/cursor.d.ts","default":"./dist/src/adapters/cursor.js"},"./middleware":{"types":"./dist/src/adapters/raw-api.d.ts","default":"./dist/src/adapters/raw-api.js"},"./package.json":"./package.json"},"gitHead":"4d8b06b37ac6617b5332cbc41bddacab4a5ba68c","scripts":{"test":"tsc -p tsconfig.json && node --test \"dist/tests/**/*.test.js\"","build":"tsc -p tsconfig.json","replay":"node dist/src/cli.js replay","typecheck":"tsc -p tsconfig.json --noEmit","conformance":"tsc -p tsconfig.json && node dist/src/cli.js conformance"},"_npmUser":{"name":"john-mg","email":"john@merchantguard.ai"},"_npmVersion":"10.9.2","description":"Local runaway-agent circuit breaker for AI coding agents and local model runtimes. One policy across Claude Code, Cursor, Codex, Ollama, vLLM, LM Studio and raw orchestrators: detects fan-out storms and sustained token burn, blocks the next spawn, and pro","directories":{},"_nodeVersion":"22.17.1","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.0.0","@types/node":"^22"},"_npmOperationalInternal":{"tmp":"tmp/burn_0.2.1_1788482132971_0.07693422005144712","host":"s3://npm-registry-packages-npm-production"}},"0.2.2":{"name":"@agentguard-run/burn","version":"0.2.2","keywords":["agentguard","claude-code","cursor","codex","ollama","vllm","agents","token-budget","circuit-breaker","runaway","fan-out"],"license":"SEE LICENSE IN LICENSE","_id":"@agentguard-run/burn@0.2.2","maintainers":[{"name":"john-mg","email":"john@merchantguard.ai"}],"bin":{"agentguard-burn":"dist/src/cli.js"},"dist":{"shasum":"d81706b306e42b215aa217d68d65e5aa420527ea","tarball":"https://registry.npmjs.org/@agentguard-run/burn/-/burn-0.2.2.tgz","fileCount":55,"integrity":"sha512-Cjq/ypumlQNnldxoC0aD/EsyEonl0ntqC2jWYE6KazNYK1gP578bL7yVOr0XhUqO1FBCn74OfpiqhQ9xiG17mg==","signatures":[{"sig":"MEQCIDOk8zXlEFuKSwjxObaQNWELdADXwPyswAyIDOR9bB3sAiAJ41VByjI+JwWvYQTzmusqZORKDtcKYIUw+I5BtsFT/w==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":285075},"main":"dist/src/index.js","type":"commonjs","types":"dist/src/index.d.ts","engines":{"node":">=20.0.0"},"exports":{".":{"types":"./dist/src/index.d.ts","default":"./dist/src/index.js"},"./codex":{"types":"./dist/src/adapters/codex.d.ts","default":"./dist/src/adapters/codex.js"},"./proxy":{"types":"./dist/src/proxy/server.d.ts","default":"./dist/src/proxy/server.js"},"./cursor":{"types":"./dist/src/adapters/cursor.d.ts","default":"./dist/src/adapters/cursor.js"},"./middleware":{"types":"./dist/src/adapters/raw-api.d.ts","default":"./dist/src/adapters/raw-api.js"},"./package.json":"./package.json"},"gitHead":"0079be8094795abd3c4010fe711b16cf6d0833de","scripts":{"test":"tsc -p tsconfig.json && node --test \"dist/tests/**/*.test.js\"","build":"tsc -p tsconfig.json","replay":"node dist/src/cli.js replay","typecheck":"tsc -p tsconfig.json --noEmit","conformance":"tsc -p tsconfig.json && node dist/src/cli.js conformance"},"_npmUser":{"name":"john-mg","email":"john@merchantguard.ai"},"_npmVersion":"10.9.2","description":"Local runaway-agent circuit breaker for AI coding agents and local model runtimes. One policy across Claude Code, Cursor, Codex, Ollama, vLLM, LM Studio and raw orchestrators: detects fan-out storms and sustained token burn, blocks the next spawn, and pro","directories":{},"_nodeVersion":"22.17.1","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.0.0","@types/node":"^22"},"_npmOperationalInternal":{"tmp":"tmp/burn_0.2.2_1788483225046_0.42485736867632107","host":"s3://npm-registry-packages-npm-production"}},"0.2.3":{"_id":"@agentguard-run/burn@0.2.3","bin":{"agentguard-burn":"dist/src/cli.js"},"dist":{"shasum":"e56011fc235883a44898c9460e16a53d2e47f693","tarball":"https://registry.npmjs.org/@agentguard-run/burn/-/burn-0.2.3.tgz","fileCount":57,"integrity":"sha512-9Y2L+L7YHmi7yQafb16Rbv3lRuUZD/QAWaL5g2oMH/6kAFYKQuHM4Sf/Fy9s93KLMPtrlrkbdiaXZt987AdOtw==","signatures":[{"sig":"MEUCIQDgQdYUJ6o09IfB1d3pGXrSoPEolesGd6aQhfqVaHSDZQIge3bDZurkuE+uJma8eZfLCY3+pchCvj3uBcJlFiay0GE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIGCg6PW1AXHagGogvFHHtY4T4VpxDDdA/wRrSV2Ef9hQAiEAzdtGcu4fRfO9w2Jinrl8Nd8njKT5vI0ahFSpocIVS28="}],"unpackedSize":294641},"main":"dist/src/index.js","name":"@agentguard-run/burn","type":"commonjs","types":"dist/src/index.d.ts","engines":{"node":">=20.0.0"},"exports":{".":{"types":"./dist/src/index.d.ts","default":"./dist/src/index.js"},"./codex":{"types":"./dist/src/adapters/codex.d.ts","default":"./dist/src/adapters/codex.js"},"./proxy":{"types":"./dist/src/proxy/server.d.ts","default":"./dist/src/proxy/server.js"},"./cursor":{"types":"./dist/src/adapters/cursor.d.ts","default":"./dist/src/adapters/cursor.js"},"./middleware":{"types":"./dist/src/adapters/raw-api.d.ts","default":"./dist/src/adapters/raw-api.js"},"./package.json":"./package.json"},"gitHead":"14071c3fa91c8815a01a092493dcc26f92618834","license":"SEE LICENSE IN LICENSE","scripts":{"test":"tsc -p tsconfig.json && node --test \"dist/tests/**/*.test.js\"","build":"tsc -p tsconfig.json","replay":"node dist/src/cli.js replay","typecheck":"tsc -p tsconfig.json --noEmit","conformance":"tsc -p tsconfig.json && node dist/src/cli.js conformance"},"version":"0.2.3","_npmUser":{"name":"john-mg","email":"john@merchantguard.ai"},"keywords":["agentguard","claude-code","cursor","codex","ollama","vllm","agents","token-budget","circuit-breaker","runaway","fan-out"],"_npmVersion":"10.9.2","description":"Local runaway-agent circuit breaker for AI coding agents and local model runtimes. One policy across Claude Code, Cursor, Codex, Ollama, vLLM, LM Studio and raw orchestrators: detects fan-out storms and sustained token burn, blocks the next spawn, and pro","directories":{},"maintainers":[{"name":"john-mg","email":"john@merchantguard.ai"}],"_nodeVersion":"22.17.1","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.0.0","@types/node":"^22"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/burn_0.2.3_1789662781317_0.07191672885020317"}}},"time":{"created":"2026-09-03T13:37:15.684Z","modified":"2026-09-17T16:33:01.595Z","0.1.0":"2026-09-03T13:37:16.071Z","0.1.1":"2026-09-03T14:37:41.998Z","0.2.0":"2026-09-03T23:50:37.517Z","0.2.1":"2026-09-04T00:35:33.132Z","0.2.2":"2026-09-04T00:53:45.275Z","0.2.3":"2026-09-17T16:33:01.410Z"},"license":"SEE LICENSE IN LICENSE","keywords":["agentguard","claude-code","cursor","codex","ollama","vllm","agents","token-budget","circuit-breaker","runaway","fan-out"],"description":"Local runaway-agent circuit breaker for AI coding agents and local model runtimes. One policy across Claude Code, Cursor, Codex, Ollama, vLLM, LM Studio and raw orchestrators: detects fan-out storms and sustained token burn, blocks the next spawn, and pro","maintainers":[{"name":"john-mg","email":"john@merchantguard.ai"}],"readme":"# @agentguard-run/burn\n\nLocal runaway-agent circuit breaker for AI coding agents.\n\nRaw token counters did not help. You see \"360k tokens\" and keep going. This\ntool does the three things a counter does not: it decides whether a session is\npathological, it blocks the next agent spawn when it is, and it tells you what\nto do about it. Nothing leaves the machine.\n\n## Two safety planes\n\nOriginally fitted against 412 real Claude Code sessions, then replayed on\n2026-09-15 against 438 sessions. The history shows two independent\nfailure shapes that one detector cannot cover:\n\n| Plane | Catches | Rule | Validated on |\n|---|---|---|---|\n| Structural | fan-out storms: many agents re-sending context | WARN 24 spawns, STOP before spawn 41, no agents-spawning-agents past depth 2 | 59-, 190- and 226-spawn sessions; the 190-spawn session has a 4.35B post-STOP tail (92%) |\n| Economic | slow grinds: few agents, enormous total | WARN 3.5B, STOP 5B tokens per session | the 9.15B / 26-spawn session the spawn cap could not see |\n\nThe 2026-09-15 replay snapshot: **4 STOP, 3 WARN, 431 clean across 438\nsessions and 616 spawns**. Replay hero: **32%** — **10.27B** of **32.58B**\nobserved tokens came after a STOP boundary; API-list scenario **$4,639**.\nThis is an upper bound assuming no override or restart. Replay does not label\nfalse positives. Active histories can change the next replay result.\n\nCache-read ratio was about 98% in the original calibration, healthy and pathological alike. It\nis shown as an explanation and never used to decide.\n\n## Start with replay, not with the hook\n\n```\nnpx @agentguard-run/burn replay\n```\n\nRuns the detectors over your existing history and shows what enforcement would\nhave intercepted, when, and the observed tail after each stop. It is an upper\nbound, labelled as such. Nobody installs a blocker cold.\n\n```\nnpm i -g @agentguard-run/burn\nagentguard-burn init --write          # merge the hook into ~/.claude/settings.json (backup taken)\nagentguard-burn init codex --write    # same for ~/.codex/hooks.json\nagentguard-burn status                # hook health, shadow observations, every live session\nagentguard-burn enforce               # after 7 days and 50 decisions\n```\n\nThe hook installs in **shadow mode**: every decision is recorded, nothing is\nblocked, until you have seen it be right. `status` shows what it would have\ndone so far, which sessions are live on every host, and whether each hook's\ncommand still exists on disk (a hook whose script is gone fails open, and\n`status` says so in capitals).\n\n### When it stops you and you disagree\n\n```\nagentguard-burn resume --once --reason \"these 60 agents are the plan\"   # the next STOP passes, once, on any host\nagentguard-burn resume --reason \"load test\"                              # every STOP passes for 15 minutes\nagentguard-burn resume --clear\n```\n\nEvery override is written to the decisions ledger with its reason. A\n`--once` override is consumed atomically: two hooks racing for it cannot\nboth pass. Warnings are spoken once per change in the finding set, not once\nper spawn; eighteen identical banners train you to stop reading the\nnineteenth.\n\n## One policy across hosts (0.2.0)\n\nThe detectors never learn which host produced an event. Claude Code, Cursor,\nCodex, a local model runtime behind the proxy, and an orchestrator calling\nthe middleware all normalise into the same event stream, share one\nmachine-wide reservation lock, and sign the same receipt. The same failure,\nthrough every door, stops at the same step: `agentguard-burn conformance`\nreplays a 42-spawn storm and a 250M-token-per-call grind through each adapter\nand asserts fan-out WARN at 24, STOP at 41, sustained WARN at 3.5B, STOP at\n5B.\n\nWhat each host can actually see is stated, not implied:\n\n| Host | Spawns | Depth | Usage | How |\n|---|---|---|---|---|\n| Claude Code | authoritative | authoritative | authoritative | PreToolUse hook + transcript (unchanged from 0.1) |\n| Raw middleware | authoritative | authoritative | authoritative | `beforeSpawn` / `beforeCall` leases in your orchestrator |\n| Ollama proxy | none | none | authoritative | `prompt_eval_count` + `eval_count` on the final chunk |\n| vLLM / LM Studio / OpenAI-compatible proxy | none | none | authoritative when the server sends `usage`, else reported missing | non-streaming `usage`, or the final SSE usage event |\n| Cursor (beta) | authoritative | estimated | none | native `subagentStart` deny; hosted-model usage is never exposed |\n| Codex (beta) | authoritative | estimated | estimated | `PreToolUse` on `spawn_agent`; live deny, allow and override canary passed on codex-cli 0.151.0; transcript parsed best-effort |\n\nAn `OK` from a host that cannot see usage is an OK about spawns, and `status`\nsays `usage:n/a` next to it. Missing usage never becomes a guessed zero.\n\nThe full claim, \"40 spawns, depth 2, 5B tokens, enforced identically\", is true\nfor a deployment that feeds both a topology source and a usage source into one\nsession ID: raw middleware plus the proxy, for instance. A proxy alone sees\ntokens and no tree. A Cursor hook alone sees the tree and no tokens. The\ncomposite conformance check proves the combined case: candidate spawn 41 sees\nboth planes in its findings.\n\n### Local models: the compute plane\n\nToken dollars are close to meaningless when the GPU is yours. What runs away\nis the machine: concurrency and occupied request time. The proxy tracks both\nand warns at 4 concurrent calls by default. No universal STOP ships for\nhardware we cannot see; set `localCompute.stopConcurrent` or\n`stopOccupiedMs` in `burn-policy.json` for your server. Elapsed request time\nincludes queueing and transport, so it is called occupied time, never GPU\nutilisation.\n\n```\nagentguard-burn proxy --upstream http://127.0.0.1:11434 --host ollama\n# point the agent at http://127.0.0.1:18080 and send x-agentguard-session: <id>\n```\n\nLoopback only, both sides, by default. Every upstream chunk is written to the\nclient before it is inspected; the observer is a side channel, never a data\npath. A STOP answers the *next* request with 429 and the alarm box. It never\ncuts a stream that is already flowing, and it never kills a running agent.\nBlocking is not killing.\n\n### Raw middleware\n\n```ts\nimport { createRawApiGuard } from '@agentguard-run/burn/middleware';\nconst burn = createRawApiGuard({ sessionId: 'nightly-refactor-17' });\n\nconst spawn = burn.beforeSpawn({ parentDepth: 0 });\nspawn.throwIfBlocked();\nspawn.started();\ntry { await worker() } finally { spawn.finished() }\n\nconst call = burn.beforeCall({ estimatedTokens: 120_000 });\ncall.throwIfBlocked();\ntry {\n  const res = await client.chat({ ..., headers: call.headers });   // proxy correlates by call id\n  call.complete({ tokens: res.usage.total_tokens });\n} catch (e) { call.fail(); throw e }\n```\n\nUsage is committed by call ID and *replaces* what was reserved under it.\nWhen middleware estimated 120K and the proxy later saw 87K for the same call,\nthe session moves by 87K, not 207K.\n\n### Cursor and Codex\n\n```\nagentguard-burn init cursor    # ~/.cursor/hooks.json snippet, failClosed on\nagentguard-burn init codex     # ~/.codex/hooks.json snippet\n```\n\nBoth renderers are one page each and emit only their host's documented output\nobject. Codex fails the whole hook on Claude's common fields (`continue`,\n`stopReason`, `suppressOutput`), and a failed hook is a fail-open hook, so the\nCodex renderer never emits them and a test forbids them by name.\n\n**Codex** passed a live canary on the installed codex-cli 0.151.0 on\n2026-09-03: a `spawn_agent` call was denied with the alarm box as the reason,\na shell call passed untouched, and a `resume --once` override let the next\nspawn through with the reason on the ledger. Two things the docs got wrong\nand the wire settled: the tool arrives as `spawn_agent` (the docs say it\n\"matches as Agent\"; the matcher covers both), and project-local hooks only\nload when the project is trusted. The captured payloads are in\n`fixtures/codex-0.151.0-pretooluse.json` and drive a test.\n\nOne step Codex makes you do by hand: after `init codex --write`, open\n`codex`, run `/hooks`, and trust the AgentGuard hook. Codex requires this\nonce per hook source, and there is no CLI for it. Until it is done,\n`codex exec` stalls the first time a spawn would be gated (verified: it\nhangs with no output; the same with hooks defined in `config.toml`).\n`status` repeats this under the codex line because it cannot see whether\ntrust was granted.\n\n**Cursor** is verified against the documented schema (`permission`,\n`user_message`, `agent_message`; `~/.cursor/hooks.json` with `failClosed`),\nnot yet against an installed build. It stays beta until a live deny canary\npasses.\n\n### Receipts\n\nEvery spawn decision, and every model call that is not OK, is signed with a\nlocal Ed25519 key (Node built-ins, key generated on first use, 0600) and\nchained to the previous receipt for the session. A receipt carries the host,\nthe coverage, the counts, the verdict, the policy digest and a hash of the\nsession ID. It carries no prompt, completion, path, or tool input. It can\nleave the machine when a transcript never can.\n\n## The concurrency guarantee\n\nTen parallel `Agent` calls launch ten hook processes that all read the same\ntranscript and all see the same count. A naive cap is cosmetic during exactly\nthe burst it exists for. Spawns are admitted through an atomic, cross-process\nreservation under a machine-wide lock; the test suite launches 60 real OS\nreservation processes against a cap of 40 and asserts exactly 40 are admitted,\nand separately exercises 60 Cursor hook processes. The opt-in stress test runs\n240 actual Claude hook processes against cap 40:\n\n```sh\nnpm run build\nAGENTGUARD_STRESS=1 node --test dist/tests/stress.test.js\n```\n\nIt checks exactly 40 admitted and 200 denied, verifies the receipt chain for\ncoordinated decisions, and reports lock failures separately. Infrastructure\nfailures deny in enforce mode before a receipt can be chained, as in the gateway.\n\n0.2.0 fixed the lock itself. Under 240 concurrent hook processes the 0.1\nlock could tear down a live sibling's lock (a waiter judged \"owner is dead\"\nabout an instance that had already been released and replaced) and admit\n41 to 46. Lock instances now carry a nonce; a reclaim only counts if it\ngrabbed the instance it judged, and every write is fenced on the holder's\nown nonce still being on the path. In 0.2.3, bounded, staggered retries prevent\nlock waiters from starving the holder. The Sep 15 audit includes one successful\n240-process run after that fix; it does not establish a 192-run guarantee.\n\nSingle-machine by design. Two laptops on one account do not share state, and\nthat is stated rather than hidden.\n\n## Account thresholds\n\n`account.warnConcurrentSessions` warns when more than that many sessions have\nbeen active on this machine in the last 30 minutes, matching `status` liveness.\nOptional `account.warnTokens` and `account.stopTokens` sum the last\n`account.windowActiveMinutes` of token buckets from each active session.\nBoth token limits default to `null`. Closed gateway sessions are excluded;\nhook and gateway session files are both read. WARN never blocks. STOP records\na would-block decision in shadow and blocks new work only in enforce mode.\n\n## What it never does\n\nNo prompts, responses, file contents, or tool inputs are persisted or rendered.\nNo telemetry. No provider-quota guesses: it projects against your configured\npolicy, never against a subscription allowance it cannot see.\n","readmeFilename":"README.md"}