# 0014: Claude Code usage comes from its transcripts, and reports spend without a ceiling Status: accepted for token spend. **Corrected by decision 0015**: this record originally claimed Claude Code exposes no quota window. That was wrong — it does, through the status line — and the claim is struck below rather than quietly edited out, because the reasoning that followed from it shaped the adapter. Decision 0013 established the provenance test for a usage adapter: does the harness forward a provider's number, or record its own? Claude Code is the case that makes the second half of that test matter. ## Correction The original text asserted that "Claude Code publishes no quota API and no remaining-balance command" and that a user asking how much they have left "gets the honest answer — Lumbridge can show what was spent, and cannot show what remains, because Claude Code does not say." **Both statements are false.** Claude Code 2.1.80 and later pipe a `rate_limits` object with `five_hour` and `seven_day` windows to the configured `statusLine` command on every turn, and the CLI documents that shape itself. There is also an account usage endpoint. The correct claim is narrower and is the only one this record still makes: *the transcript* carries spend and not quota. Decision 0015 covers the window surface. ## The surface What Claude Code writes to disk per session is the API's `usage` object for every assistant turn, appended to a per-session JSONL transcript under `$CLAUDE_CONFIG_DIR/projects` (default `~/.claude/projects`). Each assistant record carries `input_tokens`, `output_tokens`, `cache_creation_input_tokens`, and `cache_read_input_tokens`, alongside the model that produced it. Summing those is how this adapter reports spend. **A subscription's window, ceiling, and reset are not in the transcript**, so this profile reports consumption against no ceiling rather than implying a quota — but that is a fact about this file, not about Claude Code, and the quota is read separately under decision 0015. The `statusLine` hook does require mutating the user's `settings.json`, which is why the transcript came first: reading a file the harness already writes needs no change to the user's configuration. That was a good reason to build this adapter, and a bad reason to conclude the other surface did not exist. ## Why harness-reported Claude Code forwards the provider's per-response counts faithfully, so a single record's numbers originate with the provider. But a running total is the *harness's* record — an append-only log Lumbridge is reading, not a provider's statement of account. Under 0013's rule the value is therefore `HarnessReported`, and the footer says `harness · approximate`. ## Content blindness is structural, not procedural **These files contain the user's conversations.** The parser models exactly four integers, a record type, and a model name. Every other field — message text, tool inputs, file contents, `service_tier`, `inference_geo`, `server_tool_use` — is discarded by serde during parsing, because there is no field in the wire types that could hold it. A test asserts that no debug rendering of a parsed record can contain message content. That is the same discipline as the Codex probe's refusal path: the safe behaviour is made unrepresentable rather than merely avoided. ## What "tokens" counts The reported number is `input + output + cache_creation + cache_read`. Cache reads are included because they are billed and do count against a subscription window, even though they are re-reads of context already counted once. Excluding them would understate consumption. Weighting them by price would require a price list this adapter does not have, and would turn a counted fact into an estimate. In practice cache reads dominate the total — on the transcripts this was verified against they were roughly 98% of it — so the derived burn rate is largely a measure of context re-read per turn rather than of new work. The split is preserved in `TokenTally` for a detail view that can say so. ## Priming before reporting The probe is a tail follower: it remembers a byte offset per transcript and reads only what was appended since, so its running total is monotonic by construction. The ledger rejects an observation that moves a profile backwards, so this is a correctness requirement, not an optimisation. It also **reports nothing until it has read every existing transcript to its end**. A partially-read backlog is indistinguishable from an enormous burst of spend, and the ledger will derive a burn rate from it: the first run against a 20 MB backlog with an 8 MB per-poll budget reported **forty-six billion tokens an hour**, which was catch-up, not usage. The first reading must be a true baseline before any rate derived from it can mean anything. A shrinking file resets its own offset rather than trusting a position into different content. ## Bounds A scan walks at most six directory levels and 4096 files, never follows symlinks out of the tree, reads at most 8 MB per poll, and refuses a single record over 1 MB while still advancing past it. A transcript's last line is routinely a partial record still being written; it is left unconsumed for the next read rather than parsed or skipped.