Reading Codex rollout files: what I hit, what I worked around, and what I still need #45392
Replies: 2 comments 1 reply
|
For the “turn finished vs process died” question, there are explicit terminal events in the current implementation, but I would keep the raw-rollout adapter versioned. At commit Importantly, Useful regression cases: normal completion, terminal error, explicit interruption, a truncated log without its terminal record, and an old completed turn followed by a new unfinished turn. The old completion must not mark the new turn done. The documented App Server interface separately uses |
|
ooocooc's terminal events are the answer for reading the file after the fact. If the viewer can also run alongside the session, there's a second signal with no rollout parsing: Codex's lifecycle hooks. Stop fires when the turn ends, and PostToolUse fires per tool call, so "what got edited this turn" is the apply_patch and exec calls as they happen. Codex names its tools apply_patch for edits and exec for shell, which is what a matcher has to key on. We build kgai and moved our end-of-turn logic from transcript parsing to those two hooks, for a reason next to yours. The rollout shape is Codex-only, Gemini's end-of-turn event carries no transcript, and edits made through the shell (sed -i, a heredoc) never show up as an edit item anyway. Untested: a killed process. I'd expect no Stop, but that's a guess, not a spec. |
Uh oh!
There was an error while loading. Please reload this page.
I build Fishbowl, a local read-only viewer for coding-agent sessions
(https://github.com/zonion088-design/fishbowl). It reads
~/.claude/projects/.jsonl on the Claude Code side and
~/.codex/sessions/YYYY/MM/DD/rollout-.jsonl on the Codex side.
The Codex side has been the harder of the two. Writing down what I hit, in case
others are building on the same files — and because I'd rather be corrected than
keep guessing.
Problems I hit, and what I did about them
1. The file is being written while you read it.
A line without a trailing newline has to be held over to the next pass, or you
parse truncated JSON. I keep a byte-offset cursor per file and only consume
complete lines.
2. Records occasionally can't be parsed.
I've seen torn writes, and upgrades that leave a rollout corrupted (#45150). My
reader skips and flags rather than failing — a bad record shouldn't take the
whole session down, but it also shouldn't disappear silently.
3. There's no identity I'm willing to trust.
Given the answer in #45251 — nothing outside the app server API is durable — I
key activities on (file, line number) instead of any ID inside the record. That
survives field renames, which matters because #43593 reports exactly that kind
of silent vocabulary change.
4. Volume.
#42345 notes each command's output is stored four times; a 12-day session hit
1.4 GB. My scanner is incremental for that reason — stat() every few seconds,
parse only the new bytes.
What I haven't solved
Turn finished vs. process died mid-turn. I've been inferring the boundary
from record sequences rather than keying off a completion marker. If there's a
signal that's actually reliable for this, I'd rather use it than keep guessing.
Sessions that lose their rollout entirely. On the Claude Code side there's a
report of sessions going unreachable with no transcript left on disk (#93920).
I don't know whether the Codex equivalent exists or what the recovery path is.
I'll keep this thread updated as I learn more — including if any of the above
turns out to be wrong, which is likely for at least one of them.
All reactions