Spend · Billing Guard CLI
Billing Guard CLI
What it is
repoops-billing-audit is the portable shell around the Billing Guard reconciliation engine. One run:
- Reads local Claude Code JSONL transcripts (default
~/.claude/projects, override with--claude-dir) and folds them into a day-by-model token ledger. Your ground truth; it never leaves the machine. - Pulls the Anthropic Admin Usage & Cost API for the same window when
ANTHROPIC_ADMIN_KEYis set. The provider's claim. - Recomputes expected cost from token counts times a versioned rate card and compares inside a tolerance band (default 2%).
- Prints a findings table (day, model, expected, billed, delta, signature) plus a coverage summary, and writes an evidence bundle JSON shaped for a finance dispute.
Exit codes make it automation-friendly: 0 everything reconciles, 1 findings, 2 configuration error.
Prerequisites
- Node 20 or newer. Check with
node --version. - Claude Code telemetry present. If you use Claude Code on this machine, transcripts already live under
~/.claude/projects. No setup needed. - Optional: an Anthropic Admin key. From console.anthropic.com: Settings, then API keys, then Create Admin Key. Set it as
ANTHROPIC_ADMIN_KEYin the environment. Without it the CLI runs in telemetry-only mode: it prints the expected-cost ledger it can compute locally plus a clear "cannot verify without an Admin key" note. It never fakes a finding.
Install and run
npx repoops-billing-audit does not work yet: publishing the package is a pending operator decision. Until then, run it from a checkout, or via the GitHub form if you have access to the repository.From a checkout (works today)
git clone https://github.com/sellingascode/repo-dashboard.git cd repo-dashboard npm install node bin/billing-guard.mjs --window 30
Via npx from GitHub (authorized users)
npx --package github:sellingascode/repo-dashboard repoops-billing-audit --window 30
This resolves the package straight from the repository, so it needs GitHub access to it.With verification enabled
# PowerShell $env:ANTHROPIC_ADMIN_KEY = "sk-ant-admin01-..." node bin/billing-guard.mjs --window 30 --out billing-guard-report.json # bash / zsh ANTHROPIC_ADMIN_KEY=sk-ant-admin01-... node bin/billing-guard.mjs --window 30
Flags:
--window <days>lookback window (default 30).--tolerance <pct>tolerance band percent (default 2).--claude-dir <path>Claude home directory (default~/.claude).--out <path>evidence bundle path (default./billing-guard-report.json).--jsonprint the evidence bundle JSON instead of the table (for scripts and CI).
Scheduled background runs
The audit is cheap and read-only, so a daily background run on a managed laptop is the natural setup. Neither example below needs admin rights.
Windows: per-user Scheduled Task. Runs daily at 09:00 under your own account:
schtasks /Create /SC DAILY /ST 09:00 /TN "RepoOpsBillingAudit" ^ /TR "node C:\path\to\repo-dashboard\bin\billing-guard.mjs --window 30 --out C:\Users\you\billing-guard-report.json"
Set ANTHROPIC_ADMIN_KEY as a user environment variable first (setx ANTHROPIC_ADMIN_KEY sk-ant-admin01-..., then a fresh session picks it up). Remove the task with schtasks /Delete /TN "RepoOpsBillingAudit".
macOS: LaunchAgent. Save as ~/Library/LaunchAgents/ai.repoops.billing-audit.plist, then launchctl load it:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"><dict>
<key>Label</key><string>ai.repoops.billing-audit</string>
<key>ProgramArguments</key><array>
<string>/usr/local/bin/node</string>
<string>/path/to/repo-dashboard/bin/billing-guard.mjs</string>
<string>--window</string><string>30</string>
<string>--out</string><string>/Users/you/billing-guard-report.json</string>
</array>
<key>EnvironmentVariables</key><dict>
<key>ANTHROPIC_ADMIN_KEY</key><string>sk-ant-admin01-...</string>
</dict>
<key>StartCalendarInterval</key><dict>
<key>Hour</key><integer>9</integer><key>Minute</key><integer>0</integer>
</dict>
</dict></plist>launchctl load ~/Library/LaunchAgents/ai.repoops.billing-audit.plist
--outcarries both sides' numbers per flagged day.Reading the findings table
Each finding is one row: day, model, expected, billed, delta, signature. The signatures:
- variance-band: the billed day total exceeds the telemetry-recomputed expected cost beyond the tolerance band.
- ghost-usage: the provider reports usage for a day and model on which local telemetry (which was capturing that day) logged zero tokens.
- rate-check: the billed amount implies a per-token price matching no known rate-card row.
- duplicate-burst: provider-reported usage is at least 2x the locally logged usage for the same day.
- delta-alarm: day-over-day billed total grew 3x or more.
- contradiction: the provider's own surfaces disagree; the usage report shows zero tokens while the cost report bills money.
Below the table, the coverage summary is as important as the findings. Days the local telemetry did not capture are listed as cannot-verify, never flagged: missing coverage is not evidence of overbilling. Structural blind spots (Priority Tier costs, code-execution charges) appear as cannot-cross-verify annotations.
The tolerance band
Anthropic explicitly documents client-side cost figures as approximations, so Billing Guard never compares dollars for cent-equality. Token counts are the stable primitive: expected cost is recomputed from your token counts times the published per-model rates, then compared inside the band (default 2%, --tolerance to adjust). A day inside the band reconciles; a day outside it becomes a finding with the raw numbers attached. If your baseline drift runs hotter than 2%, widen the band before trusting the alerts; a band tighter than the real-world approximation noise produces noise, not findings.
Honest limits
- Telemetry is opt-in and local. The ground-truth ledger only covers machines and sessions where Claude Code transcripts exist. A day with no local capture is reported as cannot-verify, not as a finding.
- Subscription plans without Admin API access cannot verify. The Usage & Cost reports require an organization Admin key. Claude subscription plans (Pro/Max) do not expose invoice-side data this way, so the CLI can only run telemetry-only mode there.
- Known Admin API blind spots. Priority Tier costs are excluded from the cost report and code execution is excluded from the usage report; both are surfaced as annotations rather than silently mismatching.
- The rate card is versioned, not omniscient. A model missing from the card makes its day cannot-verify rather than producing a made-up expected cost.
What's next
The dashboard surface for Billing Guard (a section on the spend tab family with the same findings, plus an evidence-bundle export button) is in development. Follow the Billing Guard overview or read the research post on why AI invoices deserve an audit trail.