Agentic AI AcademyAgentic AI Academy

Sessions, Resume & Forking

Continue, branch, and recover long-running work

Intermediate 11 minBuilder
What you'll be able to do
  • Resume prior work with `codex resume`, including the picker, `--last`, `--all`, and resuming a specific `<SESSION_ID>`
  • Branch a conversation safely with `codex fork` and the in-session `/fork`, `/new`, and `/resume` commands
  • Explain where sessions are stored (`$CODEX_HOME/sessions/`), that they are JSONL rollout files, and that resuming appends
  • Locate a session ID from the picker, `/status`, or the session files on disk
  • Mirror the same resume controls in headless automation with `codex exec resume`
  • Choose between resume, fork, and new for a given situation, and treat the on-disk layout as volatile
At a glance

Codex doesn't just hold a conversation — it persists it. Every interactive session is written to disk as a rollout file, so you can close your terminal, reboot, and pick up a multi-day task exactly where you left off. This lesson teaches the three moves that make long-horizon work durable: resuming a saved session, forking it to branch an idea without losing the original, and starting fresh inside the same CLI — plus where those files live and how to do all of it headlessly.

  1. 1The mental model: a session is a file, not a vibe
  2. 2Resuming: pick up exactly where you left off
  3. 3Forking and starting fresh: branch an idea without burning the thread
  4. 4Where sessions live on disk
  5. 5Finding a session ID
  6. 6Resume in headless and automated runs

The mental model: a session is a file, not a vibe

Most chat tools treat a conversation as something that lives only in the window — close the tab and it's gone. Codex is different: every interactive session is persisted to disk the moment it starts. Think of a session less like a phone call and more like a document that Codex keeps writing to as you work.

That one fact unlocks everything in this lesson. Because the conversation is a durable artifact, you can:

  • Close your terminal and come back tomorrow — the full transcript, including every file edit and command Codex ran, is still there to resume.
  • Survive a crash, a reboot, or an accidental Ctrl+C without re-explaining the task from scratch.
  • Run genuinely long-horizon work — a migration that spans several days — as one coherent thread instead of a dozen disconnected chats.

The unit Codex persists is a session (also called a thread or a rollout). It carries the model and provider you were using, the working directory, and the ordered list of everything that happened. When you resume, Codex replays that history into context and continues as if you never left.

The rest of this lesson is really just three verbs you apply to that durable file: resume it, fork it, or start a new one — plus knowing where it lives so you can find, copy, or inspect it.

Key insight

Why this matters for agents specifically

A coding agent's value compounds with context — it gets better at your task the longer it's been working on it. Throwing that context away at the end of every terminal session would waste the most expensive thing Codex builds up. Persistence is what lets the agent stay useful across days, not minutes.

Resuming: pick up exactly where you left off

The core command is codex resume. Run it and Codex opens a picker — a list of your recent sessions. Highlight one to see its summary, press Enter, and you're back in that thread with full history.

Most of the time you don't want the picker — you want the session you were just in. There are flags for that:

CommandWhat it does
codex resumeOpens the picker of recent sessions; Enter reopens the highlighted one
codex resume --lastSkips the picker, jumps straight to your most recent session in the current directory
codex resume --allUsed with --last to ignore the current-directory filter (include sessions from any dir)
codex resume <SESSION_ID>Resume a specific session by its ID; accepts an optional trailing prompt

The directory filter is the subtle part. By default Codex scopes the picker and --last to sessions started in your current working directory, which is usually what you want — you cd into a project and resume that project's work. When you've forgotten which directory a session lived in, combine --last --all to reach across all of them.

Resuming a specific session is the most precise option. You can even hand it a fresh instruction in the same breath:

bash
# Reopen a session by ID and immediately give it a new task
codex resume 0f9c1a2b-... "now add tests for the new endpoint"

Inside an already-open CLI you don't need to quit first — type /resume to load a saved conversation from your session list without leaving the program.

Tip

`--last` is your daily driver

For the common case — you closed the terminal an hour ago and want to keep going — codex resume --last from inside the project directory is the fastest path back. No picker, no IDs, no hunting.

Note

Resume vs. starting over

Resuming replays the entire prior transcript into context. For a long thread that can be a lot of tokens. If the old context is stale or irrelevant to your next task, a fresh session (next section) is often cheaper and cleaner than dragging history along.

Forking and starting fresh: branch an idea without burning the thread

Resuming continues a single line of history. But real work isn't always linear — sometimes you want to try an alternative approach without abandoning the conversation you've built. That's what forking is for.

codex fork [SESSION_ID] starts a new thread that preserves the original transcript as its starting point. The original session stays untouched; your fork is a copy you can take in a different direction. It's the conversational equivalent of git branch: explore a risky idea on a branch, and if it doesn't pan out, the trunk is exactly as you left it.

There are three in-session commands that round out your options without leaving the CLI:

CommandUse it when…
/forkYou want to branch the current conversation into a new thread and try something different from this point
/newYou want a clean slate — a fresh conversation inside the same running CLI, no prior history
/resumeYou want to switch into a saved conversation from your session list

The distinction between fork and new is worth fixing clearly:

  • Fork keeps the history and copies it into a separate branch — use it when the accumulated context is valuable and you want to explore a variation.
  • New discards the history and starts empty — use it when the context is stale or you're switching to an unrelated task.

This maps directly onto the session-hygiene principle Codex recommends: one thread per coherent unit of work, not one giant thread per project. When you finish a feature and start an unrelated bug fix, that's a /new. When you want to try a second implementation of the same feature, that's a /fork.

Tip

Fork before a risky experiment

About to let Codex attempt a big speculative refactor? /fork first. If it goes sideways you abandon the fork and resume the clean original — no need to untangle a polluted transcript or rely on Ctrl+C timing.

Where sessions live on disk

Resume and fork feel like magic until you know what they're reading. Codex stores every session as a JSONL rollout file — one file per session, where each line is a JSON record of a single event (the metadata header, then each user message, model reply, command run, and file change in order).

The root directory is $CODEX_HOME/sessions/, which defaults to ~/.codex/sessions/. You can relocate the whole Codex state tree — config, credentials, and sessions — by setting the CODEX_HOME environment variable, which is handy for isolating profiles or running Codex under automation.

text
~/.codex/
├── config.toml          # your settings
├── auth.json            # credentials
└── sessions/            # one rollout file per session
    └── YYYY/MM/DD/
        └── rollout-<timestamp>-<id>.jsonl

Three properties matter in practice:

  • Resuming appends. When you resume a session, Codex adds new events to the existing rollout file rather than creating a new one — so a long-running, repeatedly-resumed task lives in a single growing file.
  • The files are plain JSONL. You can read, grep, or archive them with ordinary tools. (Codex also keeps an archived_sessions/ directory for ones you've cleared away.)
  • The nested YYYY/MM/DD/ layout is community-reported, not a guaranteed contract. The root ($CODEX_HOME/sessions/) and the JSONL-rollout format are well established; the exact date-nesting and filename pattern come from community/DeepWiki sources and an issue tracker, so don't hard-code a path against them — let codex resume find files for you.

Watch out

Treat the on-disk layout as volatile

The precise sessions/YYYY/MM/DD/rollout-*.jsonl nesting is not documented on a primary OpenAI page — it's reported by the community. It can change between releases. Build scripts around codex resume / codex exec resume and session IDs, not against the directory structure. Verify the current layout if you genuinely need to parse files directly.

Finding a session ID

Several commands above take a <SESSION_ID>. A session ID is just the unique identifier Codex assigns each thread (a UUID). There are three reliable ways to get one:

  1. From the picker. Run codex resume and the list shows your recent sessions; the picker is the no-memory-required way to find the right thread by its summary.
  2. From /status. Inside an active session, /status displays the session configuration and token usage — including the current session's ID. This is the quickest way to grab the ID of the thread you're in right now (for example, to fork it from another terminal).
  3. From the session files. Because each rollout is a file under ~/.codex/sessions/, the ID is embedded in the filename and in the file's metadata header. Useful when scripting or when you're reconstructing what happened after the fact.

In practice you'll lean on the picker for interactive work and on /status (or the headless event stream) when you need to capture an ID programmatically.

Example

Grab-and-fork across two terminals

In terminal A, run /status to read the current session ID. In terminal B, run codex fork <SESSION_ID> to branch that exact conversation into a parallel thread — letting you explore a variation in B while A keeps its original line of work intact.

Resume in headless and automated runs

Everything so far has been interactive, but the same persistence model works for codex exec — the non-interactive command used in CI, cron jobs, and scripts. Headless runs are sessions too: they persist under ~/.codex/sessions just like interactive ones (unless you opt out).

codex exec resume mirrors the interactive flags exactly:

CommandWhat it does
codex exec resume --lastContinue the most recent session non-interactively
codex exec resume --allWith --last, ignore the current-directory filter
codex exec resume <SESSION_ID>Continue a specific session, optionally with a new prompt

This is what makes multi-step automation possible: a first job kicks off a task and records its session ID, and a later job resumes that exact thread to continue — for example, a pipeline that plans on one trigger and implements on the next.

bash
# Step 1: start a task headlessly and capture the thread it created
codex exec --json "draft a migration plan for the users table" > step1.jsonl

# (parse the thread/session id out of the JSONL event stream)

# Step 2 (later run): resume that exact session and continue the work
codex exec resume <SESSION_ID> "now generate the migration files"

If you don't want a run to persist — a throwaway check that shouldn't clutter your session history — codex exec supports an --ephemeral flag that skips writing the rollout to disk.

Note

Where the ID comes from in headless mode

Interactive sessions surface the ID via the picker and /status. In headless mode you capture it from the --json event stream — the thread/session identifier appears in the emitted events (e.g. on the thread-started event), which your script can parse and reuse on a later codex exec resume.

Try it: Resume, fork, and inspect a real session

Goal: build the muscle memory for durable sessions by running the full lifecycle yourself.

1) Start and persist a session. In a small repo, run codex and give it a real two-step task, e.g. "Add an input-validation helper to this module." Let it make the change, then quit the CLI entirely (/exit).

2) Resume by --last. From the same directory, run codex resume --last. Confirm the full prior transcript is back, then ask it to "add a unit test for that helper" — proving the context survived a clean exit.

3) Find the ID. Inside the resumed session, run /status and note the session ID it reports.

4) Fork a variation. Open a second terminal and run codex fork <SESSION_ID> (using the ID from step 3). In the fork, try an alternative — "rewrite the helper using a schema library instead" — and confirm the original session in terminal one is untouched.

5) Inspect the files. Look under ~/.codex/sessions/ and find your rollout .jsonl file(s). Open one and confirm it's line-delimited JSON with a metadata header. Note the directory nesting you actually see — and remember it's volatile, so don't script against it.

6) (Optional) Headless resume. Run codex exec --json "summarize what this module does" > run.jsonl, locate the session/thread ID in the JSONL event stream, then run codex exec resume <SESSION_ID> "now list any edge cases it doesn't handle".

Write three sentences: when would you reach for resume vs fork vs /new, what did /status show you, and why is hard-coding the session file path a bad idea?

Key takeaways

  1. 1Every Codex session is persisted to disk the instant it starts, so you can close the terminal, reboot, or crash and still pick up long-horizon work exactly where you left off.
  2. 2`codex resume` opens a picker; `--last` jumps to the most recent session in the current directory, `--last --all` reaches across all directories, and `codex resume <SESSION_ID>` targets a specific thread (with an optional trailing prompt).
  3. 3`codex fork [SESSION_ID]` branches a conversation while preserving the original — fork keeps useful context, `/new` starts clean, and `/resume` switches into a saved thread from inside the CLI.
  4. 4Sessions are JSONL rollout files under `$CODEX_HOME/sessions/` (default `~/.codex/sessions/`), and resuming appends to the existing file rather than creating a new one.
  5. 5Get a session ID from the resume picker, from `/status` inside a live session, or from the session files themselves; in headless mode capture it from the `--json` event stream.
  6. 6`codex exec resume` mirrors `--last`/`--all`/`<SESSION_ID>` for CI and scripts — but the exact `YYYY/MM/DD/rollout-*.jsonl` layout is community-reported and volatile, so script against resume and IDs, not the directory structure.

Quiz

Lock in what you learned

Check your understanding

0 / 4 answered

1.You were working on a feature in `~/projects/api` an hour ago, closed the terminal, and now want to jump straight back into that exact session without scrolling through a picker. From inside `~/projects/api`, what's the fastest command?

2.Codex has built up a lot of useful context on a feature, and you want to try a second, riskier implementation of the SAME feature without losing the work you've done. Which command fits best, and why?

3.A teammate writes a script that parses Codex session files directly at `~/.codex/sessions/2026/06/04/rollout-*.jsonl`. Why is this fragile?

4.In a CI pipeline, one job starts a Codex task and a later job needs to continue that exact thread non-interactively. How do you wire this up?

Go deeper

Hand-picked sources to keep learning