Repository navigation
Description
What do you want to change?
In the default auto cost mode, a modelBreakdowns entry's cost adds together two different kinds of figure: costUSD values stored in the log, and costs calculated from the price table. The JSON does not say how much of cost is which.
I'd like to add one optional per-breakdown field, storedCost: the part of cost that came from stored costUSD values. It is present only when at least one record in that breakdown used its stored cost, so --mode calculate output and every breakdown without stored costs keep their current bytes.
Reproduction on 20.0.32 with two synthetic Claude records, same day and model, one without costUSD and one with "costUSD": 0.5. Command: ccusage daily --json --by-agent --offline --timezone UTC, reading .daily[0].agents[0].modelBreakdowns[0]:
--mode |
cost today |
|---|---|
auto (default) |
0.503084 (0.5 stored + 0.003084 calculated) |
calculate |
0.006084 |
display |
0.5 |
Today, in auto:
{"cacheCreationTokens":20,"cacheReadTokens":30,"cost":0.503084,"inputTokens":1500,"modelName":"claude-sonnet-4-20250514","outputTokens":100}
Proposed (not built):
{"cacheCreationTokens":20,"cacheReadTokens":30,"cost":0.503084,"inputTokens":1500,"modelName":"claude-sonnet-4-20250514","outputTokens":100,"storedCost":0.5}
Why?
I'm building a FinOps tool that reads ccusage's JSON and maps it to the FinOps Foundation's FOCUS format. The converter is here: https://github.com/erenozen/ccusage-focus. To fill a cost column honestly I need to know whether a figure is what the agent recorded or an estimate at list price. In auto mode, 0.503084 is both, and nothing in the output separates them. --mode calculate avoids the mix but drops the stored figure.
People on flat-fee subscriptions ask the same question from the other side, "is this number my bill?", in #1280.
I read the closing comment on #1737 and what was merged in #1750. This is one optional key in the same place as missingPricing, with the same rule of appearing only when it says something, and nothing changes in calculate mode. It is not a new output format; JSON stays the only one, as decided in #231. My converter lives outside ccusage.
How? (optional)
The per-record choice is made in rust/crates/ccusage-core/src/cost.rs:39-45 and lost where per-record costs are summed into a breakdown: rust/adapters/claude/src/daily.rs:639, rust/crates/ccusage-core/src/summary.rs:92, and the merges in rust/crates/ccusage-adapter-all/src/types.rs:175 and :203. Each of those lines sits right beside the existing missing_pricing handling, so the new value would follow the same path.
ModelBreakdown (rust/crates/ccusage-core/src/types.rs:98-112) would gain #[serde(skip_serializing_if = "Option::is_none")] pub stored_cost: Option<f64> beside missing_pricing. The per-record value has to travel through the loaded-entry structs the way missing_pricing_model does; those are constructed at 58 sites in 27 files, tests included, so the diff is wider than the one field. --no-cost strips cost keys by name in rust/crates/ccusage-core/src/output.rs:564-569, so storedCost would join that list. Docs: one sentence after the missingPricing bullet in docs/guide/json-output.md, and the "Mixed data" line in docs/guide/cost-modes.md would point to it.
If you agree with the shape, I'd like to implement it with fixture-backed tests next to the changed modules.
Activity
pullfrog commentedon Oct 15, 2026
github-actions commentedon Oct 15, 2026
Pullfrog triage: priority:low
Kind: feature request
Maintenance fit: excluded
Confidence: high
Requests a new optional storedCost field in JSON model breakdowns to separate stored costUSD from calculated cost in auto mode for an external FinOps converter. This is new output surface, not a defect in existing behavior, with no maintainer endorsement, so excluded with low priority.
Decision: closed by the contribution gate.
feat(adapter): report stored cost in JSON model breakdowns (#1903)