Skip to main content

cc-session-core

PyPI Python versions CI codecov Dependabot License: MIT

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.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cc_session_core-0.2.0.tar.gz (80.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cc_session_core-0.2.0-py3-none-any.whl (66.4 kB view details)

Uploaded Python 3

File details

Details for the file cc_session_core-0.2.0.tar.gz.

File metadata

  • Download URL: cc_session_core-0.2.0.tar.gz
  • Upload date:
  • Size: 80.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for cc_session_core-0.2.0.tar.gz
Algorithm Hash digest
SHA256 82453571c349703207004a2cf0d4834c4b025101b0df004aa1253e65b5974964
MD5 cb84e3496dd2803c82e712b6b2200851
BLAKE2b-256 0cce0fc200df2ee4e2007229171c45bc7493b12b3537f7632636e6ce005ea13c

See more details on using hashes here.

Provenance

The following attestation bundles were made for cc_session_core-0.2.0.tar.gz:

Publisher: publish.yml on Magic-Man-us/cc-session-core

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file cc_session_core-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: cc_session_core-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 66.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for cc_session_core-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 163085c5f869f151386f90479acbadf1d9a533ce537003eb94b53830868d05fc
MD5 fbaa6be1bfbb97dca328c04bbfac9d31
BLAKE2b-256 72bbc83f1a90815579659b7be56b999b3288895ebb5003c71aad583afe14f0ab

See more details on using hashes here.

Provenance

The following attestation bundles were made for cc_session_core-0.2.0-py3-none-any.whl:

Publisher: publish.yml on Magic-Man-us/cc-session-core

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page