Codex CLI session format

Store and files

Codex CLI stores state under ${CODEX_HOME:-~/.codex}. Xcode-hosted Codex sessions use ${HOME}/Library/Developer/Xcode/CodingAssistant/codex. deja keeps both stores under the single codex harness: DEJA_CODEX_ROOT relocates the CLI store and DEJA_XCODE_CODEX_ROOT relocates the Xcode store. Rollouts are sessions/YYYY/MM/DD/rollout-*.jsonl, and a rollout Codex has compressed is rollout-*.jsonl.zst — its own background worker rewrites one once it is seven days old (COMPRESSED_SUFFIX, MIN_ROLLOUT_AGE in codex-rs/rollout/src/compression.rs), and it materializes the plain file back before appending, so both names exist for one session while that happens. archived_sessions/ holds the same JSONL for sessions Codex has archived. history.jsonl belongs to the CLI store and contains prompt history.

Rollout records

A rollout begins with session metadata and then event records. The parser reads payload.role, payload.content, and the older payload.message fallback.

{"timestamp":"2026-07-17T09:00:00Z","type":"session_meta","payload":{"session_id":"session-7","cwd":"/work/api"}}
{"timestamp":"2026-07-17T09:00:01Z","type":"response_item","payload":{"role":"assistant","content":[{"type":"output_text","text":"The migration is complete."}]}}

payload.role is retained. When only payload.message is present, an agent_message payload is the assistant and anything else is the user. event_msg turns are read only when the rollout has no roled response_item messages, since a current rollout carries every turn in both streams. An exec_command (cmd) or shell_command (command) function_call becomes a command record, its function_call_output tool output (with the exit code), and a custom_tool_call (apply_patch) the edit it made. Content may be a string or an array of text-bearing parts. session_meta supplies the stable ID and project working directory. Timestamps accept RFC 3339, Unix seconds, or Unix milliseconds.

Prompt history

Each history line is independent:

{"session_id":"session-7","ts":1784278801,"text":"check the migration"}

History entries map to one-message sessions with role user and project history. The same prompt is usually in its rollout too. A full load keeps only the entries whose session has no rollout; an incremental pass reads the history file on its own, so a prompt can still appear in both.

Known quirks and drift

  • Rollout files are append-only JSONL and may have a torn final line.
  • Events without a payload, and payloads that are neither a message nor a tool call, are ignored.
  • history.jsonl duplicates user prompts but lacks assistant responses and project metadata.
  • Reading a compressed rollout needs the zstd CLI; without it the store reports zstd CLI not found rather than quietly holding fewer sessions. A store of plain rollouts needs nothing.
  • Older records use payload.message; current records generally use structured payload.content.

Last verified: 2026-09-10


deja reads this format and thirty-seven others, and turns what it finds into memory your agents can search. See the harness matrix for what is wired where, or install it and search your own history.

Found this useful? Star deja-vu on GitHub.