{"_id":"@adhd/agent-plugin-budget","_rev":"8-b8c47d854f02a46836edbe8a5fa3475d","name":"@adhd/agent-plugin-budget","dist-tags":{"latest":"0.2.0"},"versions":{"0.0.2":{"name":"@adhd/agent-plugin-budget","version":"0.0.2","_id":"@adhd/agent-plugin-budget@0.0.2","maintainers":[{"name":"pseudosky","email":"skywinston.sk@gmail.com"}],"dist":{"shasum":"9eb22e816e4f42207ed8970d2bec1c4c8722c2b6","tarball":"https://registry.npmjs.org/@adhd/agent-plugin-budget/-/agent-plugin-budget-0.0.2.tgz","fileCount":6,"integrity":"sha512-MSmEiSMtaqQ15m+Sx6qUWnP/Cegf8IE2u4wihXxkchGDlWMnxDQ7HICcKAfb8GmtgolaJ5isozIueyZN16NRJg==","signatures":[{"sig":"MEQCIFivt1G60XdMNexo2pId+I8MqlotSK9Uyx1LFZA/JM9UAiBGkAglPHsUYBgcXXpwHFuJ0ncFXqToLcMGOxOt8nENrw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":51885},"main":"./index.cjs","type":"module","module":"./index.js","exports":{".":{"types":"./index.d.ts","import":"./index.js","require":"./index.cjs"}},"gitHead":"36e7fe6e3b1dd5a9356fb1dab93d9eb1746df8b0","typings":"./index.d.ts","_npmUser":{"name":"pseudosky","email":"skywinston.sk@gmail.com"},"_npmVersion":"11.6.2","description":"Budget enforcement plugin for @adhd/agent-mcp — caps token spend, cost, wall-clock time, and model calls per task/session/agent","directories":{},"_nodeVersion":"24.11.1","dependencies":{"zod":"*"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"@adhd/agent-base-types":"^2.1.1"},"_npmOperationalInternal":{"tmp":"tmp/agent-plugin-budget_0.0.2_1784686920401_0.925287798802678","host":"s3://npm-registry-packages-npm-production"}},"0.0.3":{"name":"@adhd/agent-plugin-budget","version":"0.0.3","_id":"@adhd/agent-plugin-budget@0.0.3","maintainers":[{"name":"pseudosky","email":"skywinston.sk@gmail.com"}],"dist":{"shasum":"bf8f5c4e36013f21bf69f81284159eebbf11bbcf","tarball":"https://registry.npmjs.org/@adhd/agent-plugin-budget/-/agent-plugin-budget-0.0.3.tgz","fileCount":6,"integrity":"sha512-99N4reRsOnwDUuWNNaSvz94dUyYcOrx/xL4Gm245bqY6HajJmLglrkrB1Z+1Z/QrVi8fg07rEoOKRPvJACHXdA==","signatures":[{"sig":"MEUCIQCJ++FBpY62C2Ys9rv5kwD3r2uFH5VPNPyfLYcr6ll9+wIgYvOe4B7Af3SdMhvWCN3sQrcH7RPKMqD58OlxM0FFXd0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":52585},"main":"./index.cjs","type":"module","module":"./index.js","exports":{".":{"types":"./index.d.ts","import":"./index.js","require":"./index.cjs"}},"gitHead":"afca4fc9097845a32a9e371ce6cd1252cbc0be6b","typings":"./index.d.ts","_npmUser":{"name":"pseudosky","email":"skywinston.sk@gmail.com"},"_npmVersion":"11.6.2","description":"Budget enforcement plugin for @adhd/agent-mcp — caps token spend, cost, wall-clock time, and model calls per task/session/agent","directories":{},"_nodeVersion":"24.11.1","dependencies":{"zod":"*"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"@adhd/agent-base-types":"^2.1.2"},"_npmOperationalInternal":{"tmp":"tmp/agent-plugin-budget_0.0.3_1784773931597_0.6231993706386769","host":"s3://npm-registry-packages-npm-production"}},"0.0.4":{"name":"@adhd/agent-plugin-budget","version":"0.0.4","_id":"@adhd/agent-plugin-budget@0.0.4","maintainers":[{"name":"pseudosky","email":"skywinston.sk@gmail.com"}],"dist":{"shasum":"fe6ee1bd2ca6d1155807f315b15a12a09b4e36d8","tarball":"https://registry.npmjs.org/@adhd/agent-plugin-budget/-/agent-plugin-budget-0.0.4.tgz","fileCount":6,"integrity":"sha512-KX8RIfwEjbntOYXsARDr/UfCgJqHY+wv3dbJXWSKL3nE8mRVdSj+EiKi252Rr53IVlQzHtygFh7KK9sRJJMl+Q==","signatures":[{"sig":"MEYCIQCrU+gGbokL0QCv6frxHDPOqwaUlTXxIbCyXUAcF3MYjQIhALUU97vkqn5r5jjOHv0KW8zl1w14p7NdVrbe1cA6CTRV","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":53285},"main":"./index.cjs","type":"module","module":"./index.js","exports":{".":{"types":"./index.d.ts","import":"./index.js","require":"./index.cjs"}},"gitHead":"eb0fd170825539850ae91a64393f8a8f376d8c7b","typings":"./index.d.ts","_npmUser":{"name":"pseudosky","email":"skywinston.sk@gmail.com"},"_npmVersion":"11.6.2","description":"Budget enforcement plugin for @adhd/agent-mcp — caps token spend, cost, wall-clock time, and model calls per task/session/agent","directories":{},"_nodeVersion":"24.11.1","dependencies":{"zod":"*"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"@adhd/agent-base-types":"^2.1.3"},"_npmOperationalInternal":{"tmp":"tmp/agent-plugin-budget_0.0.4_1784831141599_0.8369971198490695","host":"s3://npm-registry-packages-npm-production"}},"0.0.5":{"name":"@adhd/agent-plugin-budget","version":"0.0.5","_id":"@adhd/agent-plugin-budget@0.0.5","maintainers":[{"name":"pseudosky","email":"skywinston.sk@gmail.com"}],"dist":{"shasum":"13295f3bc989a097a6e662b3231242f801636b0e","tarball":"https://registry.npmjs.org/@adhd/agent-plugin-budget/-/agent-plugin-budget-0.0.5.tgz","fileCount":6,"integrity":"sha512-IjAO5G2naT5i8YG3jnxMakEZcE6shfALLxqfOEeqSpFMN+ou9My4mC7XIGTiHs52PdQj/m3Iq7vESMKSRjJDGw==","signatures":[{"sig":"MEQCIAa1ApPipCXtU/HL8rWlf8jYyFUabEwD2wKWZNbzT2qWAiBUam7BQ/svdO6hDFOmKFmigAo2H68mbFGca1YxoGu9Bg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":53423},"main":"./index.cjs","type":"module","module":"./index.js","exports":{".":{"types":"./index.d.ts","import":"./index.js","require":"./index.cjs"}},"gitHead":"60d30f61a52a3cb55285346e534382df02258264","typings":"./index.d.ts","_npmUser":{"name":"pseudosky","email":"skywinston.sk@gmail.com"},"_npmVersion":"11.6.2","description":"Budget enforcement plugin for @adhd/agent-mcp — caps token spend, cost, wall-clock time, and model calls per task/session/agent","directories":{},"_nodeVersion":"24.11.1","dependencies":{"zod":"*"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"@adhd/agent-base-types":"^2.1.4"},"_npmOperationalInternal":{"tmp":"tmp/agent-plugin-budget_0.0.5_1784934776229_0.4125049207364888","host":"s3://npm-registry-packages-npm-production"}},"0.0.6":{"name":"@adhd/agent-plugin-budget","version":"0.0.6","_id":"@adhd/agent-plugin-budget@0.0.6","maintainers":[{"name":"pseudosky","email":"skywinston.sk@gmail.com"}],"dist":{"shasum":"19bbde1735995a3954209a66b057647ec77a9bb7","tarball":"https://registry.npmjs.org/@adhd/agent-plugin-budget/-/agent-plugin-budget-0.0.6.tgz","fileCount":6,"integrity":"sha512-WfWugwWYZpmp1Mlw0ob2qVhkVy8ZIDVRGCpOk1vZbk6YnyFunyCa7G9WZE+QtcWtg9600/0ilMVvBBUKR2LByQ==","signatures":[{"sig":"MEUCIDRh5jJ6HeG2URe3hC07E0pbBgOUe0wRepI7ZakWJ9SgAiEA6uodUU9FhkF9SgLOgMK49A/ldD36QZllFg06+YbD1K4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":53423},"main":"./index.cjs","type":"module","module":"./index.js","exports":{".":{"types":"./index.d.ts","import":"./index.js","require":"./index.cjs"}},"gitHead":"4a55390e41abde59d4b6c1f420851503ff727386","typings":"./index.d.ts","_npmUser":{"name":"pseudosky","email":"skywinston.sk@gmail.com"},"_npmVersion":"11.6.2","description":"Budget enforcement plugin for @adhd/agent-mcp — caps token spend, cost, wall-clock time, and model calls per task/session/agent","directories":{},"_nodeVersion":"24.11.1","dependencies":{"zod":"*"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"@adhd/agent-base-types":"^2.1.5"},"_npmOperationalInternal":{"tmp":"tmp/agent-plugin-budget_0.0.6_1784937253879_0.08972890485568086","host":"s3://npm-registry-packages-npm-production"}},"0.0.7":{"name":"@adhd/agent-plugin-budget","version":"0.0.7","_id":"@adhd/agent-plugin-budget@0.0.7","maintainers":[{"name":"pseudosky","email":"skywinston.sk@gmail.com"}],"dist":{"shasum":"f3dc5cd25cad8f1772a05ceaa145ebcae06f7fc5","tarball":"https://registry.npmjs.org/@adhd/agent-plugin-budget/-/agent-plugin-budget-0.0.7.tgz","fileCount":6,"integrity":"sha512-kQyrtyUGoECgjtESTnq8rQ+jSUh0+Mjo6A/XSvNOnvvT4zUtAyub5wqa22PWeogAygvyNnsr3DLE8fUC5DFnuQ==","signatures":[{"sig":"MEUCIQCmsI252XNJ59wTK61RXGo2F6aMghv0HxSthO2ikRZU2gIgOgJ6qqhbHKWbkDWiZ8fwRiaeKphIwNwEhHnPP9QVWS4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":53561},"main":"./index.cjs","type":"module","module":"./index.js","exports":{".":{"types":"./index.d.ts","import":"./index.js","require":"./index.cjs"}},"gitHead":"936d50dc3a4c827b29a00dcd8686ba968775cd06","typings":"./index.d.ts","_npmUser":{"name":"pseudosky","email":"skywinston.sk@gmail.com"},"_npmVersion":"11.6.2","description":"Budget enforcement plugin for @adhd/agent-mcp — caps token spend, cost, wall-clock time, and model calls per task/session/agent","directories":{},"_nodeVersion":"24.11.1","dependencies":{"zod":"*"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"@adhd/agent-base-types":"^2.1.6"},"_npmOperationalInternal":{"tmp":"tmp/agent-plugin-budget_0.0.7_1784948675513_0.5867305198525241","host":"s3://npm-registry-packages-npm-production"}},"0.1.0":{"name":"@adhd/agent-plugin-budget","version":"0.1.0","_id":"@adhd/agent-plugin-budget@0.1.0","maintainers":[{"name":"pseudosky","email":"skywinston.sk@gmail.com"}],"dist":{"shasum":"d88d7b3ceb3bdc84f86f4e12a916f523b89f1282","tarball":"https://registry.npmjs.org/@adhd/agent-plugin-budget/-/agent-plugin-budget-0.1.0.tgz","fileCount":6,"integrity":"sha512-H/yxxEzIMHNZ7doMiRwuhfxRsMtjJs1OlvsmEYq3fgfZwjb8vPzDzCNXuCTKZU35vDYPCaVF/yktMMorBFyONw==","signatures":[{"sig":"MEYCIQCzYVPdmPpA8z7fRuHvIHo7Z57g4gUO7lKba9yatiIXVwIhAKSsBfL1FJitWzSaORP6YcnG9L1k7FfhuRrGrB0eOdgR","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":53747},"main":"./index.cjs","type":"module","module":"./index.js","exports":{".":{"types":"./index.d.ts","import":"./index.js","require":"./index.cjs"}},"gitHead":"1dbc0638f8eb1b7c961bc9359def6f4425da5c15","typings":"./index.d.ts","_npmUser":{"name":"pseudosky","email":"skywinston.sk@gmail.com"},"_npmVersion":"11.6.2","description":"Budget enforcement plugin for @adhd/agent-mcp — caps token spend, cost, wall-clock time, and model calls per task/session/agent","directories":{},"_nodeVersion":"24.11.1","dependencies":{"zod":"*"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"@adhd/agent-base-types":"^2.2.0"},"_npmOperationalInternal":{"tmp":"tmp/agent-plugin-budget_0.1.0_1785136558069_0.1145724404142956","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@adhd/agent-plugin-budget","version":"0.2.0","description":"Budget enforcement plugin for @adhd/agent-mcp — caps token spend, cost, wall-clock time, and model calls per task/session/agent","type":"module","publishConfig":{"access":"public"},"main":"./index.cjs","module":"./index.js","typings":"./index.d.ts","exports":{".":{"import":"./index.js","require":"./index.cjs","types":"./index.d.ts"}},"peerDependencies":{"@adhd/agent-base-types":"^2.3.0"},"dependencies":{"zod":"*"},"gitHead":"23e8c5f9498f3586bcfb054df02dc45f9f4072ec","_id":"@adhd/agent-plugin-budget@0.2.0","_nodeVersion":"24.11.1","_npmVersion":"11.6.2","dist":{"integrity":"sha512-1M0+V6WsiWBIazHk+HDBuNfZkJffYj+MQFSGcO/tlYmRvhlIb5gsGiaJJzXG4C75udkP6dH/84wX1e8h80Mnhw==","shasum":"50232070b0988031a9391fed6c34e5583f95fc4c","tarball":"https://registry.npmjs.org/@adhd/agent-plugin-budget/-/agent-plugin-budget-0.2.0.tgz","fileCount":6,"unpackedSize":75210,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDfK6SOz8Wky1zQIkfBPGJlWMkhxzqxS9aCTapWNu8FywIgLjK4QySbNzS7qflhfU8h3f3qEhJRjpJjhrjsiIsRZkE="}]},"_npmUser":{"name":"pseudosky","email":"skywinston.sk@gmail.com"},"directories":{},"maintainers":[{"name":"pseudosky","email":"skywinston.sk@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/agent-plugin-budget_0.2.0_1786493136729_0.7192259400387768"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-22T02:22:00.249Z","modified":"2026-08-12T00:05:37.193Z","0.0.2":"2026-07-22T02:22:00.529Z","0.0.3":"2026-07-23T02:32:11.741Z","0.0.4":"2026-07-23T18:25:41.769Z","0.0.5":"2026-07-24T23:12:56.403Z","0.0.6":"2026-07-24T23:54:14.014Z","0.0.7":"2026-07-25T03:04:35.669Z","0.1.0":"2026-07-27T07:15:58.185Z","0.2.0":"2026-08-12T00:05:36.984Z"},"description":"Budget enforcement plugin for @adhd/agent-mcp — caps token spend, cost, wall-clock time, and model calls per task/session/agent","maintainers":[{"name":"pseudosky","email":"skywinston.sk@gmail.com"}],"readme":"# @adhd/agent-plugin-budget\n\nEnforcement plugin for `@adhd/agent-mcp`. Caps token spend, model calls, wall-clock time, and tool usage per task, session, agent, provider, or globally — with configurable time windows and warning/block modes.\n\n## Config\n\nPlace at `.adhd/agent-mcp/config.json` (auto-discovered by the plugin loader):\n\n```json\n{\n  \"plugins\": [\n    {\n      \"module\": \"@adhd/agent-plugin-budget\",\n      \"config\": {\n        \"defaults\": {\n          \"caps\": [\n            { \"field\": \"tokens\", \"maximum\": 50000 },\n            { \"field\": \"calls\", \"maximum\": 8 },\n            { \"field\": \"wallClock\", \"maximum\": 120000 }\n          ]\n        }\n      }\n    }\n  ]\n}\n```\n\n## Caps\n\nEach cap defines one limit. Fields:\n\n| Field          | Unit  | Scope     | Description                                                                                                             |\n| -------------- | ----- | --------- | ----------------------------------------------------------------------------------------------------------------------- |\n| `tokens`       | count | all       | Sum of input + output + cache tokens                                                                                    |\n| `inputTokens`  | count | all       | Input tokens only                                                                                                       |\n| `outputTokens` | count | all       | Output tokens only                                                                                                      |\n| `calls`        | count | all       | Number of LLM model calls                                                                                               |\n| `wallClock`    | ms    | task only | Wall-clock time from task start                                                                                         |\n| `modelMs`      | ms    | task only | Cumulative model response time                                                                                          |\n| `cost`         | USD   | all       | Estimated cost (requires `costPerInputToken` / `costPerOutputToken`)                                                    |\n| `toolCalls`    | count | tool only | Per-tool call count                                                                                                     |\n| `responseSize` | chars | tool only | Raw response character length. Enforced at `transform:tool_result` — truncates (warning) or replaces with error (block) |\n\n### Custom message\n\nEach cap supports an optional `message` that overrides the auto-generated enforcement message. Use it to give the agent actionable guidance:\n\n```json\n{ \"field\": \"toolCalls\", \"maximum\": 5, \"mode\": \"block\", \"message\": \"Search is expensive. Use the index: query__search first\" }\n```\n\n### Scopes\n\n| Scope     | Coverage                                              | DB query                                     |\n| --------- | ----------------------------------------------------- | -------------------------------------------- |\n| `task`    | Current task in-memory only                           | None                                         |\n| `session` | Current task + all historical tasks in session        | `task_usage` JOIN `tasks` WHERE `session_id` |\n| `agent`   | Current task + all historical tasks for this agent    | `task_usage` WHERE `agent_name`              |\n| `global`  | Current task + ALL historical tasks across all agents | `task_usage` all rows                        |\n\nScope is inherited from the dimension's `scope` field if not set on the individual cap:\n\n```json\n{\n  \"defaults\": {\n    \"scope\": \"agent\",\n    \"caps\": [\n      { \"field\": \"tokens\", \"maximum\": 50000 },\n      { \"field\": \"calls\", \"maximum\": 8 }\n    ]\n  }\n}\n```\n\n### Time windows\n\nUse ISO8601 durations for rolling window caps:\n\n```json\n{ \"field\": \"tokens\", \"maximum\": 200000, \"window\": \"PT24H\", \"scope\": \"agent\" }\n```\n\nSupported formats: `PT24H`, `PT1H30M`, `P1DT6H`, `PT30M`, etc.\n\nWhen a cap has both `scope` and `window`, the window query provides the historical total (scope-filtered, within the window) — no double-counting.\n\n### Tool-level caps\n\nTool caps enforce at `pre:tool_call` (toolCalls) or `transform:tool_result` (responseSize):\n\n```json\n{\n  \"tool\": {\n    \"default\": { \"caps\": [{ \"field\": \"toolCalls\", \"maximum\": 100 }], \"mode\": \"warning\" },\n    \"overrides\": {\n      \"web_search\": {\n        \"caps\": [{ \"field\": \"toolCalls\", \"maximum\": 20 }],\n        \"mode\": \"block\"\n      },\n      \"filesystem__read_text_file\": {\n        \"caps\": [\n          { \"field\": \"responseSize\", \"maximum\": 500, \"mode\": \"warning\", \"message\": \"File too large. Use read_text_file with head:100 to preview, search_files for pattern matching, or read_multiple_files to batch-read small files\" },\n          { \"field\": \"toolCalls\", \"maximum\": 100, \"mode\": \"warning\", \"message\": \"Too many file reads. Use search_files or get_file_info first\" }\n        ]\n      }\n    }\n  }\n}\n```\n\n- `toolCalls` field — enforced at `pre:tool_call`\n  - `warning` — tool call is blocked, agent receives a diagnostic, task continues\n  - `block` — tool call is blocked, task fails with `BUDGET_EXCEEDED`\n- `responseSize` field — enforced at `transform:tool_result` (after the tool runs)\n  - `warning` — tool result is **truncated** to `maximum` chars, task continues\n  - `block` — tool result is replaced with an error message (task continues, agent sees the error)\n\n## Dimensions\n\nCaps are merged from three dimensions in this order:\n`defaults ← agent ← provider`\n\n```json\n{\n  \"defaults\": {\n    \"caps\": [{ \"field\": \"calls\", \"maximum\": 8 }]\n  },\n  \"agent\": {\n    \"default\": { \"caps\": [{ \"field\": \"calls\", \"maximum\": 5 }] },\n    \"overrides\": {\n      \"cheap-agent\": {\n        \"caps\": [{ \"field\": \"calls\", \"maximum\": 1, \"message\": \"Cheap agents get 1 call max\" }]\n      }\n    }\n  },\n  \"provider\": {\n    \"default\": { \"caps\": [{ \"field\": \"cost\", \"maximum\": 0.1 }] },\n    \"overrides\": {\n      \"anthropic\": { \"caps\": [{ \"field\": \"cost\", \"maximum\": 0.5 }] }\n    }\n  },\n  \"tool\": {\n    \"default\": { \"caps\": [{ \"field\": \"toolCalls\", \"maximum\": 100 }], \"mode\": \"warning\" },\n    \"overrides\": {\n      \"web_search\": {\n        \"caps\": [{ \"field\": \"toolCalls\", \"maximum\": 20, \"message\": \"Consider caching search results\" }],\n        \"mode\": \"block\"\n      },\n      \"filesystem__read_file\": {\n        \"caps\": [{ \"field\": \"responseSize\", \"maximum\": 500, \"mode\": \"warning\", \"message\": \"Raw file content is too large. Use shell tools instead: head -n 100, wc -l, grep for patterns\" }]\n      }\n    }\n  }\n}\n```\n\nCaps are **additive** across dimensions — multiple caps targeting the same field all apply. For example, `defaults` and `agent.overrides` can both cap `calls`; the stricter bound wins by throwing first.\n\n## Cost estimation\n\nFor the `cost` field, set token prices on the defaults dimension:\n\n```json\n{\n  \"defaults\": {\n    \"costPerInputToken\": 0.000003,\n    \"costPerOutputToken\": 0.000015,\n    \"costPerCacheReadToken\": 0.0000003,\n    \"costPerCacheWriteToken\": 0.00000375,\n    \"caps\": [{ \"field\": \"cost\", \"maximum\": 0.1 }]\n  }\n}\n```\n\nCost = `uncachedInputTokens × costPerInputToken + cacheReadTokens × costPerCacheReadToken + cacheCreationTokens × costPerCacheWriteToken + outputTokens × costPerOutputToken`.\n\n`costPerCacheReadToken` and `costPerCacheWriteToken` default to `costPerInputToken` when unset, so a config that only sets the two flat rates bills every input token at the flat input rate — identical to the pre-cache-aware behavior. To match a model's real rate card (e.g. DeepSeek: input `$0.14/M`, cache-read `$0.0028/M`), copy the per-class rates from the provider rate card; on cache-warm runs most input is cache-read, and billing it at the flat input rate over-counts spend by up to ~50x.\n\n## Backward compat (flat format)\n\nThe old flat field format is supported via automatic conversion:\n\n```json\n{\n  \"config\": {\n    \"maxTotalTokens\": 50000,\n    \"maxModelCalls\": 8,\n    \"maxWallClockMs\": 120000,\n    \"scope\": \"agent\"\n  }\n}\n```\n\nConverts internally to:\n\n```json\n{\n  \"caps\": [\n    { \"field\": \"tokens\", \"maximum\": 50000 },\n    { \"field\": \"calls\", \"maximum\": 8 },\n    { \"field\": \"wallClock\", \"maximum\": 120000 }\n  ],\n  \"scope\": \"agent\"\n}\n```\n\n### Custom messages in flat format\n\nThe `message` key is also passed through in flat format — it applies to all caps in the dimension:\n\n```json\n{\n  \"config\": {\n    \"maxTotalTokens\": 50000,\n    \"maxModelCalls\": 8,\n    \"mode\": \"warning\",\n    \"message\": \"Budget limit hit\"\n  }\n}\n```\n\n## Performance\n\nEnforcement makes exactly `U + W` DB queries per event where:\n\n- `U` = number of unique non-task scopes across all caps (0..3)\n- `W` = number of unique (scope, window) pairs across all caps\n\nZero DB queries when no caps are configured. No per-cap scaling.\n\n## Testing\n\n```bash\nnx test agent-plugin-budget\n```\n","readmeFilename":"README.md"}