Find out what running Claude Code (or Codex) sessions in parallel really costs, from your own transcripts. TranscriptAnalyzer reads the session transcripts Claude Code keeps on disk, or Codex's session logs, prices every API request at list rates, and works out how much of the bill comes from the prompt cache being rebuilt, and why it was rebuilt.
If you run several Claude Code sessions side by side, each one sits idle while you work in the others. Once a session's prompt cache expires (5 minutes or 1 hour, depending on the TTL it wrote), the next turn re-writes the whole context at 1.25× or 2× the input price, instead of reading it back at a small fraction of it. Is that a real cost of working in parallel, or is the extra spend just that every session has its own prompt and nothing is shared between them?
The transcripts hold enough to answer that with numbers instead of intuition: every request's token usage, cache reads and writes (split by TTL), timestamps, and every prompt you typed in every session.
Needs Python 3.10+ and nothing else.
pip install -e .
transcript-analyzer # all of ~/.claude/projects -> transcript-report.html
transcript-analyzer --since 2026-09-01 # from a date (your local time) on
transcript-analyzer --since 2026-10-01 --until 2026-10-07 # one week, days inclusive
transcript-analyzer --session 6a3ff1c1 # one session (an id prefix is enough)
transcript-analyzer --project CodeCompass # projects whose name contains this
transcript-analyzer --tz UTC # count days in UTC (or +02:00, -05:00, ...)
transcript-analyzer --root D:\friend\projects # someone else's transcripts
transcript-analyzer --codex # Codex logs in ~/.codex/sessions
transcript-analyzer --root D:\friend\.codex # Codex logs are detected from the folder too
transcript-analyzer --out me.html --title "Mine" # pick the file name and title
transcript-analyzer --json result.json # also save the full result
transcript-analyzer @refactor-week.txt # options saved in a fileor, without installing, python -m transcript_analyzer.
Filters cut through sessions: each request counts on the day it was made, and a session that
started before --since still has its earlier history taken into account. That history tells
the tool what context a rebuild lost and whether you were busy elsewhere. --session and
--project repeat. --session also takes a session's file name (<id>.jsonl, or Codex's
rollout-<time>-<id>.jsonl). To reuse the same set, put the options in a file, one per line:
# refactor-week.txt
--session 3f2a91 # auth refactor
--session b77c04 # migration
--since 2026-10-01
--title Refactor week
A # starts a comment at the start of a line or after a space; quote a value to keep one in it
(--title "Week #3").
It prints a short summary and writes an HTML report in two parts.
Overview
- Cost by project, by day and by session: each one split into normal use and extra cost from cache rebuilds. A session running over several days is spread across them.
- Cost by model: fast mode on its own row.
- Tokens and cost by type: each token type's share of all tokens next to its share of the cost.
- Cost per request by context size: how much more each turn costs as a conversation grows.
Cache analysis
- Hit rate and totals: tokens read from and written to cache.
- The verdict: the extra cost from cache expiring while you worked in other sessions, and how each theory holds up.
- Extra cost by cause and by project: expired while busy elsewhere, expired while away, rebuilt within the cache lifetime, cold starts.
- By sessions running at once: rebuild cost as a share of spend at each level.
- Idle gaps: how long sessions sat between turns, against the cache lifetimes (5 min and 1 h for Claude, 30 min for OpenAI).
- Cold starts: how often a new session read a prefix that was already cached.
If a model has no known list price, the report says so and prices it as that maker's flagship model.
The report is one self-contained file: styles, charts and script are all inline, with no links to
the web or to anything on disk, so you can email it and it opens anywhere. It has light and dark
modes, and every chart has a table view. Projects are named after the folder their sessions ran
in; a session started in your home folder shows as ~ (home) rather than your account name.
"Cost" means what the same usage would cost at API list rates, which is also a fair yardstick on a subscription plan.
Transcripts contain whole conversations and the contents of files Claude read. Treat them as
private. The report holds only numbers and project names, but check the project names before you
send it to anyone. The .gitignore here keeps reports, JSON dumps and input
folders out of the repo.
-
Load. Every
.jsonlunder the root is a cache chain: main sessions, and each subagent in<session>/subagents/. Assistant lines carrymessage.usage; one request spans several lines (one per content block, with output tokens growing as it streams), so they're merged byrequestId, keeping the final counts; the same request copied into another file counts once. Your own prompts are collected separately, per session. Lines Claude Code writes itself (background task results, command output) don't count, and neither do prompts from sessions a script drove (sdk-cli,codex exec).Codex: each
rollout-*.jsonlis one thread and each API response is one request. A thread that another one spawned counts toward the session that spawned it. -
Price. Input, output, cache reads, and cache writes at 1.25× (5m) or 2× (1h) input, per model, with fast mode at 2×. OpenAI cache writes are 1.25× input and last at least 30 minutes. Prices live in
PRICESintranscript_analyzer/analyze.py. -
Attribute. For each request, the context the previous request had cached but this one had to re-write is a miss, costed at the write price minus the read price it would otherwise have paid. Each miss gets a cause:
- Expired, busy elsewhere: the idle gap exceeded the chain's TTL, and you sent prompts to another session during it. This is the cost of working in parallel (an upper bound: you might have stepped away anyway).
- Expired, away: the gap exceeded the TTL and you weren't prompting anywhere else.
- Other: re-written within the TTL, e.g. compaction or switching models.
- Cold start: a chain's first request, costed the same way: what writing its context cost over reading it. Paid once per session whether sessions run one at a time or side by side, and often partly read from a shared prefix another session warmed.
transcript_analyzer/
analyze.py load transcripts, price requests, attribute misses
codex.py load Codex session logs into the same shape
report.py the self-contained HTML report
cli.py command line and text summary
tests/ pytest, on synthetic transcripts only
release.py bump version, update CHANGELOG, tag, push
CHANGELOG.md release notes (a pushed tag publishes the matching section)
This is a personal tool, published as-is — issues and pull requests aren't accepted (PRs auto-close). Fork it and make it your own. 🧾
MIT — see LICENSE. © 2026 RelentlessOldMan.