Glossary & Formulas

Concepts, data sources, and the math behind every number on every page.

Contents

Turn (and conversation) unit of work

The atomic billing unit and the building block of every cost calculation.

A turn is one user-prompt → assistant-response exchange. In Claude Code's JSONL transcript, each turn is a single record carrying:

Cost is computed per turn (see API value). When you see "39,227 turns" on the Insights page, that's the total count of those JSONL records across every parsed session.

A conversation (or session) is a single sessionId — i.e. one continuous chat thread Claude Code kept alive. One conversation contains many turns: opening the session is turn 1, every reply after a follow-up prompt is another turn. A long-running CLI session in a complex project can rack up hundreds or thousands of turns; a cowork "ask once" session might be just two or three.

The Conversations table on the Insights page summarises each session:

See also Turn log cap for how many turns the timeline activity feed retains.

API value cost basis

What every dollar/euro figure on the dashboard represents.

Cost is computed at the pay-as-you-go API rate for each model, regardless of what subscription plan you're on. Even when you've paid a flat $100/mo for Max 5×, the dashboard shows the API cost equivalent of your usage so you can compare value-received against fee-paid.

The cost of a single turn is:

$$ \text{cost}_\text{turn} = \frac{\text{in} \cdot p_\text{in} + \text{out} \cdot p_\text{out} + \text{cw} \cdot p_\text{cw} + \text{cr} \cdot p_\text{cr}}{10^6} $$

where in/out/cw/cr are token counts and the per-million rates come from each model's pricing card. Two pricing pipelines exist:

See Reconciliation for how the two are aligned.

CLI vs Cowork sources

Two distinct ways Claude Code writes JSONL transcripts:

Both produce identical JSONL turn records — the dashboard differentiates them only because the directory structure tells us which entrypoint launched the session.

Worktree project structure

Claude Code can attach a session to a git worktree — a side-checkout of the same repo on a different branch under .claude/worktrees/<random-name>/. Each worktree session writes its own JSONL stream, so build_insights.py sees them as distinct project entries named <parent> (wt: <branch>).

The Projects roster and the dashboard's project filter roll worktrees back up under their parent so a project's true total includes every branch's spend.

Cache hit ratio formula

How much of your prompt was reused vs paid full price for.

$$ \text{hit ratio} = \frac{\text{cache\_read}}{\text{cache\_read} + \text{cache\_create}} $$

cache_read tokens cost ~10% of input rate. cache_create tokens cost ~125% of input rate (the cost of putting them in the cache). A high ratio means long sessions are reusing context efficiently.

Healthy is >85%. Below 50% suggests the model is rehydrating context from scratch each turn.

No-cache hypothetical formula

"What would this have cost if prompt caching didn't exist?"

Without caching, every cache_read token would be re-billed at the full input rate (since they'd be regular input tokens) and cache_create would never have been a separate line item. The savings are:

$$ \text{saved} \approx \text{cache\_read} \cdot p_\text{in} \cdot 0.9 $$

The 0.9 factor is (input rate − cache_read rate) ÷ input rate ≈ (1 − 0.1). Reading from cache is 10% of input price; the saving per token is the other 90%.

Used by Chapter 4 of the Story page and the dashboard's "Cost by Model & Pricing Tier" table.

Monthly projection formula

Average daily cost extrapolated to a 30.44-day month (the average days/month across a year).

$$ \text{monthly} = \frac{\sum_d \text{cost}_d}{|\text{days}|} \cdot 30.44 $$

Span is calendar-day distance between the first and last active day in the selected range, not just the count of active days. So 5 active days inside a 20-day calendar window divides by 20, not 5.

Plan utilization formula

What share of your subscription's flat fee you're getting in API value.

$$ \text{utilization} = \frac{\text{monthly projection}}{\text{plan monthly fee}} \cdot 100\% $$

Pay-as-you-go API and Enterprise plans return n/a (no flat fee to compare against).

Tool categories classification

Every tool invocation is bucketed into one of five categories at parse time:

Cost is attributed to the turn that ran the tool, then divided equally among that turn's tool invocations for per-tool aggregations.

Insights vs ccusage reconciliation cross-source

Two pricing engines, two slightly different totals. ccusage ($A) uses Anthropic's pricing data verbatim. build_insights.py ($B) re-prices from JSONL using static rate tables — typically ~2× higher on cache-heavy workloads.

The dashboard shows ccusage totals (KPI authoritative). When the user filters by project, only insights has the per-project breakdown. To keep the filter consistent, we use insights for shares and apply them to the ccusage day-total:

$$ \text{cost}_{\text{proj},d}^{\text{shown}} = \text{cost}_d^{\text{ccusage}} \cdot \frac{\text{cost}_{\text{proj},d}^{\text{insights}}}{\sum_p \text{cost}_{p,d}^{\text{insights}}} $$

So a project's filtered total is mathematically guaranteed to be a fraction of the day's true dashboard total.

Multi-machine merge cross-machine

Each machine writes its own snapshot to machines/<hostname>.json and pushes via git. build_machine_snapshot.py aggregates every peer's snapshot into:

All times stay UTC across machines so hour-bucket keys merge cleanly. Display-time conversion (story page tz selector) shifts only what's rendered.

Timestamps & timezones data

JSONL records carry a Z-suffixed UTC timestamp. build_insights.py slices the first 13 chars (YYYY-MM-DDTHH) as the hour-bucket key. Aggregations across machines work because every host writes the same canonical UTC keys.

On the page side, tzmode.js uses Intl.DateTimeFormat({ timeZone }) — DST is handled by the browser's IANA tz database, so you don't need to track shift transitions manually. UTC remains the default; pick a zone via Settings.

Turn log cap data

The Timeline activity feed reads insights.json's turnLog[], which is capped at 1000 most-recent turns by default. Heavy users can raise the cap by exporting an env var:

CCUSAGE_TURN_LOG_CAP=5000 bash update_usage.sh

The feed title shows "capped at X of N parsed" when truncation occurred so older activity isn't silently dropped.

Dead-end project filter

The Projects roster tags any project as a "dead-end" if either:

Auto-generated cowork session names like affectionate-gifted-ramanujan usually fall into this bucket. Hide-by-default toggle keeps them out of the roster unless you explicitly want to see them.

Day × Hour peak cell heatmap

Across the selected date range, every turn is bucketed by its UTC weekday (0…6) × hour-of-day (0…23). The cell with the highest total cost is the "peak cell". A single integer hour-of-day from this heatmap gets converted to local time via:

$$ \text{local hour} = \text{format}(\text{Date.UTC(today, hour)}, \text{tz}) $$

Caveat: a single hour-of-day across many months can't fully represent a DST-spanning year. The "today" reference is used for DST orientation — accurate within a ±1-hour shift if your data crosses a DST transition.