Typed, exhaustive parser for Claude Code session transcripts (.jsonl), plus a context-map tool.
Project description
cc-session-core
Typed, lossless parser for Claude Code session transcripts (~/.claude/projects/**/*.jsonl), plus a session-analysis layer (timeline, tool-call pairing, cost) and a context-map tool built on it.
Each transcript line is validated by a Pydantic TypeAdapter over a discriminated union keyed on the record type. Three layers, each a discriminated union: top-level records, message.content blocks, and attachments. usage, message, and the built-in tools' inputs/results are fully typed; cc_session_core.parsing.tools dispatches per-tool models by tool name, with a raw fallback for MCP/unknown tools.
Parsing is lossless: models keep unknown fields (extra="allow"), and an unmodeled record/block/attachment type lands in an Unknown* carrier that still holds its payload — nothing is dropped or raised. The coverage gate is the schema audit (cc_session_core.report.audit), which reports anything that fell into extra or an Unknown* fallback (field names and value-types only, never values).
Install
pip install -e . # or: uv pip install -e .
Library
Parse lines into typed records:
from pathlib import Path
from cc_session_core import iter_records, parse_line, ParseFailure
rec = parse_line(line) # one JSON line -> typed record
for rec in iter_records(Path("session.jsonl")):
if isinstance(rec, ParseFailure):
... # file, line_number, error, raw
elif rec.type == "assistant":
rec.message.usage.input_tokens
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:
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
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 .jsonl file or a project directory (directories load recursively). --tools lists paired tool calls; --queries prints the full why/queried/returned timeline; --list indexes the sessions in a directory; --audit reports 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. 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.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cc_session_core-0.1.0.tar.gz.
File metadata
- Download URL: cc_session_core-0.1.0.tar.gz
- Upload date:
- Size: 66.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fad275cad78dd9ebfb4df2a1b3729bceaf6d68101e892b8ba83e062571882f16
|
|
| MD5 |
b97dcaf7d8837879a8473ca0647e908e
|
|
| BLAKE2b-256 |
627a5e36cc0463118ad1dcc756616ce418709e47da13c488f599ea1be04e85f8
|
Provenance
The following attestation bundles were made for cc_session_core-0.1.0.tar.gz:
Publisher:
publish.yml on Magic-Man-us/cc-session-core
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cc_session_core-0.1.0.tar.gz -
Subject digest:
fad275cad78dd9ebfb4df2a1b3729bceaf6d68101e892b8ba83e062571882f16 - Sigstore transparency entry: 2195114001
- Sigstore integration time:
-
Permalink:
Magic-Man-us/cc-session-core@1001878acfcd73e6fe9e1ca4fa0caa75838b755c -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/Magic-Man-us
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@1001878acfcd73e6fe9e1ca4fa0caa75838b755c -
Trigger Event:
release
-
Statement type:
File details
Details for the file cc_session_core-0.1.0-py3-none-any.whl.
File metadata
- Download URL: cc_session_core-0.1.0-py3-none-any.whl
- Upload date:
- Size: 54.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
11e25a7468e584f4cb25831e7b0ac88d0e732461acb9578b656f515d0be48acd
|
|
| MD5 |
5bd2cdac61d1cae1670a3f755c9833bf
|
|
| BLAKE2b-256 |
d468c0d4b7bf3b7bd4664e23a8f30277976d29d17abf7925097f612973cc37ac
|
Provenance
The following attestation bundles were made for cc_session_core-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on Magic-Man-us/cc-session-core
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cc_session_core-0.1.0-py3-none-any.whl -
Subject digest:
11e25a7468e584f4cb25831e7b0ac88d0e732461acb9578b656f515d0be48acd - Sigstore transparency entry: 2195114017
- Sigstore integration time:
-
Permalink:
Magic-Man-us/cc-session-core@1001878acfcd73e6fe9e1ca4fa0caa75838b755c -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/Magic-Man-us
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@1001878acfcd73e6fe9e1ca4fa0caa75838b755c -
Trigger Event:
release
-
Statement type: