Skip to content

feat(sessions): read OpenAI Codex CLI sessions - #67

Merged
lostmartian merged 1 commit into
mainfrom
feat/codex-reader
Oct 19, 2026
Merged

lostmartian merged 1 commit into
mainfrom
feat/codex-reader

Conversation

@lostmartian

Copy link
Copy Markdown
Collaborator

What

agentdiff now reads OpenAI Codex CLI sessions alongside Claude Code and runs the same findings on them: long context, cache rebuilds, stuck retries, repeated failures, re-reads.

agentdiff                     # Claude Code + Codex
agentdiff --agent codex       # Codex only (or: claude, all)
agentdiff --codex-home PATH   # default $CODEX_HOME or ~/.codex

Why

Roadmap P1.4. Covering more than one agent doubles the audience. It's also the defence against any one vendor building this into its own tool: no vendor will analyse a competitor's sessions.

How

The reader is built from the openai/codex source at rust-v0.163.0. sessions/codex.py documents the format notes; the main points:

  • Where files are found: sessions/**/rollout-*.jsonl plus archived_sessions/, recursively.
    • Lines must have the wrapped format {timestamp, type, payload} (Codex 0.33+). Older unwrapped files carry no usage and are skipped.
    • .jsonl.zst files are read when compression.zstd (Python 3.14) or zstandard is available.
  • Usage:
    • Read from token_usage_record, one per API response and de-duplicated by response_id.
    • Older logs fall back to event_msg/token_count last_token_usage, skipping repeats and rate-limit-only events.
    • input_tokens already includes cached tokens, and output_tokens already includes reasoning tokens. Both are handled.
  • Model: taken from the latest turn_context, so it can change mid-session. thread_settings_applied.service_tier == "priority" marks the Fast tier.
  • Pricing:
    • OpenAI list prices fetched 2026-10-19 (gpt-6.x, gpt-5.x, codex, o3/o4-mini).
    • New long_context_tokens field: above 272K input, input is billed at 2x and output at 1.5x, per OpenAI's pricing page.
    • Codex logs carry no cost, so the report labels Codex figures as API-equivalent estimates.
  • Tools:
    • function_call / custom_tool_call / local_shell_call are paired with their outputs by call_id.
    • Exit codes are parsed from the output text (Process exited with code N / Exit code: N) or taken from paginated item_completed CommandExecution events.
    • Each tool call is attributed to the next usage record, because usage is logged when the response completes.
  • Forks and subagents: fork de-duplication moved to sessions/dedupe.py and is shared by both agents. Legacy forks copy their parent's usage lines, and those are counted once. Threads with parent_thread_id nest under their parent.
  • Analyzer: recognises Codex shell tools (exec_command, shell, local_shell), the cmd arguments they use, and bash -lc '…' wrapping.
  • Report:
    • The header names the agents it read, e.g. "Claude Code + Codex".
    • An Agent column appears when there is more than one agent.
    • The footer notes Codex estimates and any requests on models with no known price.
  • Tests: an autouse fixture points CODEX_HOME and CLAUDE_CONFIG_DIR at empty directories, so no test can read a developer's real logs.

Testing

make lint                  -> All checks passed
uv run python -m pytest    -> 475 passed (14 new in tests/test_codex.py)

What the tests cover:

  • per-model pricing;
  • a model change mid-session;
  • the long-context and Fast tiers;
  • the token_count fallback, including skipping repeats and null events;
  • usage records taking priority over token_count;
  • skipping legacy and broken files;
  • finding nested and archived rollouts;
  • de-duplicating a legacy fork;
  • nesting a subagent under its parent;
  • exit codes producing a stuck-retry finding;
  • paginated CommandExecution events;
  • loader labels and filtering;
  • CLI text and JSON output;
  • a full analysis producing a context-bloat finding.

By hand: my real Claude-only report is unchanged. A combined Claude + Codex demo renders the new header, the Agent column and the estimate note.

⚠️ Not yet tested against a real Codex session. Codex isn't installed on this machine, so every Codex test uses synthetic rollouts built from the source schema. Worth one real run before announcing Codex support:

codex      # do any small task
npx @kerrshift/agentdiff --agent codex --since 1d

Checklist

  • Exactly one logical change in this PR
  • make lint passes
  • uv run python -m pytest is green
  • Docs updated if user-facing
  • CHANGELOG.md entry added under [Unreleased] (if feat/fix)
  • Conventional title: type(scope): summary

Parse Codex rollouts (~/.codex/sessions, archived_sessions, $CODEX_HOME)
from the openai/codex rust-v0.163.0 schema: per-response usage from
token_usage_record (token_count fallback), per-turn model from
turn_context, OpenAI long-context and Fast tiers, tool calls with exit
codes, fork de-duplication and subagent nesting. Add --agent and
--codex-home, agent-aware report labels, and OpenAI list prices.
@lostmartian
lostmartian merged commit 9f8223e into main Oct 19, 2026
7 checks passed
@lostmartian lostmartian mentioned this pull request Oct 19, 2026
6 tasks done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant