Codex CLI history: where it is, how to read it, how to search it
every session is on disk; Codex lists them, it does not search them
Codex keeps every session you run. What it does not have is a way to ask which session had the fix, or to look at them outside the resume picker. The files are plain enough that jq and sqlite3 go a long way, and a week in, one detail breaks the obvious grep.
Where Codex keeps it
Everything is under ${CODEX_HOME:-~/.codex}:
sessions/YYYY/MM/DD/rollout-<time>-<id>.jsonl: one file per session, the whole conversation, appended as it runs. The first line issession_meta, with the session id and the working directory.- After seven days Codex compresses a rollout in the background to
rollout-….jsonl.zst. Codex reads both forms. Anything that looks for*.jsonlstops seeing sessions older than a week. archived_sessions/: sessions you archived, same format.history.jsonl: your prompts only, one line each, with the session id. No replies, no commands.state_5.sqlite: the session list the resume picker reads, with title, working directory, git branch, token count and an archived flag. The number in the name moves with Codex releases.
What Codex gives you
codex resume # picker, sessions started in this directory codex resume --all # every directory codex resume --last # straight into the most recent one codex resume --include-non-interactive # codex exec runs too codex fork # a copy of an old session to continue from codex archive <id> # hide it; codex unarchive brings it back codex delete <id> # gone for good
The picker shows titles and first messages. It does not look inside the conversations, and it only knows about Codex.
Reading it without any tool
The last few sessions, with where they ran:
for f in $(ls -t ~/.codex/sessions/*/*/*/rollout-*.jsonl | head -10); do jq -r 'select(.type=="session_meta") | .payload | "\(.timestamp[:16]) \(.cwd) \(.id)"' "$f" done
The same list from the picker's database, read-only:
sqlite3 -readonly ~/.codex/state_5.sqlite " SELECT datetime(updated_at, 'unixepoch', 'localtime'), substr(title, 1, 50), cwd FROM threads WHERE archived = 0 ORDER BY updated_at DESC LIMIT 20;"
What you typed in one session, from the prompt log. It holds interactive sessions only; prompts given to codex exec are not in it:
jq -r 'select(.session_id=="<id>") | .text' ~/.codex/history.jsonl
Which sessions mention something, including the compressed ones:
grep -l "pgbouncer" ~/.codex/sessions/*/*/*/rollout-*.jsonl zstdgrep -l "pgbouncer" ~/.codex/sessions/*/*/*/rollout-*.jsonl.zst
That works for one word you remember exactly. It gets slow over months of history, has no ranking, and misses the session where you said it differently.
Searching it
deja-vu indexes these files, compressed ones and archived ones included, with the history of every other agent on the machine. It only reads them.
deja index deja --harness codex "pgbouncer prepared statement" # ranked, with the session id deja last 20 --harness codex # recent sessions, any directory deja show <id> # the conversation deja resume <id> # the command that reopens it in Codex deja view # all of it as one local HTML page
Bare deja opens the same search as a screen that updates as you type: a narrows it to Codex, ↵ reads a session at the match, r reopens it in Codex.
Drop --harness codex and the same search covers Claude Code, Cursor, opencode and the rest, which is usually where the answer turns out to be. Credentials are stripped as the index is built. A session deja has indexed stays searchable after codex delete or a cleanup; deja forget removes it on purpose.
To have Codex look this up itself at the start of a session, rather than you running the search, see memory for Codex.
On more than one machine
Codex keeps its history local, and codex resume only lists what is on this disk. deja can carry its index between machines over SSH, with no service in between:
deja sync ssh devbox # push this machine's sessions there deja sync ssh devbox --both # and pull its sessions here
What arrives is searchable with deja on the other side. It does not add sessions to the other machine's resume picker. Across machines has the details.
Deleting Codex sessions · Where every agent stores history · Resuming a session
Found this useful? Star deja-vu on GitHub.