026. The Codex daemon holds the rollout files
- Date
- 2026-10-30
- Agents
- Codex CLI
- Measured on
- real machine
Measured
2026-10-30, Codex CLI 0.164.0 (standalone install, x86_64-unknown-linux-musl),
on Linux (Debian 13, x64), in a private tmux server with a throwaway
HOME and a copied login. The scenarios scenarios/codex/approval.sh
(with and without --no-daemon) and scenarios/codex/two-sessions.sh
read /proc/<pid>/fd of each process at each step.
Measured on: real machine.
What was measured
- In the default mode, the TUI starts an app-server daemon:
~/.codex/packages/app-server-daemon/releases/<version>-<target>/bin/codex app-server --listen unix:// --analytics-default-enabled --managed-daemon. It has no tty. Its parent is the TUI. A second child,codex app-server daemon pid-update-loop, also starts. - The daemon, not the TUI, holds the session files open:
~/.codex/thread-writer-locks/<session id>.lock, from the start of the session, before the first prompt.~/.codex/sessions/YYYY/MM/DD/rollout-<time>-<session id>.jsonl, from the first prompt. The TUI holds neither file.
- Two TUIs with the same
HOMEshare one daemon. The daemon is a child of one of the two TUIs. It holds the lock and the rollout file of both sessions. - After the TUI exits, the daemon keeps running. Its parent becomes process 1. It keeps the lock and the rollout file of the ended session open.
codex resume --lastuses the daemon that runs. It appends to the same rollout file. It makes no new file. No process in the tree of the resumed TUI holds the file.- With
--no-daemon, the TUI itself holds the lock from the start and the rollout file from the first prompt.resumealso appends to the same file in this mode.
Mechanism
The daemon writes the sessions for all TUIs of one HOME. Thus an open
rollout file in the process tree of a TUI does not prove that the session
belongs to that TUI, and an open rollout file does not prove that its
session is live. Only with --no-daemon does an open file link one TUI to
one session.
The session ID in the lock file name is known before the first prompt, when no rollout file exists yet.
Incident
aw planned an exact binding from a Codex TUI to its rollout file through the open files of the process tree. In the default mode that binding can pick the session of another TUI.
Screens
None.
Not measured
- macOS and Windows.
- Whether a file links a TUI to its thread in daemon mode, for example
~/.codex/state_5.sqlite. It was not read. - When the daemon exits after the last TUI exits. It still ran 20 s after.
- The sandbox helper: on this machine
bwrapcould not make a namespace, so the commands ran with no sandbox helper process.
Later measurement, 2026-10-30 (0.164.0)
The scenario scenarios/codex/daemon-life.sh measured three items of the
list above. Fact 39 and fact 40 give the details.
- The life of the daemon: it did not exit in the 300 s after the last TUI exited, in two runs. A TUI that started 30 s after the last exit used the same daemon. About 6 minutes after its start, the daemon replaced itself with a daemon of a newer version (0.166.0), with a new pid. The new daemon held no file of the ended sessions.
- A
--no-daemonTUI next to a running daemon holds its own rollout file and lock. The daemon does not hold them. - The layout of
~/.codex/state_5.sqliteand of the other databases has no column for a pid or a client of the daemon. Onlylogsinlogs_2.sqlitejoins aprocess_uuidto athread_id. The rows were not read.