# Token metrics — how much agent work this PCB took, as recorded

Snapshot generated **2026-11-06T16:20:14Z** (the last usage row included;
refreshed from the 2026-11-06T16:11:56Z export, same SQL, bound
`created_at <= 1793982014`).
Headline, for the project scope defined below:

| scope | agents | usage rows | input tokens | output tokens |
|---|---|---|---|---|
| chat tree (main chat + its subagents) | 58 | 533 | 560,954,013 | 2,717,243 |
| checkpoint cron (`pdlvds-progress`) | 211 | 165 | 163,551,170 | 929,625 |
| **project total** | **269** | **698** | **724,505,183** | **3,646,868** |

**Gross total: 728,152,051 tokens processed.** Read the semantics section
before quoting that number anywhere: it is *gross tokens processed* — the
full context is re-sent on every model request, so the sum counts the same
content many times. It is a work meter, not a content size and not a bill.

## Files

- `token_series.csv` — one row per usage record (timestamp, agent, input,
  output, running cumulative totals), sorted by time.
- `agents.csv` — every agent in scope, its role, its totals, and its
  model codename (column `model`: the value of `agent.agents.model`
  for the agent — `ipnext/watermelon-v0` for the 212 root-class
  agents, `ipnext/avocado-5.17-v1`/`-v2` for the 57 subagents; see
  the codename note in the Cost summary section).
- `commit_alignment.csv` — every commit in this repo's HEAD history with
  cumulative project tokens at the commit's time and the board state from
  the audit file committed at that revision (`not recorded` where the
  record doesn't say — never back-filled).
- `progress_vs_tokens.svg` — cumulative tokens vs unconnected nets and
  clearance violations at the board-bearing attempt commits.
- `token_per_message.svg` — per-message gross tokens over time (top
  panel, log scale, colour-coded by scope) with project epochs annotated,
  and below it the cumulative tokens as a six-layer stack: each scope
  keeps its top-panel hue (main chat / subagents / checkpoint cron),
  the darker shade of a hue is input tokens and the lighter shade is
  output tokens, a scope's two layers sit adjacent so its band height
  is its cumulative subtotal, and the top edge of the stack is the
  grand cumulative total. All plotted times are Pacific time
  (America/Los_Angeles) — the CSVs keep epoch seconds, so this is
  display-only. Embedded in the site's Token usage section. Generated
  by `make_token_chart.py` from `token_series.csv` + `agents.csv`;
  each epoch in the script names the commit its timestamp comes from,
  and the script asserts the stack's per-scope layers and grand total
  against the CSVs before writing the SVG.
- `align_commits.py` — regenerates `commit_alignment.csv` from
  `token_series.csv` + git history (runs anywhere the repo is cloned).
- `input_split.csv` — per usage record: recorded input split into
  estimated NEW vs REPEATED (see the input-split section; an
  **estimate**, not a record).
- `input_split_summary.csv` — the same split aggregated per scope.
- `input_split.svg` — cumulative stacked area of estimated new vs
  repeated input over time (Pacific-time axis), labelled as estimate.
- `estimate_input_split.py` — regenerates the three files above from
  `token_series.csv` + the agent transcripts under `~/agents`
  (this machine only).
- `input_split_validation.json` — every fit/validation number quoted
  in the input-split section below.
- `api_rates.json` — hand-maintained API list prices (USD per MTok) for
  the three providers in the cost summary. Each provider entry is a
  like-for-like tier pair (flagship + step-down), each with its
  official source URL and the date it was fetched; the file also
  carries `codename_map`, resolving the recorded model codenames to
  the public models they are priced as. Re-check before regenerating.
- `cost_summary.csv` — per-provider list-price equivalents computed
  from `agents.csv` totals at the rates in `api_rates.json`: one row
  per (scope, tier) priced share, a per-tier `all` row per provider,
  and three whole-volume costs per provider, each tier-matched (each
  share priced at its own model's tier): `all-uncached
  (tier-matched)` (per-scope rows plus the `all` headline),
  `all-cached (tier-matched)`, and the cache-adjusted pair
  `cache-adjusted (pessimistic estimate)` / `cache-adjusted
  (optimistic estimate)`. See the Cost summary section below. Generated by
  `make_cost_summary.py`, which cross-checks its totals — and the
  codename split — against `token_series.csv`.
- `cache_share_by_agent_type.csv` — the estimated repeated
  (cache-served) percentage behind the cache-adjusted cost, by agent
  type (main chat / subagents / checkpoint cron), computed by
  `make_cost_summary.py` from the per-record estimates in
  `input_split.csv`.

## Source

The Muse runtime database (`muse.db`, read via the read-only SQL tool).
Two candidate tables exist:

- `agent.token_usage` (per-request) — **completely empty (0 rows). Do not use.**
- `agent.agent_message_token_usage` — populated; the only usage source
  used here. Columns: `agent_id`, `message_id`, `input_tokens`,
  `output_tokens`, `created_at` (seconds epoch, UTC).
- `agents.csv`'s `model` column comes from a second table,
  `agent.agents` (column `model`): an internal codename per agent
  (`ipnext/watermelon-v0`, `ipnext/avocado-5.17-v1`), present for all
  66 agents in this snapshot. At a future refresh, an agent id with
  no `agent.agents` row would export with a blank `model`.

## Semantics — what a row is

Evidence gathered while building this export:

- A row aggregates **all model requests made while producing one message**
  in that agent. The main agent has 482 rows in this snapshot, one per
  delivered message/turn
  (a turn with many tool calls makes many requests, each re-sending the
  context — hence rows larger than the 350k context window).
- Every **completed subagent has exactly one row**, timestamped at its
  completion, totalling its whole run (e.g. the CI-fix rounds 1–2 worker:
  9,121,511 input / 45,386 output in a single row) — with one exception:
  for a subagent whose session was compacted, the row covers only the
  segment since the last compaction (input-split section; coordinator
  #1), so a compacted agent's recorded total is a floor, not a full
  accounting.
- **Running agents have no rows.** At snapshot time the second build
  coordinator (~5.5 h of v6/Freerouting work) and this metrics worker had
  none — their usage lands only when they complete. All totals here
  therefore *undercount* in-flight work.
- Sanity anchor: one live request of the root agent on 2026-11-04T07:58Z
  was estimated at 219,814 input tokens (session status) — a single
  request, vs 235,111,727 cumulative input over its 482 message rows.

## Input split — NEW vs REPEATED (ESTIMATE, not a record)

**Headline, with its error attached:** of the 724,505,183 recorded
input tokens, 602,936,034 (83.2%) were estimable. The split is
published under two bounds for the injected preamble (see the
simplification note below). **Pessimistic** (preamble never
cache-served): an estimated **57.22% (345,013,960) were NEW** —
content sent for the first time in its context window, plus the
preamble at every request — and **42.78% (257,922,074) were
REPEATED** — context re-sent within the same window. **Optimistic**
(preamble cache-served after its first send per session): **97.35%
repeated**. Per scope (pessimistic / optimistic repeated): chat tree
**48.76% / 98.26%** (of its estimable
488,970,170); checkpoint cron
**17.11% / 93.48%** (of its estimable 113,965,864). The remaining 121,569,149 tokens (16.8%) are NOT estimable (below); they
are carried as repeated in the CSV, flagged per row. Validation:
against held-out agents the estimator's reconstructed totals land at
median recorded/estimated ratio **1.06** (p10 0.46, p90 1.48; median
absolute error **14.8%** after a train-derived correction) — a much
wider spread than the fit quality on the earlier, smaller snapshot,
so read the percentages as carrying a wide uncertainty band, not as
exact. This split is the closest available proxy
for cached-vs-uncached input: repeated content is what a prompt
cache serves, but a repeat is not necessarily a cache *hit* (caches
expire), and no billing conclusion follows from tokens alone.

### Correction (2026-11-04): the compaction rule

The first published version of this estimate handled compactions
under an incorrect rule. It kept a kept item's identity alive across
a compaction: only the summary counted as new at the first request
after the boundary, and kept items went on accruing REPEATED from
that first send. That is not how a prefix cache works. A prompt
cache is keyed on the exact token prefix of a single context window;
a compaction starts a new window whose text — the summary plus the
kept items, the kept items now standing at new positions behind
different preceding text — matches nothing already cached. On the
first request after a compaction, everything in the surviving
context is therefore uncached (NEW); repeats accrue only from the
second request in the new window onward. No evidence shows any
provider preserving cache across a compaction, and systems that
expose the mechanism (Claude Code after a recompaction, for one)
treat the new window as new. The old rule measured *content
repetition* — whether the same text had ever been sent before —
which is an upper bound on the cache-served share, not the share
itself.

Effect on the numbers: NEW rises by 35,500 tokens overall
(4,780,664 → 4,816,164; REPEATED 127,876,475 → 127,840,975), so the
repeated share moves 96.40% → 96.37% of estimable input and the
chat-tree share 97.52% → 97.49%; the cron scope contains no
compactions and is unchanged. Per agent: the root agent's NEW rises
28,213 → 79,055 (three compactions in its transcripts at
publication); build coordinator #1's NEW *falls* 58,608 → 43,266,
because the old pipeline additionally carried a manual add-on that
counted its final segment's starting context on top of the summary
— a double count the corrected rule makes unnecessary, since the
segment's first request now counts the whole window exactly once,
by the rule itself. The cost summary's estimated-share sensitivity
moves with the corrected shares (Muse $44.31 → $44.39, Claude
$44.67 → $44.77, OpenAI $123.20 → $123.37; its headlines do not
depend on the split and are unchanged). Validation of the totals
model never depended on the split rule, and re-running it
reproduces every published fit statistic exactly (held-out median
ratio 1.03; median absolute error 3.5% raw, 3.2% after correction);
every published record still satisfies new + repeated = recorded
exactly, and the recorded total is unchanged at 133,253,984.

One artefact of re-running on a live machine: the regenerated
validation file lists an eighth compaction anchor — the root agent
compacted again at 2026-11-04T10:47:56Z, after the frozen export.
Its segment contains no frozen usage rows, so it changes no
published figure; the seven anchors of the original publication are
unchanged.

### Simplification (2026-11-05): the preamble split is published as two bounds

The fitted preamble — the runtime-injected standing context:
system prompt, tool schemas, and the standing files (AGENTS.md,
MEMORY.md, the alignment synthesis, indexes), fitted at roughly
68K–85K tokens per request depending on agent class, about a fifth
of the context window — is the estimate's biggest unknown, because
whether a provider's cache actually serves it cannot be observed
from any record here. At the project owner's direction the split is
therefore published under **two bounds**:

- **Pessimistic** (the headline split): the preamble is NEW at
  **every** request — every context starts totally fresh. The
  standing files are re-injected per request and are edited mid-run
  (MEMORY.md changes during ordinary work; the alignment file
  regenerates nightly), and cache residency across the long gaps
  between messages is not assumed.
- **Optimistic** (the rule this estimate originally used): the
  preamble is NEW once per session and cache-served at every later
  request — as much caching as the model allows.

Effect at this snapshot: the overall repeated share is **42.7%
pessimistic / 97.4% optimistic**; the main chat's is **37.1% /
99.2%**. Because the preamble is re-sent on every one of an agent's
requests, it dominates the NEW side of the pessimistic bound for
long-running agents. The totals model and its validation are
untouched — only the split moved.

### Why this is an estimate

The per-request table `agent.token_usage` has exactly the right
column (`cached_input_tokens`) but contains **zero rows** in this
deployment (re-verified 2026-11-04), and the per-message table has
no cache split. `agent.context_items` / `agent.context_text_segments`
have no token-count fields either (checked against the schema docs).
What does exist per item is the transcript text
(`~/agents/agent-<id>/sessions/*.jsonl`, present for all 50 agents
with usage rows), so the split is reconstructed from text sizes.

### Method (estimate_input_split.py)

- A transcript is an ordered item stream. A model *request* is
  inferred as one maximal run of consecutive assistant-produced items
  (thinking / commentary / tool calls / assistant messages); its
  input is a fixed preamble (system prompt + tool schemas, absent
  from transcripts) plus all context items present before the run.
- An item is NEW at the first request that sends it, REPEATED at
  every later send; the preamble (injected standing context) is
  split under two bounds — NEW at every request (pessimistic) or
  NEW once per session (optimistic); see the simplification note
  above. Item size
  = text character count.
- **Fork slices:** spawned chat agents' transcripts open with a
  byte-identical copy of a slice of the parent's stream (detected:
  a ≥20-item prefix also present in an earlier-born chat-tree
  transcript; found in 12 sessions, 43–361 items, 69,735–472,983
  chars). The slice is the agent's starting context (new at its
  first own request); the parent's requests inside it are not
  counted as the child's.
- **Compactions** (`compaction_checkpoint` records, 7 at
  publication): a compaction starts a NEW context window. The
  summary replaces all items before `first_kept_seq` and dropped
  items are gone; at the first request of the new window the ENTIRE
  surviving context — summary and kept items alike — counts as NEW
  (uncached), because a prefix cache is keyed on the exact prefix of
  one window and the new window's prefix matches nothing cached.
  From the window's second request on, its content accrues REPEATED
  normally. (The first published version of this bullet described a
  different rule; see the correction note above for why it was
  wrong.)
- **Single-row agents with compactions** are modelled on their
  post-last-compaction segment only: build coordinator #1's row
  reconciles with its final segment (estimated 2,276,625 vs recorded
  2,224,018, ratio 0.98) but not with its whole stream (~55M
  predicted, 25× the record) — its usage evidently accumulated over
  the final segment only. The segment's starting context counts as
  new at its first request — by the compaction rule itself (the
  segment opens a new window), not by any add-on.
- Responses are assigned to usage records by timestamp (a response
  belongs to the first record completing after it). 74 inferred
  responses fall after their agent's last snapshot record (the root
  agent kept working past the snapshot bound) and are excluded.
- Fit, per class (root / chat-tree subagent / cron worker):
  `recorded ≈ S/cpt(class) + preamble(class)·K`, K = inferred
  requests in the record, S = summed context chars before each
  request, fitted by non-negative least squares. Thinking items are
  counted as re-sent context (the with-thinking variant beat the
  without-thinking variant on held-out data, 3.2% vs 3.8% median
  absolute error — a narrow margin; both fits are in the validation
  file).

Fitted parameters (full-data fit; train-half fit in parentheses):
chars/token 3.39 (3.39) root, 3.42 (3.61) chat-sub, 3.62 (3.63)
cron; preamble 74,392 (74,392) root, 58,711 (61,326) chat-sub,
46,036 (45,754) tokens cron. These preambles are *effective* values:
they absorb per-request wrapper overhead as well as the true
system prompt and tool schemas, so do not quote them as prompt sizes.

### Validation

Split-half by agent (stratified by scope; root always in train —
it holds 102 of the 151 records; the published fit uses all agents):

- Train (124 records): median ratio 0.985, p10 0.950, p90 1.029,
  median absolute error 2.6%.
- Held-out test (17 records): median 1.028, p10 0.806, p90 1.090,
  median absolute error 3.5%; after per-class corrections derived
  on train only (0.984 root / 0.966 chat-sub / 1.003 cron): median
  1.025, median absolute error 3.2%. (Corrections cancel in the
  published proportions; they validate the totals model only.)
- The root agent's 102 records under the full fit: median 0.984,
  p10 0.952, p90 1.028, median absolute error 2.6%.
- Per-agent median ratios across the 40 estimable agents span
  0.77–1.10. Worst: build coordinator #1 (0.77) and one of its
  workers (0.79) — see the anchor cross-check for why.
- **Compaction anchors (independent cross-check):** the runtime's
  own `tokens_before` at each compaction vs the model's estimate of
  the same context: root 0.99 / 1.04 / 0.99 (within ±4%), coordinator
  #1 1.06, then 1.38 / 1.40 / 1.28 — its later, code- and
  JSON-dense segments carry more tokens per character than the
  class factor assumes. (`tokens_after` measures the compacted
  content alone and does not reconcile with the request model; it
  is not used.)
- **Not estimable:** the 10 cron run/delivery agents (596,845
  recorded input). Their session files hold the paired worker's
  stream, not their own requests: reconstructing those files
  over-predicts their ~50–70k records by ~8× (ratio ≈ 0.12). They
  are excluded from fitting and from the split percentages, and
  flagged in `input_split.csv`.

### Worked example (hand-traceable)

Cron checkpoint worker `6f4d20c5` (first checkpoint run; one usage
record: 385,384 input). Its transcript has 25 items and 7 inferred
requests. With the cron parameters (3.62 chars/token, preamble
46,036):

| request | context before (chars) | context tokens | + preamble | request total | new chars first sent |
|---|---|---|---|---|---|
| 1 | 8,602 | 2,377 | 46,036 | 48,413 | 8,602 |
| 2 | 24,157 | 6,675 | 46,036 | 52,711 | 15,555 |
| 3 | 31,740 | 8,770 | 46,036 | 54,806 | 7,583 |
| 4 | 44,456 | 12,283 | 46,036 | 58,319 | 12,716 |
| 5 | 53,978 | 14,914 | 46,036 | 60,950 | 9,522 |
| 6 | 56,892 | 15,719 | 46,036 | 61,755 | 2,914 |
| 7 | 59,993 | 16,576 | 46,036 | 62,612 | 3,101 |

Estimated total 399,566 vs recorded 385,384 (ratio 0.96). New =
all 59,993 item chars sent once (16,576 tokens) + the preamble's
first send (46,036) = 62,612, i.e. 15.7% of the estimate; the
published row scales that proportion to the recorded total:
est_new 60,390, est_repeated 324,994. Every number here can be
re-derived from the 25 items (the task prompt is 8,602 chars; the
first tool output, 13,761 chars, is first sent at request 2 —
counted in its new_chars 15,555 alongside request 1's own thinking,
commentary and tool call).

### Limitations

- Chars-per-token varies with content (prose vs code vs JSON); the
  per-class factor is an average, and dense segments (coordinator
  #1's later work) are under-estimated by up to ~40% at the segment
  level. Agent-level medians stay within 0.77–1.10, but treat any
  single record's split as ±10–20%, and small records as noisier.
- Mid-session context expiry/summarisation of old tool outputs, if
  the runtime does any outside compaction records, is invisible in
  transcripts and would inflate the repeated estimate.
- Published per-record new+repeated equals the recorded input
  exactly by construction (proportions applied to records); the
  estimation error lives entirely in the proportion.

## Scope — who counts

(a) **Chat tree.** `agent.agent_ancestors` for root agent
`4925d244-018c-4b4f-9fad-7b3ad78af7c1` (this chat): 17 agents — root, 13
direct children (2 build coordinators, CI-fix ×3, gallery ×3, CI speed,
CI-signal ×3, this worker), 3 grandchildren (coordinator #1's workers).
Cross-check: `agent.subagent_spawns` lists exactly the same 13 direct
children of the root and the same 3 children of coordinator #1 — the two
records reconcile completely, no gap.

(b) **Checkpoint cron.** The `pdlvds-progress` job (every 30 min) runs
under the goal scheduler, a different tree. Found via
`scheduler.jobs`/`scheduler.job_runs`: 23 runs, each with a worker agent
and a history agent (46 ids). Usage rows exist for all 23 history agents
(the checkpoint authors, 0.39M–1.17M input each) and for 11 of the 23 run
agents (small rows, ~0.05M–0.09M each); the other 12 have no rows.

(c) **Nothing else.** A prompt-text census (`subagent_spawns` prompts
mentioning the project) found no project agents outside (a)+(b).

The two scopes are disjoint agent-id sets (verified), so the total does
not double-count. Two honest overlaps of *effort*, not of records: the
root agent's rows include the turns that delivered checkpoint handoffs in
this chat (orchestration cost), and they include turns spent reading
subagent reports.

## Caveats

- The table is **live**: the root agent keeps accruing rows. This snapshot
  ends at the 2026-11-04T08:29:34Z row; later exports will be larger.
- Coverage starts at the first row, **2026-11-03T18:34:31Z**, ~6 minutes
  after the project's first user message (18:28Z) — that first row
  aggregates the opening work burst (2,945,917 input), so coverage is
  effectively from the start.
- Because subagent rows land at completion, token growth appears in lumps
  at delivery times. `commit_alignment.csv` assigns a commit the
  cumulative total of rows timestamped ≤ the commit time: work that was
  in flight at commit time is missing from that row and appears later.
- GitHub's server-side merge commits are not in this clone's HEAD lineage
  and carry no content changes; the alignment covers the 110 content
  commits of the lineage.
- Board state is parsed from the audit file **as committed at each
  revision** (an attempt-specific `results/audit-*.txt` when the commit
  touched one, else `results/pcb-audit.txt`). No ERC report is committed
  anywhere in the history (ERC reports live in CI artifacts), so
  `erc_errors` is `not recorded` throughout — the ERC story (875 → 0) is
  in `docs/00-status.md`, not in git.

## Cost summary (list-price equivalents)

Subscriptions are different for all three providers and unquantifiable
from any record available here. This project ran on a Muse
subscription — the user's known flat cost — and no per-token charge is
exposed in any record. The figures below are therefore **rough cost
estimates for if one would want to scale up**: the recorded token
volume priced at each provider's published pay-as-you-go API list
rates. They are not a bill, and not what this project cost.

Why API prices are the comparison currency (project owner's framing,
2026-11-04): Anthropic's and OpenAI's subscription tiers carry no
token count at all — Anthropic's are flat multipliers (5×, 20×) of an
undefined base amount, and OpenAI's are similar, except that hitting
the limit degrades your thinking level first. Only Muse's
subscription tiers correspond to an actual token count. A
subscription therefore cannot answer "what would this workload cost
to run as a business"; the pay-as-you-go API rates can, which is why
this table uses them. The report gives these costs per provider:
**all-uncached** (every input token at the standard rate — no cache
credit at all), **all-cached** (every input token at the cache-read
rate — the unattainable opposite bracket), and between them a
**cache-adjusted estimate published as two bounds** — pessimistic
and optimistic — which bills input per the estimated
new-vs-repeated split (input-split section: repeated share of
estimable input is 42.7% pessimistic / 97.4% optimistic at the
current snapshot). The split is an estimate
reconstructed from transcripts, not a measurement — no record of
actual cache hits exists — and "repeated" is an upper bound on
"cache-served": the estimate assumes every repeat of earlier context
is served from the provider's cache, modelling no cache expiry,
eviction, or minimum-prefix rules. Treat the cache-adjusted figure
as optimistic; a real cache-billed cost would land somewhere between
it and the all-uncached figure.

Rates used (USD per 1M tokens, standard rates, fetched 2026-11-04;
also in `api_rates.json`). Each provider is priced as a like-for-like
tier pair — flagship and step-down:

| Provider | Model | Input | Cached input | Output |
| --- | --- | ---: | ---: | ---: |
| Meta | Muse Wonder 1.0 | $4.00 | $0.20 | $20.00 |
| Meta | Muse Spark 1.3 | $1.25 | $0.15 | $4.25 |
| Anthropic | Opus 5.5 | $4.00 | $0.20 | $20.00 |
| Anthropic | Sonnet 5.5 | $2.00 | $0.10 | $10.00 |
| OpenAI | GPT-6 Astra | $10.00 | $1.00 | $50.00 |
| OpenAI | GPT-6.1 Sol | $2.00 | $0.10 | $10.00 |

Model codenames (confirmed by the project owner, 2026-11-04):
`ipnext/watermelon-v0` = Muse Wonder; `ipnext/avocado-5.17-v1` and
`ipnext/avocado-5.17-v2` = Muse Spark. The recorded volume splits
by codename — watermelon: 398,662,897 input / 1,700,050 output (the
root agents: main chat + checkpoint cron); avocado (both builds):
325,842,286 input / 1,946,818 output (all subagents) — and every
provider's figures below price the watermelon share at its flagship
tier and the avocado share at its step-down tier, like-for-like. For the Muse row those tiers are the
public models themselves. (Corroboration, one line: this chat's root
agent records `ipnext/watermelon-v0`, and the runtime independently
identifies this session's model as Muse Wonder.) Pricing note: the
internal build number (5.17) does not correspond 1:1 to a public
Spark version; the Spark share is priced as Spark 1.3 Standard, the
current public Spark card.

Tier choices: Claude Opus 5.5 is Anthropic's flagship tier for
long-running agentic coding — its pricing page's own description
(one tier sits above it, Claude Fable 5.1 at $10 / $50 / $0.25);
Claude Sonnet 5.5 is the Sonnet line directly below Opus on the same
page, cache-read at 0.05× base input. GPT-6 Astra is OpenAI's
flagship model; GPT-6.1 Sol is the sibling line directly below it in
the same Standard table.

**All-uncached cost at list prices — each model's share priced
at its own tier** (every input token billed at the standard
uncached rate; snapshot 2026-11-06T03:27:00Z). Each scope ran on
one tier — the main chat and the checkpoint cron on the flagship
tier, the subagents on the step-down tier:

| Scope | Meta | Anthropic | OpenAI |
| --- | ---: | ---: | ---: |
| Main chat | $955.86 | $955.86 | $2,389.64 |
| Subagents | $415.57 | $671.15 | $671.15 |
| Checkpoint cron | $672.79 | $672.79 | $1,681.99 |
| **Total** | **$2,044.22** | **$2,299.80** | **$4,742.78** |

Each scope figure is the sum of its rounded input and output
component costs (the convention `cost_summary.csv` uses for all its
totals), so the Total row is the exact sum of the three rows above
it. Per-tier detail behind each figure is in `cost_summary.csv`
(the `all-uncached (tier-matched)` rows).

The whole-volume costs. *All-uncached* is the table above:
no cache credit anywhere. *All-cached*: every input token billed
at its tier's cache-read rate — the floor of what caching could
ever save, not an achievable figure (a first send is never a cache
read). Between them, the *cache-adjusted* estimate under its two
preamble bounds: each scope's estimated repeated share billed at
its tier's cache-read rate and the rest at standard rates (the
cache estimate paragraph below). *Pessimistic*: the injected
preamble is never cache-served. *Optimistic*: it is cache-served
after its first send per session.

| | Meta | Anthropic | OpenAI |
| --- | ---: | ---: | ---: |
| All-uncached (tier-matched) | $2,044.22 | $2,299.80 | $4,742.78 |
| Cache-adjusted (pessimistic estimate) | $1,327.49 | $1,455.96 | $3,157.29 |
| Cache-adjusted (optimistic estimate) | $233.19 | $232.63 | $679.28 |
| All-cached (tier-matched) | $170.88 | $165.79 | $535.72 |

(An earlier layout showed an "upper bound (all flagship)" row —
the whole volume at flagship rates — instead of the all-cached
bracket; it was retired in favour of the three costs above.)

The two flagship cards are identical — Meta lists Muse Wonder 1.0
at exactly Opus 5.5's prices — so Meta and Anthropic agree on every
flagship-tier scope (main chat, checkpoint cron); their totals
differ only because the step-down cards differ: Spark ($1.25 in /
$4.25 out) is cheaper than Sonnet ($2 / $10) on both rates, so the
subagent share costs less on Meta than its equivalent on Anthropic.

Cache estimate, from the **estimated** new-vs-repeated split
(input-split section; the split model is validated on totals —
held-out median ratio 1.06, median absolute error 14.8% at the
current snapshot — but the split itself cannot be
validated, because no record of real cache hits exists).
Estimated repeated share of input, by agent type, under the two
preamble bounds
(`cache_share_by_agent_type.csv`):

| Agent type | Repeated share, pessimistic | Repeated share, optimistic | Estimable input | Not estimable |
| --- | ---: | ---: | ---: | ---: |
| Main chat (root agent) | 37.1% | 99.2% | 235,111,727 | 0 |
| Subagents | 59.6% | 97.3% | 253,858,443 | 71,983,843 |
| Checkpoint cron | 17.1% | 93.5% | 113,965,864 | 49,585,306 |
| **Overall** | **42.7%** | **97.4%** | **602,936,034** | **121,569,149** |

Two cautions on these percentages. First, they are shares of the
*estimable* input only; the not-estimable remainder (records whose
transcripts could not be reconciled with their recorded totals,
plus scheduler delivery agents) is carried as repeated by
convention in the cost figure, and is shown here rather than hidden
inside the percentage. Second, "repeated" counts content re-sent
inside one context window; a real prompt cache additionally expires
and evicts, so the cache-served share of a live run would be lower
— by how much, no available record can say. Cache *write* charges, where a provider has them
(Anthropic 1.25×/2× of base input; OpenAI 1.25× on these models),
are not modelled, so a real cache-heavy bill would land between
the tier-matched total and the cache-adjusted figure.

Why even these equivalents are rough:

- **Model attribution.** `agent.agents.model` is populated for all
  269 project agents, but only with internal codenames: the 212
  root-class agents (this chat's root plus the checkpoint cron's
  worker and run agents) record `ipnext/watermelon-v0`, and the 57
  subagents record `ipnext/avocado-5.17-v1` or
  `ipnext/avocado-5.17-v2`. Model codenames (confirmed by the project
  owner, 2026-11-04): `ipnext/watermelon-v0` = Muse Wonder;
  `ipnext/avocado-5.17-*` = Muse Spark. No Anthropic or OpenAI
  model name appears in any project record; transcript session
  headers carry no model field, and `runtime.requests` has no model
  column at all. So no project agent was served by a non-Muse model
  — the Anthropic and OpenAI columns are equivalents for comparison,
  priced per codename share at the like-for-like tiers, not records
  of spend.
- **Compaction floor.** For a subagent whose session was compacted,
  the recorded usage row covers only the segment since the last
  compaction (proven on coordinator #1 in the input-split work), so
  the recorded totals — and every cost figure here — are a floor
  for such agents, not a full accounting.
- **Steering context.** Meta's Model API token counts exclude
  Meta-injected steering context (it is not billed); the local
  records this table is built from may include injected context.
- **OpenAI long-context pricing.** Prompts over 272K input tokens
  bill at 2× input/cache and 1.5× output for the full request on
  GPT-6 Astra. This project's recorded turns include per-message
  input aggregates well above that, but the aggregates cannot
  separate individual request sizes, so the headline uses standard
  rates throughout; an identical workload actually billed by OpenAI
  would cost more than the $1,365.87 flagship upper bound.
- **Tokenizer differences.** Anthropic's pricing page notes its
  current tokenizer produces roughly 30% more tokens for the same
  text than its predecessor; the counts here were metered on Muse,
  so identical text would meter somewhat higher on Claude.

## Staying in sync during the project

The database export (`token_series.csv` / `agents.csv`) can only be
refreshed by an agent with `muse.db` access — no shell, git hook, or
CI job can reach the Muse runtime database. Everything downstream of
the export, however, is plain local computation, and it is wired to
stay in sync on its own:

- `metrics/sync_metrics.sh` re-runs the local generators
  (`align_commits.py`, `make_token_chart.py`, `make_cost_summary.py`)
  and stages the regenerated artifacts. The milestone plot the site
  shows is rendered at site-build time from `commit_alignment.csv`, so
  it follows automatically.
- `.githooks/pre-commit` and `.githooks/post-merge` (enabled per clone
  with `git config core.hooksPath .githooks`) call it — but a full run
  costs ~30 s, so the script only does work in clones that opt in with
  `git config metrics.sync true`. That flag is set in the merge clone
  (`pdlvds-split`) only; worker clones return instantly and pay
  nothing.
- The parent agent refreshes the database export as part of every
  merge to `main`, then the hook regenerates the rest. Net effect:
  metrics on `main` are never more than one merge behind the work;
  between merges the token axis plateaus at the last export, which the
  plateau in the per-message chart makes visible rather than hiding.
- The input split (`estimate_input_split.py`) needs the agent
  transcripts and a manual transcription into this README, so it stays
  an agent-run milestone step, not part of the hook.

## Regenerating at project end

CI cannot reach this database. An agent with `muse.db` access re-runs the
SQL below, rewrites `token_series.csv`/`agents.csv`, then runs
`python3 metrics/align_commits.py .`, re-renders the progress chart from
`commit_alignment.csv` (attempt commits only), and re-renders the
per-message chart with `python3 metrics/make_token_chart.py .`. Re-check the rates in
`metrics/api_rates.json` against their source pages, update rates and
fetch dates together, then run `python3 metrics/make_cost_summary.py .`.
Update the snapshot date and totals in this file and in
`docs/00-status.md`.
The input split additionally needs the agent transcripts, so it can
only be regenerated on this machine: after the re-export, run
`python3 metrics/estimate_input_split.py .` and transcribe the new
validation numbers from its output / `input_split_validation.json`
into the input-split section above.

### SQL used for this snapshot (verbatim)

Token-table check:

```sql
SELECT (SELECT count(*) FROM agent.token_usage) AS token_usage_rows,
       (SELECT count(*) FROM agent.agent_message_token_usage) AS msg_rows
```

Tree census:

```sql
SELECT descendant_id, distance FROM agent.agent_ancestors
WHERE ancestor_id='4925d244-018c-4b4f-9fad-7b3ad78af7c1'
ORDER BY distance, descendant_id
```

Spawn cross-check:

```sql
SELECT child_agent_id, child_depth, status, created_at
FROM agent.subagent_spawns
WHERE parent_agent_id='4925d244-018c-4b4f-9fad-7b3ad78af7c1' ORDER BY created_at
```

Per-agent totals with verification bound (the bound is this snapshot's
last row; the exported CSV was verified to reproduce these sums exactly,
per agent, all 47 agents with rows):

```sql
SELECT substr(agent_id,1,8) AS agent8, count(*) AS rows_n,
       sum(input_tokens) AS input_sum, sum(output_tokens) AS output_sum
FROM agent.agent_message_token_usage
WHERE created_at <= 1793780974 AND agent_id IN (/* the 66 scope ids in agents.csv */)
GROUP BY substr(agent_id,1,8) ORDER BY agent8
```

Model census (fills `agents.csv`'s `model` column; run once per agent
id in the exported scope — the read-only query tool caps statement
size, so in practice this ran in batches of ~11–22 ids, both as the
grouped census below and as per-agent lookups):

```sql
SELECT model, count(*) AS agents_n FROM agent.agents
WHERE agent_id IN (/* scope ids, batched */) GROUP BY model
```

This snapshot: `ipnext/watermelon-v0` × 49 agents,
`ipnext/avocado-5.17-v1` × 17 agents. Per-codename usage totals with
the same bound reproduce the split the cost summary prices
(watermelon 67,519,404 in / 258,026 out over 35 agents with rows;
avocado 65,734,580 in / 408,578 out over 15):

```sql
SELECT a.model, count(DISTINCT u.agent_id) AS agents_with_rows,
       sum(u.input_tokens) AS input_sum, sum(u.output_tokens) AS output_sum
FROM agent.agent_message_token_usage u
JOIN agent.agents a ON a.agent_id = u.agent_id
WHERE u.created_at <= 1793780974
  AND (u.agent_id IN (SELECT descendant_id FROM agent.agent_ancestors
        WHERE ancestor_id='4925d244-018c-4b4f-9fad-7b3ad78af7c1')
       OR u.agent_id = '4925d244-018c-4b4f-9fad-7b3ad78af7c1'
       OR u.agent_id IN (SELECT worker_agent_id FROM scheduler.job_runs
                         WHERE job_id='pdlvds-progress')
       OR u.agent_id IN (SELECT worker_history_agent_id
                         FROM scheduler.job_runs
                         WHERE job_id='pdlvds-progress'))
GROUP BY a.model
```

Checkpoint discovery:

```sql
SELECT job_id, source_path FROM scheduler.jobs WHERE source_path LIKE '%pdlvds%';
SELECT worker_agent_id, worker_history_agent_id, count(*) AS runs_n,
       min(started_at_utc) AS first_ts, max(started_at_utc) AS last_ts
FROM scheduler.job_runs WHERE job_id='pdlvds-progress'
GROUP BY worker_agent_id, worker_history_agent_id ORDER BY runs_n DESC
```

The series export is the same `agent_id IN (...)` list with
`SELECT created_at, agent_id, input_tokens, output_tokens
... ORDER BY created_at, agent_id`.
