Skip to main content

llm-spendguard

Actively minimize and govern LLM spend before work runs — then prove the result against the provider's bill.

uvx --from llm-spendguard spendguard scan        # 10 seconds. No key, no config, nothing leaves your machine.

That reads the coding-agent transcripts already on your disk and tells you what that work costs at API rates. Nothing is installed into your interpreter and nothing is uploaded — see what leaves your machine.

Then, when you want the guard rails, set up once:

pip install 'llm-spendguard[all]' && spendguard init --all   # ONE command: caps + identity, auto-detect your $0 subscription lanes, and wire the gate, MCP tools, in-chat receipt & slash-commands
spendguard run -- python your_job.py   # gate ONE command: cost estimate before submit + hard caps
spendguard reconcile all               # your ledger vs the provider's actual bill, with the gap NAMED
spendguard submit-jobs jobs.jsonl      # hand it a WHOLE job set + a goal; it plans the cheapest route and runs it

spendguard init is safe to re-run and works fully standalone (no account). init alone writes config and auto-detects your $0 lanes; init --all also wires the gate, MCP tools, receipt, assistant rule and slash-commands (add --quick for zero prompts). It ends on a status card + the one command that proves the path end-to-end.

Six things it does that the observability and gateway tools don't:

  1. Estimates a batch before you submit it — not after the tokens are billed.
  2. Refuses to price a model it doesn't know, loudly, instead of logging $0. (Elsewhere a $0 price can also silently exempt the call from your budget cap — an unknown model becomes an uncapped model.)
  3. Reconciles to the actual invoice and names the residual as ungoverned spend, with a published error rate — see ACCURACY.md.
  4. Learns the cheaper config and proves it's safe before adopting it (measure → test for output equivalence → adopt only if quality holds → apply → remember what failed).
  5. Plans a whole job set for you — the simplest contract there is: hand it the jobs and a goal (a budget, how urgent), and it picks the cheapest route per call — the Batch API, a subscription lane you already pay for, or the metered API — capability-matched to each call's structured-output needs, runs it, and returns. It estimates the whole set first and refuses before spending a cent over your budget. You never hand-tune which path each call takes; that's spendguard's job. See the whole-job contract.
  6. Manages constrained plans actively — sheds eligible work from a capped/overage lane to another ready $0 lane, chooses the cheapest measured-good (model, effort), substitutes an actually served model inside a bounded economic envelope, and delegates self-contained agentic work to codex/gemini/zai/kimi CLIs when the current plan is capped.

Zero required dependencies. Fail-open by design: a cost tool must never be the reason your job doesn't run. Learn more at https://llmspendguard.com · Docs & quickstart →

The global model reference is available without login at llmspendguard.com/catalog. Its row as_of is the authored date the row's price/capability payload last changed; “snapshot ingested” is the server's separate observation time. Local standalone operation remains complete; SaaS sync and dashboards are optional.

📘 New here? Read the Solution Specification — the whole story end to end: why it exists, the value, the journey of a dollar (call → gate → ledger → reconcile → push), the design, and how it's tested, secured, and operated.

What leaves your machine

Three modes. The default is local-only — you have to opt in to each of the other two.

Mode What leaves How to turn it on
Local-only (default) Nothing. scan, run, the gate, the ledger, reconcile, trust all work with no network except the providers' own free billing endpoints, which send nothing — they only read your usage. — (this is the default)
LLM attribution (opt-in) Excerpts of local coding-agent transcripts go to a model provider so an LLM can classify which project/team spend belongs to. De-identified first (deid.engine). you run spendguard chat … / accounting --run
Team dashboard (opt-in) Per-day, per-model roll-ups only: day, provider, model, kind, project, $ and token counts. No prompts, no outputs, no keys. you configure saas.json and run saas sync

Two things worth stating plainly, because they are the questions a careful reviewer asks first:

  • Your API keys never leave the machine and are never sent to our server. Provider billing is read locally with your key; only the resulting numbers are pushed, and only if you connect a team dashboard.
  • Coding-agent transcripts can contain secrets (a .env echoed into a session, a pasted credential). That is exactly why LLM attribution is opt-in and de-identified rather than on by default — and why scan, the command we ask you to run first, never sends them anywhere.

spendguard run --show prints the exact bootstrap that will execute in your process. Nothing is downloaded at runtime, ever.

The chat extra reads your claude.ai session — here is exactly what it does and why

The claude.ai desktop app caches no conversations on disk, so the only way to account for chat usage is claude.ai's own API, authenticated with the sessionKey cookie your browser already holds. That is why the optional chat extra decrypts a cookie — and we understand how that phrase reads in 2026, so here is the whole of it:

  • It is opt-in twice: you must install the chat extra and set chat.enabled (or SPENDGUARD_CHAT_ENABLED). Nothing happens by default; scan, the gate, the ledger and reconcile never touch it.
  • What it reads: ~/Library/Application Support/Claude/Cookies (the app's own Chromium cookie DB) and only the entries sessionKey, lastActiveOrg, cf_clearance. The AES key comes from your macOS Keychain, which prompts you for permission — spendguard cannot bypass that prompt, and you can deny it.
  • Where the token goes: nowhere. It authenticates requests to claude.ai from your machine. It is never logged, never printed, never sent to our server, and never included in a roll-up. The decrypt happens in-process (the cryptography dep exists precisely so the key is not passed on a command line where ps could see it).
  • What is cached: the cookie, chmod 0600, with a TTL (chat.cookie_ttl_h, default 12h), cleared on any 401. Delete ~/.spendguard/ to purge it.
  • What is pushed: if — and only if — you connect a team dashboard, the same per-day roll-ups as everything else. No conversation text, no titles, no token.
  • Don't want any of that? Skip the extra entirely. You keep the gate, the ledger, reconcile, scan and Claude Code / Codex accounting; you lose only claude.ai chat value. Or set the session key yourself and no cookie is ever read.

Why it's worth having: chat is where a large share of plan-covered work actually happens, and leaving it out doesn't make the spend disappear — it makes your total quietly wrong, which is the one thing this project exists to prevent.

Why llm-spendguard?

Cost overruns don't announce themselves — they slip in silently: a hardcoded price that drifted from the real rate, a forgotten model swap, under-batching that re-bills a shared prompt every request, a job cancelled "to save money" that still bills for completed work, an ungated script in some other venv quietly leaking spend. spendguard stops those before the spend (the gate hard-stops over a cap, prices from a verified table, finds the leaks) and learns what was actually worth it — so "cheaper" never quietly costs you quality.

Born from a real incident: a "cost-conscious" day meant to cost ~$33 actually cost $149.76 — a price constant was hardcoded wrong (GPT-5.5 at the old GPT-5 rate) and jobs ran 1 item/request (the shared prompt re-billed every call). spendguard makes those mistakes impossible to ship silently — and goes further: it reconstructs what you should do cheaper, and won't let "cheaper" cost you quality.

What it does

Enforce → shed → route → delegate → save → prove → learn.

  • gate — overlay on the OpenAI/Anthropic SDKs (armed by spendguard run --, by import spendguard, or venv-wide via the opt-in hook): estimates every batch/real-time call — chat, Responses API, Anthropic messages, and embeddings (realtime + batch input bodies) — hard-stops over a cap (per-batch + cross-process daily/monthly) — then asks if interactive.
  • reliability (no 429 storms) — one admission chokepoint paces every fan under the vendor's real rpm/tpm (seeded from the catalog's published limits, refined by AIMD from live headers) and diverts an over-deadline burst to the Batch API — so a thousand-wide fan is paced or batched, never stormed. Durable, crash-resumable, exactly-once; the caller is always served with no 429 surfaced. See docs/PLAN_429_storm_to_batch.md.
  • pricing — one canonical, verifiable table (layered from LiteLLM + curated + override), cross-checked vs OpenRouter; an audit fails CI if any code hardcodes a disagreeing price.
  • reconcile — actual $ from real billed tokens; reconcile-ledger compares the local ledger to provider billing to find leaks (ungoverned spend from a non-gated venv/repo).
  • report — daily/weekly/monthly email with spend totals + a leak alert + the advisor's top learnings.
  • learning advisor — a per-call cost+quality corpus → confidence-scored, lifecycle-tracked insights; brief pre-fills a plan, optimize recommends the cheapest config that held quality, experiment proves it (cost↓ and same-output), promote runs it and keeps the output. Cost-per-good-result, not per-token.
  • model-advisor (over MCP) — which model for this job? answered from your own measured usage: advise ranks the models you've used for a job-type by $/good, recommend picks the top-K on the cost×quality frontier at the precision the job needs (agentic quality-bar), and bakeoff measures untried models on a task sample so they enter the ranking. Exposed as a local MCP server — spendguard mcp (stdio, no SDK dep) — so any MCP client (Claude Code / Desktop, an IDE agent) can call it as tools. See Model-advisor.
  • active routing — advisor.shed_lanes plus live cap/overage state moves eligible work to ready $0 lanes; best-value resolves the cheapest measured-good (model, effort); unserved requests get the best catalog-ranked served substitute within anchor rate ×1.25. Shed results distinguish avoided-overage $ from quota-preserved value.
  • warm shared MCP + fleet — one long-lived daemon per tool is shared by sessions; spendguard fleet reports the deployed green version and stale consumers instead of leaving long-running processes silently behind.
  • cost levers — prompt-caching audit/test, semantic cache + batch dedup, cost-aware cascade routing.
  • observability — emits OpenTelemetry GenAI-convention metrics+spans → Langfuse / Helicone / Phoenix / any OTLP backend.

The advisor's own LLM use is itself caged (a separate caps.meta budget, tagged spendguard:*, excluded from the corpus it analyzes) so the governor can't overspend governing.

Cost reporting has three axes and never blends them: Total $X = $A API + $S Subscription (plan) + $R Remote (provider) :: Est sub value $V; guarded savings (measured + counterfactual) is a separate third axis, never added to real dollars or estimated subscription value.

Routing cheat-sheet

  • One-shot verdict, classification, or extraction: use adapters.call(model, prompt, reasoning="best-value", intent="stable-job-name"), vendor_call, or spendguard ask. The explicit intent lets measured quality choose the cheapest qualifying model/effort. A matching $0 subscription lane is tried first; the metered API is the fallback.
  • Many independent comprehension items: use spendguard comprehend <globs> --intent <stable-job-name> so the batch can be spread across eligible subscription lanes.
  • Self-contained agentic workspace edit: use spendguard delegate "<task>" --provider <plan> --cwd /trusted/repo --yes. This is the workspace-write, multi-step path, with a 1,800-second default budget—not the path for a hot one-shot verdict.

Name an intent, not a guessed model id, and let routing select the model and lane. The configured/served model-id source of truth is advisor.lane_models, exposed by spendguard lanes --catalog; spendguard models profiles known models but does not declare what a lane serves. Do not invent or pin ids that can go stale. The $0-on-the-billed-axis lanes are subscription-plan executors: Codex, Gemini/agy, Kimi, Claude Code, and Z.AI Coding. Codex and Kimi use default-on persistent warm daemons; Gemini and Claude Code use their plan CLIs, while Z.AI Coding uses its plan-key endpoint. OpenAI-compatible endpoints in adapters.PROVIDERS are metered API routes, not $0 merely because they speak plain HTTP. For Codex, the measured operative warm turn is ~5s; >75s applies only to a cold one-shot codex exec fallback.

Delegate agentic work to another plan

When the current plan is capped or on paid overage, spendguard delegate can hand a self-contained agentic subtask to a configured $0 or cheaper subscription plan. It is a two-hop flow: a plan-covered classifier decides whether the task is a one-shot, an agentic workspace task, or needs the current Claude context; then the selected provider CLI runs it. The default is a dry-run that returns the classification, route, separate real-$ and est-value estimate, and estimated dollars saved versus measured Claude overage:

spendguard delegate "fix and test this module" --provider codex --files src/app.py --cwd /trusted/repo --yes

MCP clients can use the same engine with spendguard_delegate (execute=false by default). The honest boundary: this offloads a SELF-CONTAINED subtask to another provider's plan; it does NOT reroute the calling agent's own turns. Use it for bounded work you can describe completely; keep live-context conversational work in the current agent. For one-shot verdicts use the routing cheat-sheet above. This implements the packaged assistant guidance in §8 of the installed spendguard:rule: batchable comprehension goes through lane routing, while agentic subwork can be handed to another provider CLI when the current plan is capped or on overage.

Docs: Architecture + diagrams · Diagrams · Durable queue + dedup · Plan shedding · Fleet / update propagation · Model-advisor (MCP) · Use with Claude/Cursor · Methodology · Roadmap (teams/orgs/SaaS) · Module map · Contributing · Changelog · Setup

Use with an AI assistant: spendguard install-rule --global writes a rule into CLAUDE.md so every Claude/Cursor conversation routes the LLM code it builds through spendguard — then spendguard install-skills adds the slash-commands: /spend (status), /spendguard-reconcile (trust the number), /spendguard-learn (advisor), /spendguard-prompts (the prompt lab), /spendguard-close (monthly close). See Use with Claude. Teams & orgs: each user keeps their own ledger and local caps; the connected server also serves effective advisory or enforced caps through GET /v1/policy, which the client pulls and enforces (an enforced org cap can only be tightened locally). Opt-in roll-ups carry decisions, shed effectiveness, savings, and fleet/client status to the dashboard. The client is production-ready and fully standalone. The team/org dashboard is live at llmspendguard.com — see ROADMAP.md.

Quickstart

A) Set up with Claude (recommended). Point Claude Code / the desktop app at this repo and say:

Install spendguard from this repo and run the guided setup in SETUP.md.

Or just run spendguard init — it reads the config registry (src/spendguard/config_schema.py — the single source of truth for every setting, its default, valid options, and whether it's secret) and walks you through caps, projects, and providers conversationally, one question at a time, then writes your config. Pointed at this repo, Claude does the same end-to-end: installs the package, runs the interview off that same registry, and wires up the gate. Details: SETUP.md.

B) pip + code.

pip install llm-spendguard
# or, from a clone of this repo:
pip install -e .
import spendguard                    # importing the guard now GATES every OpenAI/Anthropic call in this process
# spendguard.install(cap=75)         # optional — set a per-batch cap (import already installed the gate)

import spendguard auto-installs the gate (idempotent, fail-open), so pip install + import is enough — no more silently-ungated spend. Knobs: SPENDGUARD_NO_AUTOINSTALL=1 opts out; SPENDGUARD_REQUIRE=1 makes the import fail-closed (raises if an SDK is present but the gate can't enforce here — refuse loudly rather than spend ungated). For a hard guarantee in a script, keep spendguard.require() at the top.

To gate one command without touching your interpreter at all — the default, and the shape ddtrace-run and opentelemetry-instrument use:

spendguard run -- python your_job.py
spendguard run --show          # print the exact bootstrap that will execute, before you trust it

Nothing is written into site-packages and nothing persists once the process exits. To arm every process in a venv you own, that's an explicit opt-in: spendguard install-hook --venv .venv (remove with --uninstall). We don't default to writing startup hooks — see Architecture for why. Configure with spendguard init (interactive — or init --quick for non-interactive defaults) / spendguard config (show current); see the configuration reference.

Where to go next

Full CLI reference Every command, grouped: enforce · see the money · plan · prove · attribute · setup.
Configuration & subsystem reference Env knobs, caps by class, pricing layers, the learned estimator, the advisor, observability, de-identification.
Accuracy How close these numbers are to your real invoice — and what we do not capture.
Architecture The gate chokepoint and the extensibility seams.
Use with Claude / Cursor Make every assistant session gated; the slash-commands.
Solution spec The whole story end to end: why, value, the journey of a dollar, design, ops.
Setup · Changelog · Contributing · Security

Safety

Fail-open: any estimation or patch error logs a warning and lets the call proceed — the gate never breaks a job by accident. Only the deliberate over-cap stop blocks. Disable instantly with spendguard off (checked per-call, live) — and the kill switch is honored even if the gate itself errors.

Getting help

Metadata

Release files for llm-spendguard 0.12.21

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for llm-spendguard 0.12.21
File Size Uploaded
llm_spendguard-0.12.21.tar.gz 2.3 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for llm-spendguard 0.12.21
File Interpreter ABI Platform
llm_spendguard-0.12.21-py3-none-any.whl Python 3 none any Details

Total release size: 3.7 MB

Release files / llm_spendguard-0.12.21.tar.gz

Download URL llm_spendguard-0.12.21.tar.gz
Size 2.3 MB
Tags Source
SHA-256 checksum
How to use checksums
f829f530dee036a6aeab9dddd91ca175f6b35e4fdda5bc8dc540b09003c8e09e
BLAKE2b-256 checksum
How to use checksums
35fd47e6de6167b3112979a6e4c6ea4495f6450901d599c3cb4e4a21fce25e52
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 16, 2026.

Transparency log

Release files / llm_spendguard-0.12.21-py3-none-any.whl

Download URL llm_spendguard-0.12.21-py3-none-any.whl
Size 1.4 MB
Tags Python 3
SHA-256 checksum
How to use checksums
fd0ad55ece35b46fedbd47987de1afc707d5d26a53d6d11865693c5804b077aa
BLAKE2b-256 checksum
How to use checksums
c5ee12f391037a2f132dce9d325d36347f661ed7c7be824e66ad4b0d5dcba67e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 16, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.12.21 This release

2 release files

0.11.4

2 release files

0.11.3

2 release files

0.11.2

2 release files

0.11.1

2 release files

0.11.0

2 release files

0.10.0

2 release files

0.9.0

2 release files

0.8.9

2 release files

0.8.8

2 release files

0.8.7

2 release files

0.8.6

2 release files

0.8.5

2 release files

0.8.4

2 release files

0.8.3

2 release files

0.8.2

2 release files

0.8.1

2 release files

0.8.0

2 release files

0.7.2

2 release files

0.7.1

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.9

2 release files

0.2.8

2 release files

0.2.7

2 release files

0.2.6

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page