Skip to content

feat: response-viewer (eye) support for Codex sessions#152

Merged
Ark0N merged 2 commits into
Ark0N:masterfrom
pirronewantlux529-coder:codex-response-viewer
Jul 12, 2026
Merged

feat: response-viewer (eye) support for Codex sessions#152
Ark0N merged 2 commits into
Ark0N:masterfrom
pirronewantlux529-coder:codex-response-viewer

Conversation

@pirronewantlux529-coder

Copy link
Copy Markdown

Problem

The response-viewer currently only reads Claude transcripts from ~/.claude/projects. For Codex panes the eye falls back to a raw terminal-buffer dump (TUI repaint garbage), and there is no way to see the last response or the conversation thread cleanly.

A naive fix (match rollouts in ~/.codex/sessions/** by cwd + newest mtime) breaks as soon as two Codex panes share a working directory — each pane's eye shows whatever pane wrote last. We ran that variant privately for two weeks; this PR is the design that survived real-world usage.

Design: locating THIS pane's rollout

In order of confidence:

  1. history matchSession now tracks the pane's last Enter (codexLastSubmitAt, both write() and writeViaMux() paths). Correlating it against ~/.codex/history.jsonl {session_id, ts} entries identifies the thread the pane is actually on — the only signal that survives /resume, /new and /fork typed inside the codex TUI itself. An entry is credited to the pane whose Enter is closest among all codex panes, so a menu keystroke elsewhere can't steal attribution. Resolved pins are cached per (session, submitAt).
  2. originator match — codex panes are spawned with CODEX_INTERNAL_ORIGINATOR_OVERRIDE=codeman_<sessionId>; codex (verified on 0.144.1) writes the value into session_meta.originator of every rollout it creates, including new files after /new. Newest match wins.
  3. resume-id match — resumed rollouts keep their original session_meta (codex appends without rewriting it), so originator matching can't see them; but the rollout uuid is in the filename and codexConfig.resumeSessionId is known (validated as UUID first).
  4. cwd+mtime fallback — for pre-existing panes. Hardened: case-blind path compare (codex records the launch-time case; /mnt paths vary on WSL), and rollouts claimed by other panes' originators are excluded, so an idle pane can't display a sibling's thread.

Reader quality

  • User turns come from event_msg/user_message — codex emits one per real user input, and injected context (AGENTS.md, environment_context, …) never appears there, so no fragile filtering heuristics. Legacy response_item user rows are deduped per-text against the event set, so mixed-version rollouts (old turns without event_msg) keep full history.
  • Image inputs render an [image ×N] placeholder instead of silently vanishing.
  • session_meta identity is parsed once per rollout and cached (it is write-once — verified that resume appends without touching it), so repeat eye clicks cost stats + head reads of new files only.
  • ?context=full returns the whole user/assistant thread, same shape as the Claude path.

Frontend

  • Conversation role label follows the session mode (Codex / Gemini / OpenCode / Claude) instead of hardcoding "Claude".
  • The terminal-buffer fallback is now Claude-only — _cleanTerminalBuffer knows Claude CLI output, but for TUI modes it produced repaint garbage; those now show a clear placeholder.

Testing

Verified on codex-cli 0.144.1, tmux backend, two machines (WSL2):

  • Two codex panes created in the same directory within the same second: each eye shows its own response.
  • codex resume <id> panes resolve via filename uuid.
  • /new inside a resumed pane: originator match takes over (newest wins).
  • /resume typed inside the TUI, then a new message: history match follows the pane to the resumed thread.
  • Idle pane in a shared directory: empty placeholder, no bleed-over.
  • Claude sessions: unchanged behavior (regression-checked).
  • tsc, prettier, npm run build all clean.

Note: CODEX_INTERNAL_ORIGINATOR_OVERRIDE is an internal codex interface; if a future codex stops honoring it, layers 1/3/4 still function — the design degrades gracefully.

🤖 Generated with Claude Code

codeman-local and others added 2 commits July 12, 2026 10:39
The response-viewer (eye) currently reads only ~/.claude/projects — for
Codex panes it falls back to a raw terminal-buffer dump. This adds a
Codex-aware reader with exact per-pane rollout attribution.

Locating THIS pane's rollout (~/.codex/sessions/**), in confidence order:

1. history match — Session tracks the pane's last Enter
   (codexLastSubmitAt); correlating it against ~/.codex/history.jsonl
   {session_id, ts} entries identifies the thread the pane is ACTUALLY
   on, surviving /resume, /new and /fork typed inside the codex TUI.
   An entry is credited to the pane whose Enter is closest, so menu
   keystrokes in other panes can't steal attribution.
2. originator match — codex panes are spawned with
   CODEX_INTERNAL_ORIGINATOR_OVERRIDE=codeman_<sessionId>, which codex
   (verified on 0.144.1) writes into session_meta.originator of every
   rollout it creates.
3. resume-id match — resumed rollouts keep their original session_meta
   (codex appends without rewriting), but the uuid is in the filename.
4. cwd+mtime heuristic — case-blind compare (codex records launch-time
   path case) and rollouts claimed by other panes are excluded.

Reader details: user turns come from event_msg/user_message (real input
only — AGENTS.md / environment_context injections never appear there),
deduped against legacy response_item rows per-text so mixed-version
rollouts keep full history; image inputs render an [image xN]
placeholder; session_meta identity is cached per path (write-once).

Frontend: thread role label follows session mode (Codex/Gemini/
OpenCode); the terminal-buffer fallback is Claude-only — TUI modes show
a clear placeholder instead of a repaint dump.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…(PR Ark0N#152)

- Add test/routes/session-routes-codex-last-response.test.ts (app.inject +
  temp CODEX_HOME fixture rollouts): originator match beats cwd fallback when
  two panes share a dir, cwd fallback excludes sibling-claimed/foreign-cwd
  rollouts, resume-uuid filename match, history.jsonl pin outranks originator,
  event_msg/legacy user-turn dedup keeps old-codex turns, injected-context
  filtering, image placeholder, envelope shape ({success:true,data:{text,
  timestamp[,messages]}}), and a Claude-mode regression guard (codex reader
  never consulted for claude sessions)
- Replace clear-at-cap Map caches (codexHistoryPinCache, codexRolloutMetaCache)
  with the repo-standard LRUMap so a full cache wipe can't thrash hot entries
  on large rollout collections
- Join multi-block assistant/user text with a blank line instead of no
  separator (extractCodexBlockText)
- Re-enable the terminal-buffer eye fallback for shell sessions (they have no
  transcript source at all); TUI modes keep the clear placeholder

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Ark0N Ark0N merged commit 1301b4b into Ark0N:master Jul 12, 2026
2 checks passed
@Ark0N

Ark0N commented Jul 12, 2026

Copy link
Copy Markdown
Owner

Merged — thank you @pirronewantlux529-coder, and welcome as a first-time contributor! 🎉 The 4-layer Codex rollout resolution (history pin → originator → resume-UUID → cwd fallback) is genuinely thoughtful work, and the reviewers found the parser logic sound. Review added the missing test coverage (10 route tests over fixture rollouts covering pin/originator/uuid precedence, dedup, injected-context filtering, and a Claude-mode regression guard) plus small hardening (LRU caches, multi-block text joins). Hope to see more from you! 🙏

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.

3 participants