cc-session-core
Typed, lossless parser for both Claude Code transcripts
(~/.claude/projects/**/*.jsonl) and Codex rollout transcripts
($CODEX_HOME/sessions/**/*.jsonl, normally ~/.codex/sessions), plus a
provider-neutral session-analysis layer (timeline, tool-call pairing, usage/cost)
and a context-map tool built on it.
TRANSCRIPT_RECORD_ADAPTER is a shared Pydantic discriminated union. Its callable
discriminator routes Claude record types (assistant, user, system, …) and
Codex rollout types (session_meta, turn_context, response_item, event_msg,
…) without a format flag. Each provider then has nested discriminated unions for
its own content: Claude message blocks/attachments, and Codex response items/events.
Provider-specific adapters remain available when a caller deliberately wants one
format only.
Parsing is lossless: models keep unknown fields (extra="allow"), and an
unmodeled record/block/attachment/event/response-item type lands in an
Unknown* carrier that still holds its payload—nothing is silently dropped.
This matters especially for Codex because its
hook documentation
explicitly says the transcript format is not a stable interface. The typed
Codex model tracks the current open-source
RolloutItem
and
ResponseItem
definitions while retaining forward-compatible fallbacks.
Install
pip install -e . # or: uv pip install -e .
Library
Parse either provider through one shared boundary:
from pathlib import Path
from cc_session_core import (
ParseFailure,
iter_transcript_records,
parse_transcript_line,
)
rec = parse_transcript_line(line) # -> Claude Record | CodexRecord | unknown fallback
for rec in iter_transcript_records(Path("session.jsonl")):
if isinstance(rec, ParseFailure):
... # file, line_number, error, raw
else:
print(rec.type)
The backward-compatible Claude-only parse_line() / iter_records() API and
the explicit Codex-only parse_codex_line() / iter_codex_records() API are
also available.
Per-tool input/result resolution:
from cc_session_core import parse_tool_input, parse_tool_result, tool_name_index, result_tool_name
typed_input = parse_tool_input(block.name, block.input) # model, or raw value
index = tool_name_index(records) # tool_use_id -> tool name
typed_result = parse_tool_result(result_tool_name(rec, index), rec.tool_use_result)
Analyze a whole session. Session.load() auto-detects the provider and returns
the same normalized timeline/tool/cost views:
from cc_session_core import Session
s = Session.load("session.jsonl")
s.timeline() # ordered, decomposed events (text / thinking / tool_use / tool_result / ...)
s.tool_calls() # every tool_use paired with its tool_result, plus the assistant's "why"
s.cost_summary() # token + cost rollup per model (one API request counted once)
s.label()
s.info() # human title + one-line summary
For Codex, response messages, reasoning, tool calls, tool outputs, compaction,
and usage events are normalized into the canonical view. The original typed
rollout remains available as s.codex_records when isinstance(s, CodexSession).
Codex input_tokens includes cached input, so normalization subtracts
cached_input_tokens before filling the canonical uncached-input field; totals
therefore do not double-count cache reads.
Cost uses cc_session_core.cost.pricing (published list rates in EXAMPLE_PRICING); pass your own PriceTable for a different valuation. Rates are a usage valuation, not a billed amount.
CLI
cc-session PATH [--tools] [--queries] [--audit] [--list] [--json] [--strict]
cc-session PATH --export <text|markdown|json|jsonl> [--select k=v ...] [-o OUT]
PATH is a Claude or Codex .jsonl file, or a directory (directories load
recursively). --tools lists paired tool calls; --queries prints the full
why/queried/returned timeline; --list indexes sessions in a directory;
--audit reports Claude schema coverage over the target (field names +
value-types only, safe to share).
--export writes a filtered slice of the session; --select narrows it (space-separated key=comma,values): parts= (text,thinking,tool_use,tool_result,image,other), tools=, types=, uuids=, main_only=true. -o writes to a file instead of stdout.
cc-session-map [TRANSCRIPTS_DIR] [-o OUT_DIR] # default: ~/.claude/projects, .
Aggregates per transcript and overall: turns (main vs sidechain), tool usage, token usage by kind, server web tools, and cost; writes map.json and map.csv into OUT_DIR.
MCP server
cc-session-mcp (stdio) exposes list_sessions, session_summary,
tool_calls, export_session, and audit. Session listing and lookup search
both default Claude and Codex roots. It needs the mcp extra
(pip install "cc-session-core[mcp]"). Register in a Claude Code .mcp.json:
{
"mcpServers": {
"cc-session": { "command": "cc-session-mcp" }
}
}
Tests
uv sync --all-groups # pytest, ruff, pyright, mcp
uv run pytest # fast unit tests on frozen, scrubbed fixtures
CC_SESSION_CORPUS=~/.claude/projects uv run pytest -m corpus # opt-in: asserts zero Unknown*/extra/parse-failures on real data
The corpus test is the lossless coverage gate: it fails if any real line lands in an Unknown* fallback, leaves a field in model_extra, or a modeled built-in tool result falls back to raw. Fixtures are regenerated with python tests/_extract_fixtures.py (CC_SESSION_CORPUS set); free-text, paths, and base64 are scrubbed.
Metadata
Release files for cc-session-core 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| cc_session_core-0.2.0.tar.gz | 80.2 kB | With provenance | Details for cc_session_core-0.2.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| cc_session_core-0.2.0-py3-none-any.whl | Python 3 | none | any | Details for cc_session_core-0.2.0-py3-none-any.whl |
Total release size: 146.6 kB
Release files / cc_session_core-0.2.0.tar.gz
| Download URL | cc_session_core-0.2.0.tar.gz |
|---|---|
| Size | 80.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
82453571c349703207004a2cf0d4834c4b025101b0df004aa1253e65b5974964
|
|
BLAKE2b-256 checksum How to use checksums |
0cce0fc200df2ee4e2007229171c45bc7493b12b3537f7632636e6ce005ea13c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 25, 2026.
Transparency logRelease files / cc_session_core-0.2.0-py3-none-any.whl
| Download URL | cc_session_core-0.2.0-py3-none-any.whl |
|---|---|
| Size | 66.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
163085c5f869f151386f90479acbadf1d9a533ce537003eb94b53830868d05fc
|
|
BLAKE2b-256 checksum How to use checksums |
72bbc83f1a90815579659b7be56b999b3288895ebb5003c71aad583afe14f0ab
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 25, 2026.
Transparency logSecurity for cc-session-core 0.2.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for cc_session_core-0.2.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 25, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.