A black-box flight recorder for your Codex coding sessions.
Load a session by ID and replay it in a darkroom-terminal interface: a chat-style transcript, collapsible reasoning blocks, full-text search, and a cluster of instrument-panel visualizations that turn a raw session log into something you can actually read at a glance — heartbeat, constellation, duration log, a Black Box Recorder, a per-turn X-Ray, and a heuristic User Emotion layer.
Single Python file for the server, single HTML file for the UI. No pip install,
no build step, no frameworks — and it runs anywhere Codex does.
Standby screen. Run python3 viewer.py, paste a session ID, and the recorder spins up.
Anyone running Codex CLI or Codex Desktop locally who wants a better way to look back at a session than scrolling raw JSONL. Typical uses:
- Retrospect a session — see what Codex reasoned about, where it stalled, and which turns ran hot (friction / heat scoring).
- Search a long session — jump to any message with live highlighting.
- Export & share — dump a clean Markdown transcript to archive or hand off.
- Read your own prompting — the Emotion layer surfaces how a turn read (rule-based, not model-grade) so you can spot where things got tense.
- Teaching / write-ups — a legible, visual artifact of an AI pair-programming run.
It reads sessions from ~/.codex/sessions/ — the same place Codex writes them on
every platform — so it is not tied to any particular OS.
- Chat-style transcript — your messages, Codex replies, and collapsible thinking blocks
- Session ID lookup — paste any session UUID (full or partial) to load it instantly
- Search & filter — real-time highlighting (
Ctrl+F/Cmd+F) - Beat — an activity heartbeat scope of prompt/reply pulses over time
- Map — a message constellation (vertical axis = message length)
- Durations — a turn-by-turn response-latency log with avg / fastest / slowest
- Black Box Recorder — flight strips for prompt, thinking, reply, and friction; click any slice
- Session X-Ray — a selected turn's prompt → reasoning mass → reply, plus heat/time/volume signals
- User Emotion Layer — 18 heuristic emotion labels with animated Noto Emoji and confidence scores
- Darkroom flight-recorder UI — amber-phosphor-on-black, CRT scanlines, instrument framing
- Instrument boot-up decode FX — stats and readouts scramble-resolve into place (powered by the bundled ShuffleText), and gracefully respects
prefers-reduced-motion - Dark / light mode — darkroom default, blueprint-style light mode, persists across sessions
- Zero dependencies — Python stdlib only; single-file frontend, no build tools
- Fast — parses and renders 30K+ line session files in under a second
python3 viewer.pyOpens http://localhost:8080 in your browser. Use -p for a different port,
--no-open to skip the browser launch.
python3 viewer.py -p 3000 --no-openDeep-link straight to a session:
http://localhost:8080/?id=<session-id>
- Python 3.7+ (standard library only — nothing to install)
- Windows, macOS, or Linux
- Codex CLI or Desktop, with sessions stored in
~/.codex/sessions/ - A modern browser. Fonts and the animated emoji load from Google's CDN when online; offline it falls back cleanly to monospace and skips the emoji.
- Load by ID — paste a session UUID into the input and click Load (Enter works too)
- View conversation — your messages on the right, Codex replies on the left
- Expand thinking — click a "Codex thinking" block to read the reasoning
- Search — type in the search bar (or press
Ctrl+F/Cmd+F) - Recorder — open Black Box Recorder and click any slice to inspect that turn
- X-Ray — inspect a turn's prompt, reasoning, reply, and friction signals
- Emotion — browse the 18-label palette and per-turn heuristic labels (rule-based signals, not model-grade sentiment analysis)
- Theme — toggle dark/light from the header button
- Export — click
Export .mdto download a Markdown transcript
| Endpoint | Description |
|---|---|
GET / |
Serves the frontend |
HEAD / |
Health-check headers for the frontend |
GET /api/session/<id> |
Returns session metadata, events, and stats (JSON) |
A session response looks like:
{
"meta": { "id": "…", "timestamp": "…", "model": "…", "cwd": "…" },
"events": [ { "timestamp": "…", "role": "user|codex_think|codex_reply", "content": "…" } ],
"stats": { "users": 0, "replies": 0, "thinking": 0, "total": 0 }
}viewer.py is a tiny stdlib HTTP server. It locates a session JSONL under
~/.codex/sessions/ (and ~/.codex/archived_sessions/) by ID, parses the
event_msg records into user / codex_think / codex_reply events, strips
Codex's internal request wrapper from user messages, and serves them as JSON.
index.html does the rest entirely client-side — grouping events into turns and
computing the per-turn metrics that drive every visualization.
codex-session-viewer/
├── README.md # This file
├── LICENSE # MIT
├── THIRD-PARTY-NOTICES.md # Bundled third-party licenses (ShuffleText, fonts)
├── viewer.py # HTTP server + API + session parser
└── index.html # Frontend (single file, zero build deps)
~/.local/bin/codex-session— a companion local CLI for extracting Codex sessions to Markdown/JSON
- ShuffleText by IKEDA Yasunobu (MIT) — the decode/scramble text effect, vendored inline
- Oxanium & IBM Plex Mono (OFL) — typography
- Noto Emoji (OFL) — animated emotion markers
See THIRD-PARTY-NOTICES.md for full license texts.
MIT — see LICENSE.
