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:
- 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. - Tokenizer-aware token figures — every token total is shown in both tokenizer equivalents (
--tokenizer legacy|claude-4.7,--tokenizer-factorto 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. - 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.
- Local-log cross-check — joins bill rows against your
~/.claude/projects/**/*.jsonland~/.codex/sessions/by time window, reporting matched vs orphaned spend. - 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).
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
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
--resumeruns. 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 after the fact, 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.
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-hoursor 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-filefor your own numbers.
Install
pip install blackbox-bill
# or from source:
pip install .
Zero dependencies — Python 3.9+ stdlib only.
Example output
blackbox-bill v0.2.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 # 41 checks, <1s
PYTHONPATH=src python3 -m unittest discover -s tests -t . # 28 v2 checks
License
MIT
Metadata
Release files for blackbox-bill 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| blackbox_bill-0.2.0.tar.gz | 34.6 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| blackbox_bill-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 62.7 kB
Release files / blackbox_bill-0.2.0.tar.gz
| Download URL | blackbox_bill-0.2.0.tar.gz |
|---|---|
| Size | 34.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
5a2be6ce953d7c7affd20c8cb0e502348862b9ec7cb278cd72b4b31c66d4fd08
|
|
BLAKE2b-256 checksum How to use checksums |
d542e39f4ec5e0a3866d207ddac3e2b978d85c21014428c556a9ea57908d8310
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Release files / blackbox_bill-0.2.0-py3-none-any.whl
| Download URL | blackbox_bill-0.2.0-py3-none-any.whl |
|---|---|
| Size | 28.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c26de6fc34c29f36642b79f68d647ce542bd4680792262469195a51a890366da
|
|
BLAKE2b-256 checksum How to use checksums |
b92cd45114aafe05ec9f0b0c0e5a3542de91f8cf0c412acf2f43d469e7dfac0a
|
| 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.2.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.