Skip to main content

blackbox-bill

Explain where your AI-coding-tool money went. A stdlib-only Python CLI that reads your Cursor billing export and your local session logs, then tells you — in plain English — why your bill looks the way it does. v2 adds tokenizer-aware cost attribution: per-project breakdowns and subagent token share, straight from your ~/.claude/projects transcripts.

No network. No API keys. Deterministic: every explanation cites the exact rows it was computed from.

The problem

Cursor's billing pools confuse everyone:

  • u/josh3com on r/ClaudeCode: "CURSOR TEAM PLEASE HELP - Cursor support keeps telling me my 100% full usage pool is from grok bot two months in a row" — Grok Bot spend kept landing in "Other Models" with no explanation in the app.
  • u/FerretValuable9718: "Why is the 'Other Models' usage being used so much with so little time?" — screenshot showed Other Models 100% used while Cursor Models sat at 16%.
  • r/AI_Agents: "My coding agent hit a cold-start 503, found a Gemini key in my repo, and burned $40 while I slept" — spend routed to a provider the user never intended.
  • dev.to: "$402 on one ticket" in headless Claude Code — "nothing in the app said so", so the author built manual bookkeeping.
  • r/ClaudeCode, October 2026: Fable 5.1 requests silently served by 5.5 — the model on the invoice doesn't match the model you asked for.

Forums are full of people doing billing archaeology by hand. blackbox-bill automates the archaeology.

What it does

blackbox-bill --csv cursor-export.csv

Given a Cursor billing export CSV (columns vary — the parser is deliberately liberal), it prints:

  1. Pool-normalized summary — first-party Cursor pool vs "Other Models" pool vs API-key spend, per model, per day. Free-form pool labels are normalized to the three canonical pools; unrecognized labels are reported as unknown, never silently dropped.
  2. Tokenizer-aware token figures — every token total is shown in both tokenizer equivalents (--tokenizer legacy|claude-4.7, --tokenizer-factor to override the default 1.3 ratio). Claude 4.7+'s new tokenizer emits ~30% more tokens for the same text; without this, a workload looks cheaper than it bills.
  3. Plain-English explanations from rule-based anomaly detection:
    • "Why your 'Other Models' pool drained first" — auto-model routing sent X% of requests to non-Cursor models.
    • "The grok-4 spend landed in unexpected pool(s)" — one model billed across multiple pools.
    • "'fable-5.1' requests were routed to 'fable-5.5'" — silent version swaps, with the N local sessions listed.
    • "Unattended burn: $X spent while no interactive session was open" — the "$40 while I slept" case.
    • "Sudden pool switch on " — same usage pattern, different bucket mid-cycle.
  4. Local-log cross-check — joins bill rows against your ~/.claude/projects/**/*.jsonl and ~/.codex/sessions/ by time window, reporting matched vs orphaned spend.
  5. Plan-switch what-if simulator:
blackbox-bill --csv cursor-export.csv --whatif cursor:ultra

re-prices observed token usage under a different plan's rates and prints the delta vs the actual bill. Bundled rate cards are illustrative placeholders, not real Cursor pricing — pass --rates-file rates.json with your own numbers (see src/blackbox_bill/whatif.py for the format). 6. Dispatch pre-flight headroom dashboard (v0.3) — per-account rate-limit headroom before you dispatch, not after you're stuck mid task (see below).

blackbox-bill --csv export.csv --markdown report.md --since 2026-09-01

Exit codes: 0 ok, 2 usage error (unreadable CSV, unknown plan). Missing local log directories are warnings, not errors — the bill alone is still explainable.

Cost attribution from local logs (no bill needed)

blackbox-bill report works without a CSV: it reads your Claude Code transcripts and answers the questions forums keep asking.

Per-project attribution — which project burned the quota (u/rosehsu47's complaint: /usage can't tell you which project spent it, so people hand-roll quota-audit scripts over the same jsonl files):

blackbox-bill report --by-project

Aggregates tokens, estimated cost, and per-session detail per ~/.claude/projects/* directory, sorted by estimated spend. Dollar figures are estimates from an illustrative built-in rate card — pass --rates-file with your own per-1M-token rates for real numbers.

Subagent attribution — how much of the burn was subagents (u/aidiveyt measured 2,631 subagent runs eating 48.1% of tokens):

blackbox-bill report --by-agent --top 10

Subagent token share is measured on sidechain transcript messages; the Top-N ranking attributes sidechain tokens to the invoked subagent_types (Task tool calls), split proportionally.

blackbox-bill report --by-project --by-agent --tokenizer claude-4.7 \
    --rates-file my-rates.json --markdown attribution.md

Dispatch pre-flight headroom (v0.3)

Everything above explains the bill after the fact. v0.3 adds the pre-flight view one Offrun Show HN user asked for verbatim: "Thing I'd want surfaced is per account rate limit headroom before I dispatch, not after I'm stuck mid task."

Billing exports never carry quota limits, so you declare them once in a JSON file and blackbox-bill subtracts your observed usage — per account, per canonical pool — before the next dispatch:

blackbox-bill headroom --csv export.csv --limits-file limits.json

limits.json:

{
  "accounts": [
    {"name": "cursor-pro", "plan": "cursor:pro",
     "limits": {"cursor-models": 500.0, "other-models": 125.0, "api-key": null}},
    {"name": "shared-api-key", "plan": "api-only",
     "limits": {"api-key": 200.0},
     "match": {"column": "account", "value": "shared-api-key"}}
  ]
}

Limits are USD caps per pool; null is unlimited. Rows are partitioned across accounts with the optional match spec (raw CSV column value); the single account without a match spec is the default for unclaimed rows. Pools are flagged OK / LOW (under 25% remaining) / EXHAUSTED / UNLIMITED.

Planning to kick off a long agent run? Add --task-in/--task-out and the dispatch simulator re-prices the task under each account's plan rate card (the same cards the what-if simulator uses) and tells you which account can absorb it:

blackbox-bill headroom --csv export.csv --limits-file limits.json \
    --task-in 1000000 --task-out 250000 --task-pool other-models

Differentiation — from post-mortem to pre-flight. v0.1–v0.2 were post-mortem: the bill arrived, the tool reconstructed why it looks wrong. v0.3 is pre-flight: the tool shows remaining quota per account and which account survives the next dispatch before you commit. The ledger positioning doesn't change — still read-only analysis, still no enforcement, no budget lines, no blocking (that's what agentcost-cli and resume-budget-guard are for). It's the same billing-attribution ledger, just turned one step earlier in time.

Non-goals (what this is NOT)

  • agentcost-cli does multi-tool budget observability dashboards with WARN/OVERRUN budget lines. blackbox-bill has no dashboards, no budget lines, no MCP server — it explains one bill, once.
  • resume-budget-guard (sibling project) enforces cumulative spend caps across Claude Code --resume runs. blackbox-bill never blocks or enforces anything; it is read-only analysis.
  • ccusage covers Claude Code usage attribution (daily/monthly/session/blocks, per-model breakdown). blackbox-bill deliberately does not re-do Claude Code attribution — its job is the cross-tool routing black box (Cursor pools, unexpected providers, silent model swaps).

One sentence: the others tell you how much you spent or stop you from spending; blackbox-bill tells you why the bill looks wrong.

How it differs from statusline dashboards

Tools like uppinote20/claude-dashboard are observability statuslines: they live inside your IDE, rendering live context bars, rate-limit countdowns, and burn-rate widgets while you work. That's a telescope pointed at the present.

blackbox-bill is a billing-attribution ledger: it runs off local files only, and reconstructs where the money went — which pool, which project, which subagents, under which tokenizer's counting. No plugin install, no Node runtime, no live session needed — just the bill CSV and the transcripts you already have. Use the statusline to watch the burn; use blackbox-bill to audit it.

v0.3's headroom dashboard doesn't change that positioning: it is still the ledger, just consulted before the dispatch instead of after the bill. The "live" part of headroom is your own declared quota limits — the tool never polls a vendor API for remaining quota (no vendor puts that in an export, and polling one would need your credentials).

Honest limitations

  • Cursor changes its export format. The parser fuzzy-matches headers and fails soft on missing columns, but a radically new format may need new aliases — contributions welcome.
  • Routing rules are inferred, not official. Explanations are heuristics built from observed community patterns ("Other Models drains first", "Grok Bot mis-bucketing"). They are not Cursor/OpenAI/Anthropic documentation, and every explanation says so.
  • Times are local-timezone best-effort. Bill timestamps and local log timestamps are compared as wall-clock times on the same machine. If your export is in UTC and your logs are local, widen --window-hours or convert first.
  • The join is evidence, not proof. A bill row with no matching local session might be a background agent, a headless run, another machine, or a leaked key — the tool reports the gap; you investigate.
  • Token-based re-pricing is approximate. The what-if simulator re-prices tokens at flat rates; real plans have request-based pricing, overage rules, and weekly pools (e.g. SuperGrok bundles) that flat rates cannot model. Use --rates-file for your own numbers.
  • Headroom limits are self-declared. No billing export carries quota caps, so the dashboard subtracts observed spend from your numbers in limits.json. If your plan's cap changes and you don't update the file, the dashboard is wrong in exactly the way you'd expect. Keep limits conservative.
  • Dispatch simulation prices, it doesn't predict. It estimates a task's cost at flat per-token rates; real overage behavior, mid-task rate-limit backoff, and request-based floors aren't modeled. Treat "fits" as "has budget for this size", not a guarantee.

Install

pip install blackbox-bill
# or from source:
pip install .

Zero dependencies — Python 3.9+ stdlib only.

Example output

blackbox-bill v0.3.0 — where the money went
============================================================
Bill rows: 5   requests: 68   billed total: $27.00

## Tokenizer-aware token figures
Measured under: legacy tokenizer (Claude <=4.5).
Input tokens:  300.0K (legacy) ~= 390.0K (claude-4.7, x1.3)
Output tokens: 60.0K (legacy) ~= 78.0K (claude-4.7, x1.3)
Total tokens:  360.0K (legacy) ~= 468.0K (claude-4.7, x1.3)
(claude-4.7+ figures are approximations, not re-tokenized counts)

## Pool-normalized summary
cursor-models     2 rows       8 reqs  $     3.00
    claude-opus-5.5                    8 reqs  $    3.00
other-models      3 rows      60 reqs  $    24.00
    grok-4                            40 reqs  $   16.00
    gemini-4                          20 reqs  $    8.00

## Explanations

[pool-drain] Why your 'Other Models' pool drained first
Auto-model routing sent most of your billable work to non-Cursor models...
Evidence: 3 row(s), 60 request(s), $24.00.
...

Development

python3 tests/test_blackbox_bill.py          # 69 checks, <2s
PYTHONPATH=src python3 -m unittest discover -s tests -t .   # 28 v2 checks

License

MIT

Metadata

Release files for blackbox-bill 0.3.0

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

Built distribution (wheel)

Table of built distributions (wheels) for blackbox-bill 0.3.0
File Interpreter ABI Platform
blackbox_bill-0.3.0-py3-none-any.whl Python 3 none any Details

Release files / blackbox_bill-0.3.0-py3-none-any.whl

Download URL blackbox_bill-0.3.0-py3-none-any.whl
Size 35.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5e9c07c87487eea6412f520b164aab36442c2abca0be56980faeba2657601b9a
BLAKE2b-256 checksum
How to use checksums
2cce4d5c28833ae5a0555888236836f83ce3b361dc487f8a7d6d20814160e64e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.3

Security for blackbox-bill 0.3.0

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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Release history Release notifications | RSS feed

This release

0.3.0 This release

1 release file No provenance

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