Prompt Cache Accounting
July 24, 2026 ยท View on GitHub
Claude
Claude exposes separate input-side usage counters:
input_tokens_total = input_tokens
+ cache_creation_input_tokens
+ cache_read_input_tokens
In the normalized trace:
prefix_tokens = cache_read_input_tokens
newly_append_tokens = input_tokens + cache_creation_input_tokens
Adjacent-round evidence from readable raw Claude sessions:
next.cache_read_input_tokens ~= last input_tokens_total
The previous assistant output is not part of the same round's input/cache write, but when it is replayed as conversation history, it usually appears in the next round's cache write:
next.cache_creation_input_tokens >= last.output_tokens
overall adjacent pairs: 98.0%
next round starts from tool_result: 98.39%
next round starts from user_message: 94.65%
Long current user/tool input also inflates the same round's cache write:
tool_result_chars >= 50k:
median cache_creation_input_tokens = 22,518
user_input_chars >= 10k:
median cache_creation_input_tokens = 25,727
Practical model:
this_round.cache_read_input_tokens
~= cached prefix from previous request
this_round.cache_creation_input_tokens
~= previous assistant response replayed into prompt
+ this round's new user/tool-result content
+ message/tool framing and cache-boundary overhead
Caveats:
output_tokenscan include hidden/thinking or max-token output that may not be replayed as visible assistant message content.- Raw Claude Code tool logs are not always equal to what is sent to the model; some large raw tool outputs appear clipped, compacted, or shifted across cache boundaries.
- Therefore, subtracting
last.output_tokensfrominput_tokens + cache_creation_input_tokensis useful as an approximation for external context growth, but it is not a strict identity.
Codex
Codex traces do not expose a separate cache_creation_input_tokens field. The
observable split is:
prefix_tokens = cached_input_tokens
newly_append_tokens = input_tokens_total - cached_input_tokens
So the closest observable to Claude's cache write is newly_append_tokens, but
it is cache-miss/new-append accounting rather than an explicit cache-write
counter.
Adjacent-round evidence from trace/collections/current/merged.private.jsonl:
next.prefix_tokens ~= last.input_tokens_total
median error: -183 tokens
next.newly_append_tokens >= last.visible_output_tokens
95.49% of adjacent pairs
next.newly_append_tokens >= last.output_tokens
91.30% of adjacent pairs
For Codex, output_tokens includes reasoning tokens. visible_output_tokens is
estimated as:
max(0, output_tokens - reasoning_output_tokens)
This makes the previous-output relationship cleaner, because reasoning tokens are generally not replayed as visible conversation history.
Long current user input strongly increases Codex newly_append_tokens:
user_chars >= 10k:
median newly_append_tokens = 7,206
newly_append_tokens >= raw_chars / 4 in 3,376 / 3,713 rows
user_chars >= 50k:
median newly_append_tokens = 26,005
newly_append_tokens >= raw_chars / 4 in 84 / 90 rows
Long current tool output also increases append tokens, but less reliably:
tool_chars >= 10k:
median newly_append_tokens = 6,167
tool_chars >= 50k:
median newly_append_tokens = 15,891
tool_chars >= 100k:
median newly_append_tokens = 10,057
The weak relationship for extremely large raw tool outputs suggests Codex, like
Claude Code, may truncate, summarize, or otherwise avoid sending the full raw
tool output to the model. The raw trace result_chars value is therefore not
always a direct prompt-size measurement.
Practical Codex model:
this_round.prefix_tokens
~= cached prefix from previous request
this_round.newly_append_tokens
~= previous visible assistant response
+ this round's new user/tool-result content actually sent to the model
+ message/tool framing and cache-boundary effects
Compared with Claude, Codex shows the same qualitative effects but with more jitter, and without a direct public/raw counter for cache writes.
Current Codex Trace Caveat
The Codex extractor currently has subagent-aware session assignment in
scripts/extract_codex_rounds.py: subagent files keep live child turns under
the child session while replayed parent turns are assigned back to the parent
session id for deduplication. The checked trace/collections/current/merged.private.jsonl
was written before that extractor update, so large positive prefix jumps found
in that trace may include subagent replay artifacts. Recollect before treating
the current Codex jump counts as final.