Expand description
The Codex rollout watcher, which supplements the Codex hook feed.
An engine-owned background task over
$CODEX_HOME/sessions/YYYY/MM/DD/rollout-*.jsonl (#1909, ADR-0087), the
Codex twin of the Claude transcript watcher.
Hooks own a Codex session’s state; this watcher covers what they miss:
- Discovery — a session started before the daemon (or before the hooks
were installed and trusted) still has a rollout file. Its head-of-file
session_metaline yields the session’s id andcwd, so the session lands on the right worktree row even before a hook fires. - Ends hooks cannot report. Archiving an IDE or Desktop chat moves its
rollout into
$CODEX_HOME/archived_sessions/, which is outside the watched tree, so a rollout that vanishes reads as an end. And a Codex process killed by SIGHUP (closing its terminal tab), SIGTERM or SIGKILL fires noSessionEnd: while a thread is loaded, Codex holds an exclusiveflockon$CODEX_HOME/thread-writer-locks/<session-id>.lock, and the kernel drops it when the process dies, however it dies. A lock this watcher has seen held that is later free (or gone) ends the session, instead of it lingering for the registry’s TTL. - Idle liveness. An idle Codex session emits nothing, so it would age out on the TTL while its process lives on. A held lock is re-reported as a state-preserving heartbeat.
What it reads, and what it never does:
- Only the first line of a rollout (
session_meta, bounded to [MAX_HEAD_BYTES]), and from it onlyid/session_id,cwdandsource; never a conversation line. Growth is size/mtime only. Nothing is logged. - Subagent threads are skipped: their
sourceis an object ({"subagent": …}), and their hook events already carry the parent’s id. - It never reports a state: growth is a heartbeat, not
working, because a rollout keeps being written around the turn’sStopand would otherwise hold an idle session atworking. So a session only this watcher sees readsidle. It can never report an approval either — the rollout records none. - The lock probe is a non-blocking shared
flocktaken and dropped at once: on a session’s first sight, then once per scan while it is tracked and not ended (an ended session is left alone until its rollout grows). Against a live holder it fails harmlessly; it can only collide with Codex acquiring the lock for that same thread in the same instant. - On first sight a rollout whose lock is free or gone is recorded but not announced — a daemon restart must not list sessions that already ended.
Functions§
- spawn
- Spawns the watcher loop, returning its
JoinHandle.