What happened?
Summary
Running plannotator last in Codex Desktop can fail with:
No rendered assistant message found in session logs.
This happens when one Codex thread is represented by multiple rollout JSONL files. Plannotator may select an empty or aborted rollout even though another rollout for the same thread contains the previous rendered assistant message.
Observed scenario
In the affected Codex thread, several rollout files contained the same thread ID:
- one rollout was aborted and contained no assistant
output_text,
- another rollout contained the previous rendered assistant response,
- the active rollout contained the current command.
plannotator last selected the empty rollout and stopped without checking the other matching files.
Debug output, with identifiers redacted:
[DEBUG] Codex detected, thread ID: <redacted>
[DEBUG] Rollout: ~/.codex/sessions/YYYY/MM/DD/rollout-...<thread-id>_<segment-id>.jsonl
No rendered assistant message found in session logs.
Steps to reproduce
- Open a task in Codex Desktop.
- Continue or resume it until Codex creates multiple rollout files associated with the same thread ID.
- Ensure one matching rollout is empty or aborted while another contains a completed assistant response.
- Run plannotator last.
- Plannotator may select the empty rollout and return the error above.
I do not yet have a deterministic sequence that always makes Codex split a thread into multiple rollout files, but this structure occurred in a real Codex Desktop task.
Expected behavior
Plannotator should treat all rollout files belonging to the current Codex thread as one logical conversation and open the most recent completed assistant response before the active turn.
Actual behavior
Plannotator selects one matching rollout file and fails immediately when that file does not contain a rendered assistant message, even though another rollout for the same thread does.
Likely root cause
findCodexRolloutByThreadId() returns the first filename from readdirSync() that contains the thread ID:
https://github.com/backnotprop/plannotator/blob/main/apps/hook/server/codex-session.ts
The candidates are not ordered or inspected before one is selected. Therefore, when several rollout files match the same thread, filesystem iteration order determines which rollout is used.
Plannotator version
plannotator 0.27.1
OS
macOS
Agent
Codex
Where did it happen?
Annotate
What happened?
Summary
Running
plannotator lastin Codex Desktop can fail with:This happens when one Codex thread is represented by multiple rollout JSONL files. Plannotator may select an empty or aborted rollout even though another rollout for the same thread contains the previous rendered assistant message.
Observed scenario
In the affected Codex thread, several rollout files contained the same thread ID:
output_text,plannotator lastselected the empty rollout and stopped without checking the other matching files.Debug output, with identifiers redacted:
Steps to reproduce
I do not yet have a deterministic sequence that always makes Codex split a thread into multiple rollout files, but this structure occurred in a real Codex Desktop task.
Expected behavior
Plannotator should treat all rollout files belonging to the current Codex thread as one logical conversation and open the most recent completed assistant response before the active turn.
Actual behavior
Plannotator selects one matching rollout file and fails immediately when that file does not contain a rendered assistant message, even though another rollout for the same thread does.
Likely root cause
findCodexRolloutByThreadId()returns the first filename fromreaddirSync()that contains the thread ID:https://github.com/backnotprop/plannotator/blob/main/apps/hook/server/codex-session.tsThe candidates are not ordered or inspected before one is selected. Therefore, when several rollout files match the same thread, filesystem iteration order determines which rollout is used.
Plannotator version
plannotator 0.27.1
OS
macOS
Agent
Codex
Where did it happen?
Annotate