Blog
·7 min

Where Codex CLI Stores Your Session History

Codex writes every session to a JSONL rollout file under ~/.codex/sessions, and recent versions index them in a SQLite database alongside. Here is the layout, what each file holds, and how to keep it.

Codex CLI saves every session automatically. There is no save command and no prompt asking whether you want to keep the conversation — it writes the transcript to disk as you work. That is the good news. The rest of this article is about where it goes and what happens to it afterwards.

The exact location

Sessions are stored as JSONL rollout files, partitioned by date, under your Codex home directory:

# macOS / Linux
~/.codex/sessions/YYYY/MM/DD/rollout-YYYY-MM-DDTHH-MM-SS-<id>.jsonl

# Windows
%USERPROFILE%\.codex\sessions\YYYY\MM\DD\

# if you set it explicitly
$CODEX_HOME/sessions/

Each rollout file is the full transcript of one session: your prompts, the model's responses, the tool calls it made, and the results those calls returned — timestamped, one JSON object per line. It is the most complete on-disk record any of the mainstream AI coding tools writes, and it is plain text you can read with any editor.

Two more files sit next to it. session_index.jsonl in the Codex home is a metadata cache covering active and archived sessions, and history.jsonl records command history across sessions. Neither contains anything the rollouts do not; they exist so the CLI can list and resume without reading every transcript.

The SQLite index recent versions added

Newer Codex builds keep a SQLite database in the same directory — state_5.sqlite on the machine used for this article, the number being a schema generation that has moved over time. Its threads table is worth knowing about, because it records more than the transcript does:

sqlite3 -readonly ~/.codex/state_5.sqlite ".schema threads"

# columns include:
#   rollout_path      → the JSONL transcript this thread points at
#   cwd, title, first_user_message, preview
#   git_sha, git_branch, git_origin_url
#   model, model_provider, reasoning_effort, tokens_used
#   archived, archived_at, created_at, updated_at

That is a genuinely useful index: it ties each conversation to the repository, branch and commit it happened on, and to the token cost it incurred. If you want to know which sessions touched a given branch, this table can answer it and the transcripts alone cannot.

It also tells you something about the design. The database is an index; the rollout files are the record. If the index is regenerated or its schema generation moves on, what you keep is whatever is still in sessions/.

How to see what you have

# how many sessions are on this machine
find ~/.codex/sessions -name 'rollout-*.jsonl' | wc -l

# how much disk they use
du -sh ~/.codex/sessions

# the oldest one still on disk
find ~/.codex/sessions -name 'rollout-*.jsonl' | sort | head -1

# resume the most recent session
codex resume --last

If the first command returns nothing while you have been using Codex, check whether CODEX_HOME is set to somewhere other than ~/.codex — that is the usual explanation, and it is a one-line check: echo $CODEX_HOME.

What actually goes wrong

Codex is better behaved here than most of its peers: the transcripts are complete, plain text, and not deleted on a timer. The failure modes are the ordinary ones, which makes them easy to ignore until they happen.

  • The directory grows without limit, because nothing prunes it. That is the right default for a record and the wrong one for disk, so people eventually delete it by hand — usually all of it, usually in a hurry.
  • Archiving a session is a lifecycle operation, not a backup. It changes how the session is listed; it does not put a copy anywhere else.
  • It lives in your home directory on one machine. A reinstall on a new laptop starts empty, and nothing carries the old sessions across.
  • The rollouts record what Codex did, not what you did afterwards. The link between a session and the commit it produced exists only in the SQLite index, and only while that index does.
  • It covers Codex alone. If your team also uses Claude Code, Cursor or Copilot, each keeps its own history in its own place under its own rules.

How to back it up

The transcripts are text and compress extremely well. There is no reason not to keep them:

DEST="$HOME/Backups/codex-$(date +%Y-%m-%d).tar.gz"
tar -czf "$DEST" -C "$HOME" .codex/sessions .codex/session_index.jsonl

# check what you just saved
tar -tzf "$DEST" | wc -l

Put the destination somewhere your existing backups already reach. If you want the same picture across every AI tool on the machine rather than Codex alone, promptwake doctor scans for AI coding history and reports what each tool holds and what is inside a deletion window — via npx, no account, writes nothing and sends nothing anywhere.

Where the personal fix stops working

A tarball in your home directory answers the question for one developer. It does not answer it for a team, and the gap is not about backup software.

The archive is on the laptop that made it, readable by the person who made it, in a format nobody else on the team is going to parse. There is no shared view, so a lead cannot see what the team asked the model to build. It covers one tool out of several. And a tar file on a personal machine is not evidence of anything you could show to a customer's security questionnaire asking how AI-generated code is reviewed and retained.

Codex writes a better record than most tools do. It still writes it to one laptop, where it stays until that laptop stops existing.

What to do this week

Run the count and the du. If the answer is a few hundred sessions and a few gigabytes, you have a real archive of how a real share of your codebase came to exist — back it up today, before the disk-space cleanup that eventually deletes it.

If the conclusion is that this record belongs to the team rather than to whichever laptop produced it, that is what PromptWake does: it reads what Codex and the other tools already write to disk, keeps it locally by default, and on the paid tiers syncs prompt, response and resulting diff into one timeline the team can search. Do the backup either way.