Home · Guides · Find your most expensive Claude Code sessions
Find your most expensive Claude Code sessions
Your bill is higher than usual, but token-meter stats only gives you a daily/model
rollup — it doesn't point at a culprit. token-meter audit does: it ranks sessions by cost
share and flags short sessions on high-cost models, so the answer becomes "this one session," not
"sometime this week."
Updated 2026-07-15 · applies to @whdrnr2583/token-meter current release.
Problem
You glance at your Claude Max/Pro usage or your API invoice and it's noticeably higher than a normal
week — but nothing tells you why. token-meter stats 7 shows totals per day and
per model, which is enough to see that spend went up, but not enough to see which
session, sub-agent, or model choice actually drove it. Scrolling through
~/.claude/projects/*/*.jsonl by hand to find the expensive one doesn't scale once you have
more than a handful of sessions a day.
Cause
In practice, a spend spike almost always traces back to one of three patterns:
-
One long session dominated the period. A multi-hour session with a lot of tool
calls, large context, or repeated back-and-forth can rack up cost that dwarfs everything else that
week, even though no single message in it looks unusual.
-
A sub-agent (Task/Agent) burned tokens you didn't see. Sub-agent JSONL rows carry
the parent session's ID, so a runaway sub-agent's cost hides inside a session total unless
you specifically split main-session spend from sub-agent spend.
-
A short session ran on an unnecessarily expensive model. A quick exchange on Opus
or Fable that produced almost no output still bills at the top-tier rate — fine if the task
genuinely needed it, wasteful if a cheaper model would have done just as well.
The audit command's expensive_session (D1) and
high_cost_model_signal (D6) detectors exist specifically for the first and third
patterns; the sub-agent split (pattern 2) is covered separately by token-meter subagents,
shown below as a cross-check.
Command
Ingest first if you haven't recently (audit reads only what's already in the local SQLite DB), then run the audit:
token-meter ingest
token-meter audit --days 7
Full flag set, verified against src/cli.ts:
token-meter audit [--days N] [--source all|claude|codex] [--project <value>] [--limit N] [--json]
--days N — trailing window, default 7. Clamped to your history entitlement (Free: 7 days, Pro: 30 days) the same way stats/subagents are; a larger request prints a clamp warning to stderr and still runs.
--source all|claude|codex — restrict to one source (claude/codex map to the internal claude-code/codex identifiers). Default all.
--project <value> — exact-match filter once you've narrowed down which project the culprit is in.
--limit N — caps findings returned after ranking. Default 5 in terminal mode, 20 in --json mode.
--json — prints the full AuditReport as indented JSON instead of the terminal summary, for scripting.
Synthetic output
⚠ Fictional numbers below — not real user data. Formatted exactly as src/audit/reporters/terminal.ts renders it.
$ token-meter audit --days 7
TOKEN METER AUDIT — LAST 7 DAYS
Sources
claude-code: available (940 records analyzed, 100% of window covered)
codex: partial (58 records analyzed, 71% of window covered — see warnings)
Confirmed usage
Tokens: 4.04M total (in 610.0k, out 89.0k, cache 3.35M)
Estimated cost: $58.3200
Efficiency signals
Findings: 2
Cost associated: $43.2000
Confidence: medium
1. Session accounted for 70% of analyzed cost
Source: claude-code
Project: /Users/jordan/dev/api-gateway
Session: a3f9c1-88be-4d02
Tool: -
Evidence: $41.02 across 268 events over 214 min (top model: claude-opus-4-8). That's 70.3% of $58.32 across 11 sessions in the 7-day window.
Confidence: high
Suggested action: Review this session's transcript to see what drove the cost (model choice, tool calls, context size).
2. 2 short opus-4-1 sessions with minimal output
Source: claude-code
Project: /Users/jordan/dev/api-gateway
Session: -
Tool: -
Evidence: opus-4-1 is billed at $75/M output tokens — at or above this audit's high-cost bar of $25.00/M, derived from the current pricing table rather than a hardcoded model name. b7e2af-11cc (/Users/jordan/dev/api-gateway): 47s wall-clock, 210 output tokens, $1.3120. d94a02-77f1 (/Users/jordan/dev/api-gateway): 63s wall-clock, 340 output tokens, $0.8680. Separately: project "/Users/jordan/dev/api-gateway" alone accounts for 74% of total analyzed spend in the 7-day window ($43.20 of $58.32) — a cost-concentration signal worth noting alongside the model-tier pattern above.
Confidence: low
Suggested action: Review whether every short session required this model.
Warnings
- [codex] cache_inefficiency (D5) does not run for Codex: Codex's usage payload never reports cache_write_tokens, so cache-waste-day detection is structurally unavailable for this source (see src/audit/detectors/cache-inefficiency.ts).
Interpretation
-
Finding 1 (D1,
expensive_session) — session a3f9c1-88be-4d02
in api-gateway alone accounted for 70% of the week's analyzed cost. confidence: high
means it's backed by enough events (≥3) that one anomalous row isn't the whole story — this is the
session to open first.
-
Finding 2 (D6,
high_cost_model_signal) — two short, low-output sessions
ran on opus-4-1 ($75/M output — well above the $25/M "high-cost" bar the detector derives
from the current pricing table, not a hardcoded model list). Together they're a small dollar amount
($2.18) next to Finding 1, but the pattern — quick exchange, top-tier model, almost no output — is
worth a glance. confidence: low here is not a weaker version of "high"; it's the
detector's honest ceiling, because "was the model choice wrong" is a judgment call no threshold can
settle.
-
The folded-in project note ("project ... alone accounts for 74%...") is D6's
secondary signal, not a separate finding —
api-gateway is where essentially all of this
week's spend concentrated, across both findings.
-
Cost associated: $43.2000 is the deduplicated sum of both findings' costs
($41.02 + $2.18) — safe to trust as-is; findingsMayOverlap would flip to true (and get
called out in the terminal text) only if two findings shared the same underlying session.
-
codex: partial in Sources plus the D5 warning means: this account has Codex activity,
but the cache-waste detector structurally can't run against it — not a bug, not missing data.
Cross-checking with subagents and stats
D1 tells you which session; it doesn't tell you whether that session's cost was the main
conversation or a sub-agent running underneath it. Check the sub-agent split for the same window:
token-meter subagents 7
$ token-meter subagents 7
=== Sub-agent costs (7d) ===
Main: $50.1400 events=712
Sub-agents: $8.1800 events=228 (14.0% of spend)
Priciest sub-agents:
agent-7f3a21 $6.4400 events=94 out=41.2k opus-4-8
agent-04e9bb $1.2100 events=52 out=9.8k sonnet-4-6
agent-b810c4 $0.5460 events=82 out=4.1k haiku-4-5
Invocation latency (parent-side Task/Agent calls):
Task calls= 18 avg=42.3s max=118.7s
Here sub-agents are only 14% of total spend, and the single priciest sub-agent
(agent-7f3a21, $6.44) is well under Finding 1's $41.02 — so this particular session's cost
is mostly main-conversation spend, not a runaway sub-agent. If instead agent-7f3a21
had cost close to $41, that would point you at the Task/Agent prompt that spawned it, not the parent
conversation.
One gotcha: if Sub-agents: $0.0000 events=0 shows up on an account you know has run
sub-agents, it's not that none ran — agent_id attribution was only backfilled starting in
v0.1.19. Run token-meter ingest --force once to reprocess older JSONL and
recover the split.
To confirm the model breakdown independently (and rule out that Finding 1's cost is just one project
having a busy week rather than the flagged session specifically), run:
token-meter stats 7
and check whether api-gateway's row under By project and claude-opus-4-8's
row under By model roughly match what the audit finding already told you. If they don't line
up, something else in that project (not the flagged session) is also contributing, and it's worth a
second audit --project /Users/jordan/dev/api-gateway --days 30 scoped run.
Actions
-
Open the flagged session's transcript. The audit finding gives you the exact
session ID and project path — on the Free tier, locate the JSONL directly at
~/.claude/projects/<project-slug>/<session_id>.jsonl and look at what ran in
that window. Pro adds a dashboard session drill-down (down to the message) so you don't have to grep
JSONL by hand.
-
If
subagents shows a high sub-agent share for that window, look at
which agent_id is priciest and, separately, at the Task/Agent invocation latency block —
a high avg/max latency alongside a high-cost sub-agent usually means the
parent prompt is handing off too broad a task; narrowing the sub-agent's scope cuts both cost and
wall-clock time.
-
If a D6 finding recurs, decide case by case whether those short sessions actually
needed the flagged model — route genuinely trivial follow-ups to Sonnet/Haiku instead, but don't
treat every low-output Opus session as waste; a hard one-shot judgment call can legitimately be short
and need the top-tier model.
-
Re-run scoped once you have a suspect.
token-meter audit --project /Users/jordan/dev/api-gateway --days 30 (Pro, for the
30-day window) confirms whether the pattern is a one-off spike or a recurring habit in that project.
-
Script it if this becomes a weekly habit.
token-meter audit --json --limit 20
gives you the full AuditReport (see docs/audit-schema.json) to pipe into a
saved file or a simple weekly diff, instead of re-reading the terminal output by eye every time.
Limitations
-
Cost is a USD-equivalent estimate, not your invoice. Every number here comes from
pricing.ts's list-price table applied to token counts — on a flat-fee plan (Claude Max)
this shows what the same usage would have cost on metered API pricing, not money actually charged.
-
audit can tell you which session, not why. tool_events
stores no call arguments by design (a deliberate privacy invariant, not a gap) — so a finding can
point at a session or a tool pattern, but never show you the actual prompt text, file contents, or
command that ran. You still have to open the transcript.
-
The related detector
repeated_similar_tool_calls (D4) is a proxy, not proof.
If your "runaway session" investigation leads you to suspect duplicate tool calls, note that D4 can
only match on same tool + same session + similar response size within a 5-minute window — never on
actual argument equality, since arguments aren't stored. Two Read calls on genuinely
different files, or a legitimate retry loop, can both match. Confidence is capped at medium
for exactly this reason.
-
D6's confidence is always
low, by design. The duration/output/model-rate
thresholds are objective, but "was this model choice actually unjustified" is a judgment call no
threshold can prove — treat every D6 finding as a review prompt, never a downgrade instruction.
-
History is entitlement-clamped. Free caps
--days at 7; Pro at 30.
Requesting more prints a clamp warning to stderr and still runs at the capped value — it won't error
out, but it also won't quietly show you more than your tier allows.
-
Cache-waste detection (D5) never fires for Codex — Codex's usage payload never
reports
cache_write_tokens, so a Codex event can't structurally satisfy that detector's
condition. A --source codex audit legitimately returns zero D5 findings; it isn't a
missed detection.
Related guides