developer-tools
Budget Guard puts a hard daily cap on Claude API spend
Claude News
developer-toolsbudget-guard is an open source npm package that wraps an existing OpenAI, Anthropic or Gemini client and throws BudgetExceededError before any call that would push a project past its daily dollar cap. It is published on Github under an MIT license, installs with npm i budget-guard and carries zero runtime dependencies.
At a glance
- The ledger sits in process memory for a single script, in a JSON file for one machine, or in Redis for a fleet, with estimated cost reserved atomically before each call and settled afterwards.
- An optional estimator() blocks the offending call itself using a chars/4 heuristic, correcting for the newer Claude tokenizer generation that counts roughly 30% more tokens on Opus 4.7+, Sonnet 5+, Fable and Mythos.
- spendReport() returns today's spend per feature tag, while onSpend fires a per-call event with project, feature, model, cost and running day total for logs, traces or a dashboard.
Provider dashboards report spend after the fact, which leaves nothing standing between a retry loop and an overnight invoice. Refusing the call is a different class of control, and the three storage tiers read as an acknowledgement that the failure modes differ: a cron job restarting at zero on every run is a separate problem from parallel workers racing past the same cap. Per-feature attribution is likely what survives after the scare.
Usage shapes from OpenAI, Anthropic, Gemini, Bedrock and Cohere are detected automatically
The wrapper reads token counts from the response rather than from a proxy, and it recognises the OpenAI shape including Azure, Mistral, DeepSeek and xAI, the Anthropic shape, Gemini's usageMetadata, AWS Bedrock Converse and Cohere's billed_units. Anything else can be metered by passing a usageOf extractor that returns input and output counts.
Cached and reasoning tokens are priced at their own per-class rates, and the library compensates for provider conventions: xAI and Gemini report reasoning tokens outside the output count, so budget-guard adds them back. Prices live in a PRICES table in USD per 1,000 tokens. A response with no recognisable usage throws by default, with onMissingUsage set to zero as the opt-out.
Adapters cover the Vercel AI SDK v5 and v7, LangChain.js, LlamaIndex.TS and Mastra
Streaming calls pass every chunk through untouched and the cost is recorded once the stream ends. For OpenAI the library injects stream_options with include_usage, since usage only arrives on the final chunk with that flag set. Anthropic streams are read from message_start and message_delta events, Gemini streams from each chunk's usageMetadata, and guardOpenAI, guardAnthropic and guardGemini set the provider option in advance.
budgetGuardMiddleware wraps a Vercel AI SDK model and detects the v5 or v7 usage shape per call, metering generateText and streamText alike; Mastra agents are covered through the same wrapped model. LangChain.js gets a BudgetGuardHandler callback that reads usage_metadata and falls back to llmOutput.tokenUsage, and guardLlamaIndex meters LlamaIndex.TS calls from response.raw, including streaming chat().
A streak of five consecutive failures triggers the retry-storm callback
Consecutive provider failures are tracked per feature and model pair, and onRetryStorm fires once the streak reaches retryStormThreshold, set to five in the documented example. A success resets the streak and stamps retryCount on that call's spend event, so a log line can read that a $0.40 call took seven attempts. Calls blocked by the cap are not counted.
Caps can run monthly instead of daily and reset on an IANA time zone's calendar rather than UTC; an invalid zone throws at construction. With Redis, ttlSeconds has to be widened, for example to 40 days, so monthly counters do not expire early. Setting onCap to warn logs instead of throwing, and budget-guard/testing ships a fixed clock and a recording fake store.
The hosted dashboard remains unscheduled
The roadmap lists a hosted dashboard with cross-project spend and alerts as the only major item left, and no release date is given for it; the SDK itself is described as staying free. Users of version 0.1 need one change: spendReport() is now asynchronous and requires await. The examples directory runs without an API key.
Comments
No comments yet. Be the first.
Join the conversation
Sign in with Google to leave a comment. Your name and avatar come from your Google profile, and the comment appears after moderation.
We only use your name and avatar from Google. We never store your email address.
