Usage audit · 30 days to Sep 14 · 8,900 transcripts, verified twice

Where the tokens go, and how to stop dying at the wall

We don't run out of capacity because sessions are too big. We run out because subagents wait, then pay full price to reread everything they already knew.

48%

Roughly half of everything we spent in the last 30 days is three things: subagents rewriting their cache after a short wait, spin/poll loops, and a handful of runaway subagents. That share holds (39–54%) no matter how you weigh the tokens.

All three got a fix today. Two more fixes are ready and waiting on your go-ahead.

On this page

01What the usage meter actually counts

A subscription doesn't show a dollar bill, so we had to reverse-engineer what the 5-hour/weekly meter actually charges for. We compared 26,686 meter readings against the tokens each session was using at that exact minute.

Answer: the meter is not counting raw tokens. A reused chunk of context ("cache read") is nearly free. Writing a new chunk of context (a "cache write") costs full price. That's the whole story.

Token typeWeight on the limitNote
Cache writes (new context)Full weightCounts like typing it fresh
Fresh inputFull weight 
OutputFull weight 
Cache reads (context we already had)0.0063 per token95% CI 0.0031–0.0132 — cheaper even than the API's own 0.1 discount

Practical rate: about 0.5% of a 5-hour session per million cache-discounted tokens. One sentence version: a big context that stays cached is nearly free; re-writing it after the cache expires is what costs.

The input/output multipliers (82x and 13x) came back with very wide error bars — real, but not precise enough to use as a price list. Only the cache-read discount is a sharp, repeatable number.

One weekly pool, and Fable drains it fastest

There is one weekly pool per account, not two. Anthropic's support article "Claude Fable models on your plan" says Fable may use up to 50% of the weekly limit and that "your use of other models draws from the same usage limits." The "weekly Fable" meter is that 50% sub-cap. A half-empty Fable meter next to a full "weekly all" meter is not spare capacity.

Our own meter history agrees (per million cache-discounted tokens, non-negative least squares over the same windows as above; details in tools/token-audit/meter_by_model.md):

Model5-hour meter, relative to OpusWeekly meter, relative to Opus
Fable2.4x (95% CI 1.65–3.26)3.1x (95% CI 2.02–4.47)
Opus1x1x
Sonnet0.76x0.79x

Consequence: moving subagent work onto Fable would empty the shared pool two to four times faster. Fable stays where it pays, judgment and orchestration.

02Where the last 30 days went

30-day tokens
137.1B
17.72B once you weigh in cache discounts
Subagents vs. main
86%
inside subagents, 14% in Fede's main sessions
Model mix (weighted)
Sonnet 48%
Opus 37% · Fable 14% · Haiku 0.2%

Sonnet and Opus are, for practical purposes, 100% subagent work. Fable is, for practical purposes, 100% Fede's main sessions. The rule that keeps orchestration on Fable and hands worker jobs to subagents is being followed. The problem sits inside how those Sonnet/Opus workers behave, not in who's driving.

ModelShare of weighted spendRuns mostly as
Sonnet 548.2%Subagent worker (99.5% of its spend)
Opus 536.7%Subagent worker (99.6% of its spend)
Fable 5 + 5.114.1%Fede's main sessions (95%+ of its spend)
Opus 4.80.8%Mostly main sessions
Haiku 4.50.2%Barely used at all

4 in 10 subagent launches (42.1%) don't pass a model at all and fall back to whatever the default is — that's still a gap in the "route by task" rule.

02.5The top 3 offenders

RankWhatSizeEvidence
#1Idle subagents re-writing their whole context. Subagents keep their cache for 5 minutes; main sessions get an hour. Any pause past 5 minutes — a long wait, watching CI — forces a full, pricier re-write.2.87B weighted tokens (16.2% of everything)A subagent idle 5–15 minutes rewrites its cache 86% of the time, vs. 7.8% for a main session in the same gap.
#2Spin/poll turns — the same command run 100+ times in a row inside one subagent.2.64B weighted tokens (14.9%)64,623 such turns across 30 days. The Sep 12 guard has refused 358 of them since; almost all the damage predates it.
#3Ten runaway Opus subagents, all spawned from Fede's main sessions, that stayed alive near the 1M-token ceiling.1.52B weighted tokens (8.6%)Six of the ten hit over 850k context; five hit over 966k. The worst ran 4,057 turns over 20 hours.

Same three offenders, checked against three different ways of weighing a token

Fede pushed back on the ~40% headline, so we re-ran it under the meter's real cache-read discount instead of the API price list. The share went up, not down — the API price list was actually the conservative estimate.

Weighting#1 idle rewrites#2 spin/poll#3 top-10 subagentsUnion (no double-count)
Cache-writes only53.7%1.6%3.1%54.4%
Meter-realistic (best estimate)42.4%5.0%4.5%47.6%
Pessimistic bound34.3%4.6%3.8%39.1%

The defensible number: these three things are 39–54% of 30-day spend, best estimate ~48%. The ranking that matters more than the total: under a realistic weighting, idle cache rewrites alone dwarf the other two (42.4% vs. 5.0% and 4.5%). Spinning looked expensive under a raw-token view because it generates huge cache-read volume — which the meter barely charges for. The cost was never the polling. It was the cache rewrites the polling caused.

03Did the Sep 12 fix help?

Short answer: it stopped the spinning completely, but total spend did not go down, because the subagents switched from spinning to waiting through one long pause instead — and every pause over 5 minutes still rewrites the whole cache.

DateSpend that daySpin turnsSpin costCache-rewrite costActive subagents
Sep 1179M84331M11M145
Sep 2252M1,53081M19M104
Sep 31,228M6,290346M124M342
Sep 4423M1,71478M36M220
Sep 5649M6,834285M43M94
Sep 6794M2,803141M51M418
Sep 7655M4,124152M47M259
Sep 8623M3,77885M55M288
Sep 91,364M3,902172M160M354
Sep 101,010M4,107112M125M295
Sep 111,286M10,377511M107M304
Sep 12 guard shipped mid-day1,400M6,865239M197M486
Sep 13744M00174M250
Sep 14 (partial)300M0037M176

Daily trend (auto-updated)

DateCache writesSubagent idle re-writesMain-session re-writesSpin turnsFable cache writesGuard denials (wait / turn-cap / read / bash-output / idle-resume)
Sep 6117.1M31.5M4.3M2,31610.8M
Sep 793.6M34.5M3.0M3,8138.1M
Sep 8109.1M36.3M6.2M2,00516.4M
Sep 9253.4M110.1M11.5M2,77537.5M
Sep 10193.3M75.4M5.6M1,98330.8M
Sep 11168.6M78.7M4.3M8,01815.5M
Sep 12286.6M144.2M3.4M5,81119.5M
Sep 13237.4M152.3M8.4M024.1M
Sep 1499.4M40.8M1.8M015.4M
Sep 1598.3M30.6M2.4M011.5M
Sep 1689.9M19.2M1.1M5314.7M
Sep 17122.6M28.7M2.3M017.6M
Sep 18210.5M40.8M0.8M024.4M0 / 0 / 52 / 548 / 5
Sep 196.4M0.9M0.3M00.5M

Targets: subagent idle re-writes under 45M/day (one third of the Sep 12–14 average of 136M), spin turns 0.

Before the guard (Sep 1–11)
769M/day
4,209 spin turns/day · 23.5% of spend was spinning
After the guard (Sep 12–14)
815M/day
2,288 spin turns/day · only 9.8% of spend is spinning
Rewrite cost per day
70.7M → 136.1M
nearly doubled — the cost moved, it didn't leave

Offender #2 turned into offender #1. The next fix has to remove the wait itself from big-context subagents, not just stop them from spinning while they wait — that's exactly what today's wait-guard hook (section 8) does.

04Runaway subagents

Most subagents are short. A median subagent runs 32 turns. But the distribution has a long tail, and that tail is where the money is.

p50p75p90p95p99Longest
32 turns73 turns214 turns363 turns950 turns4,057 turns

What a hard turn cap would have removed, if it only cut off the tail past that point (gross removal — doesn't count the cost of re-spawning a fresh agent to finish the work):

Cap atSubagents that ran past itSpend past the cap% of 30-day spend
100 turns933 of 4,647 (20%)2.24B51.5%
200 turns5051.60B36.8%
300 turns2961.17B26.8%
500 turns1470.64B14.7%

One subagent in five produced half the month's bill, in the part of its life after turn 100 — the part where it had stopped building and started waiting. This is the direct evidence behind today's 300-turn cap (section 8).

05Checked and cleared — not the problem

ClaimVerdictWhy
Fixed per-session overhead (CLAUDE.md, memory, skills)Small~26k tokens per session (main sessions 29.5k, subagents 26.2k); after the first turn, near-zero grows in
The 1.77MB portfolio-architecture doc, read in full every sessionRefutedSessions read only the slices they need, never the whole file
Headless bots (Smith, Trinity, cron)Small2.9% of all spend
Guard hooks (poll-guard, load-guard, etc.)Zero costThey emit no output on a normal pass-through

06Earlier audits — what actually got done

Two real audits happened before this one, a month apart, both triggered by Fede hitting a wall rather than by anyone checking proactively.

AuditWhat it foundWhat happened to it
Aug 15Every subagent defaulted to OpusFixed in config — global default is now Sonnet
Aug 15Route work by task: Haiku for pulls/extraction, Sonnet as the workhorse, Opus for hard cases; drop effort for routine agentsRule only — written in CLAUDE.md, no hook enforces it; 42% of launches still skip the model param
Sep 12–13Subagents burning turns spinning on CI/status checksFixed with a hook — poll-guard shipped same night, and it works (see section 4)
Sep 12–13"Auto-compact is now automatic at 250k"Never actually set — no such setting exists anywhere on disk; today's audit fixed the real setting (section 8)
Sep 4CLAUDE.md + CONSTITUTION.md cost ~57k tokens/session before pruningPartially done — pruning is still pending review

The pattern across both prior audits: the finding that got a hook (poll-guard) actually stuck. Everything left as "a rule in CLAUDE.md" — model routing, effort levels, orchestrators not doing worker jobs — kept happening anyway, because nothing on the machine enforces it.

07What we changed today

All five below are live and verified on disk — not proposals.

08How CI-watching should work

The infrastructure to do this the right way already exists — it just isn't being used consistently.

  1. Push, not poll. A GitHub webhook forwarder plus a local event file already track every check run — 33,125 rolled-up events logged so far — and a session-wake hook can resume a session the moment something changes.
  2. Builders never watch CI. That's already the rule; today's wait-guard hook (section 8) makes it mechanically true for big subagents instead of just written policy.
  3. The woken main session spawns a small, fresh subagent to act on the result — it doesn't sit there itself.
  4. Proposed: wake only on the rolled-up "checks-passed / checks-failed / verdict" events, one wake per commit, instead of every intermediate status change. This cuts wake volume without losing any signal.

09Proposed next — pending Fede

These are recommendations, not done yet. Both are cheap and low-risk; neither touches anything customer-facing.

10Claims we checked and found false

ClaimVerdictWhat the data actually says
An account can go from a fresh reset to capped in under a dayFalseFastest observed in 30 days: 27.6 hours. Most accounts take 55–142 hours.
The 1.77MB portfolio-architecture doc is read in full every sessionFalseSessions only ever read slices of it
Fixed per-session overhead is a major driver of spendFalse~26k tokens/session — small next to the 2.87B-token rewrite category

§Appendix: the Aug 15 plan

Everything below is the original Aug 15 audit, unchanged, kept for the record. Where an item from it is now live, it's marked.

The money map (as of Aug 15)

A subscription doesn't bill dollars, so to compare consumption across models we weighted every token by its published API price — the best available proxy at the time for how hard each token pushes on the 5-hour and weekly limits.

30-day pressure (Aug 15)
86,000
weighted units, all sessions
Opus share
59%
almost all of it swarms
Haiku + Sonnet
0.17%
effectively unused
Opus 5subagent swarms
59%
Fable 5main sessions
40%
Sonnet 5a handful of runs
0.14%
Haiku 4.5almost never
0.03%

Live now By the Sep 14 audit, Sonnet and Opus have real usage (48.2% and 36.7% of weighted spend) — the "essentially unused" cheap-model problem from Aug 15 no longer exists at the model-choice level. The remaining leak is behavioral (idling, spinning, runaway turns), not "everything defaults to Opus."

The swarm default was the leak

The subagent model was pinned to Opus globally, on the assumption that agents are always coding. Most fan-outs are actually research, extraction, search-pulling, summarizing, verifying — work a smaller model does at a fraction of the pressure.

Task the agent is doingModelWhy
Pull / collate raw search results, scrape, extract fieldsHaikuRoutine, verifiable, high volume
Summarize, grep / explore a codebase, first-pass draftingHaikuCheap, fast, good enough
Research a profile, verify facts, normal implementationSonnetThe workhorse; far lighter than Opus
Adjudicate ambiguity, hard debugging, architecture, final synthesisOpusWorth the pressure — but the minority of work

Live now Global default is Sonnet, not Opus. Still rule-only Per-task routing to Haiku/Opus depends on each launch remembering to pass a model — 42% still don't.

When the wall hit, nothing caught it

Across the Aug 15 window we found roughly 1,500 limit hits clustered into 25 "walls" — moments where an account capped and everything on it died at once, 85–99% of a swarm's workers within five minutes of each other.

Fede's sessions
76%
needed him back to retype "continue"
Swarm workers
88%
died on the spot, no resume
Dead time
~180h
30 days · median 18 min per hit

Assumptions, validated (Aug 15)

AssumptionVerdictHow we knew
Subagent swarms all ran OpusConfirmed100% of 6,685 subagent runs, 30-day scan
The rotation tool refreshes the account a live session holds, killing itWrongCode check: it never refreshes the active account
Several long-running sessions on one account revoke each otherStrongly inferredRefresh tokens are single-use families; stacking 4 sessions on one account killed it
Keychain is the source of truth, the file is secondaryConfirmedThe switch writes Keychain first — the two can desync, Keychain wins
cron can't do the account switchConfirmedKeychain write exit 195, crontab "operation not permitted" — twice
A session launched from inside another hangs before its first requestConfirmedReproduced 3x
Hot-swapping the account under a running session worksPromising, unprovenNew account's meter rose while old held, but subagents confound it
apiKeyHelper accepts a subscription token (clean rotation path)UntestedCouldn't test from a nested session
A per-request pool proxyAvoidNeeds cloaking; failure mode is an account ban

The plan — leaner, then bulletproof

  1. Route by task, not by default. Drop the global Opus pin; every fan-out declares a model per role. Still rule-only past the global default
  2. Budget-gate every fan-out. Check pool headroom before launching N agents. Live now — the budget tool reads live pool headroom and sizes fleets against it.
  3. Put headroom in front of Fede. Pool capacity and time-to-reset in the status line. Live now — in the ccswitch statusline.
  4. One supervisor that runs as Fede — owns pool health, account assignment, pause/wake, re-driving dead turns. Live now — running under launchd, currently supervising 38 resumed sessions.
  5. Every worker checkpoints as it goes — a wall pauses a swarm instead of killing it. Live now — the checkpoint contract is a standing block in the fleet skill's developer briefs.
  6. Proactive rotation before the wall — switch at a safe threshold, never refresh an account a live session holds.
  7. Auto-resume at reset — park capped sessions, wait for the real reset, switch, re-drive every parked session.

The POC (built Aug 15, since matured)

PieceWhat it doesState as of Sep 14
budgetReads live pool headroom, sizes a fan-out, downshifts the model when shortLive in production use
ccdThe supervisor loop — proactive rotate, park when capped, sleep-until-reset, spread across accountsLive under launchd, 38 sessions resumed
checkpoint contractThe brief block every long worker carries so progress lives on diskNow standing in the fleet skill
exp1 / exp2Terminal experiments settling live-swap and apiKeyHelperStill not run
Sources · Sep 14 audit: 8,900 transcript files, 7.15GB, deduped by message.id, cross-checked against a from-scratch rewrite of the original parser · 26,686 usage-meter readings, Aug 15–Sep 14 · Aug 15 appendix: 9,159 transcript files, rotation-tool cache + logs, live swap test on the workstation.
Weighting note · "billed-ish" = input + 1.25x cache_creation + 0.1x cache_read + output (API list prices, used only as a cross-check) · the meter-realistic weighting in section 3 instead uses the fitted cache-read discount of 0.0063 from the regression against real meter movement.
Unverified & flagged · exact subscription weighting formula (Anthropic doesn't publish one) · apiKeyHelper subscription-token acceptance · exp1/exp2 not yet run.
PropFlow Docs