Session Management in Codex CLI: Resume, Fork, and JSONL Transcripts
Session Management in Codex CLI: Resume, Fork, and JSONL Transcripts
Most agentic coding sessions are not one-shot affairs. You investigate a bug, break for lunch, then return to fix it. You scaffold a feature in one sitting and write tests in another. Codex CLI’s session management — built on persistent JSONL transcripts, a SQLite metadata index, and first-class resume and fork subcommands — turns ephemeral terminal conversations into durable, branchable work streams. This article covers the storage internals, the commands that operate on them, and the patterns that make multi-session workflows practical.
How Sessions Are Persisted
Every interactive Codex CLI session is automatically persisted as a rollout file — a newline-delimited JSON (JSONL) archive stored under ~/.codex/sessions/[^1]. Files are organised by date:
~/.codex/sessions/
2026/
04/
13/
rollout-2026-04-13T09-41-22-a1b2c3d4.jsonl.zst
rollout-2026-04-13T14-07-55-e5f6g7h8.jsonl.zst
Each line in the rollout file is a serialised RolloutItem, one of three variants[^2]:
| Variant | Purpose |
|---|---|
SessionMeta |
Initial metadata — CWD, model, reasoning effort, Git branch |
EventMsg |
Protocol events: user messages, model responses, tool calls, approvals |
ResponseItem |
Structured model outputs |
This append-only format enables incremental persistence: Codex writes each event as it occurs, so even a session killed with Ctrl+C retains everything up to the last completed turn[^1].
Two-Tier Storage: JSONL + SQLite
Raw rollout files are the source of truth, but Codex also maintains a SQLite metadata index (StateRuntime) for fast queries[^2]. The extract module parses rollout lines on write to populate the index with thread IDs, timestamps, working directories, Git branches, first user messages, and token counts. This two-tier design means the session picker can list hundreds of sessions instantly without scanning JSONL files.
flowchart LR
A[Codex Session] -->|append events| B[JSONL Rollout File]
B -->|extract metadata| C[SQLite Index]
C -->|fast queries| D[Session Picker / /status]
B -->|full replay| E[Resume / Fork]
Thread Identity and Metadata
Every session receives a UUID v7 thread ID at creation[^2]. The ThreadMetadata record captures:
- Source: CLI, VS Code extension, or JetBrains plugin
- Working directory and Git branch at session start
- First user message (used as a preview in the picker)
- Token usage totals
- Custom thread name (if set via PR #10340’s
thread_namefield)[^3]
Thread names surface in the resume picker, replacing the default first-message preview — useful when you have dozens of sessions against the same repository.
Resuming Sessions
The resume subcommand reopens an earlier thread with its full transcript, plan history, and approval state intact[^1].
Command-Line Interface
# Interactive picker — scoped to current working directory
codex resume
# Skip picker, jump to most recent session in this directory
codex resume --last
# Include sessions from all directories
codex resume --all
# Target a specific session by UUID
codex resume 7f9f9a2e-1b3c-4c7a-9b0e-abcdef123456
The --last flag scopes to the current working directory by default. Combine with --all to resume the most recent session regardless of where it was started[^4].
In-Session Slash Command
Within an active session, /resume opens the session picker without exiting Codex[^5]. Select a previous session to switch context immediately — the current session is preserved and can itself be resumed later.
What Gets Restored
The resumption flow replays the rollout file line-by-line through five restoration stages[^2]:
- Metadata restoration — CWD, model provider, reasoning effort settings
- Context restoration — replays
UserMessageevents to reconstruct conversation history - Token tracking — restores cumulative
tokens_usedfromEventMsg::TokenCountentries - Dynamic tools — reloads any tools dynamically registered in the previous session via
get_dynamic_tools(thread_id) - Memory configuration — restores thread-specific memory mode settings
The apply_rollout_item function updates in-memory ThreadMetadata during replay without modifying the persisted rollout file[^2]. This means resuming is non-destructive — the original transcript remains untouched.
The Resume Picker
The resume_picker.rs TUI component provides paginated, sortable session selection[^2][^6]:
| Feature | Detail |
|---|---|
| Pagination | Cursor-based, PAGE_SIZE = 25 |
| Sorting | Toggle between CreatedAt and UpdatedAt timestamps |
| Filtering | Scoped to CWD unless --all is passed |
| Async loading | Non-blocking via BackgroundEvent::PageLoaded |
| Thread names | Displayed when set, falling back to first-message preview |
PR #10752 added the sortable timestamp toggle[^6], and PR #10340 added thread name display[^3] — both merged in early 2026.
Forking Sessions
Where resume continues a session in place, fork creates a new thread branching from an existing one whilst leaving the original untouched[^5].
# Interactive picker
codex fork
# Fork the most recent session
codex fork --last
# Fork a specific session
codex fork 7f9f9a2e-1b3c-4c7a-9b0e-abcdef123456
Fork Mechanics
Forking uses the InitialHistory::Forked variant[^2]:
| Property | Behaviour |
|---|---|
| Thread ID | Fresh UUID v7 |
forked_from_id |
Points to parent thread |
| History | Inherits all turns from parent up to fork point |
| Parent rollout | Remains unmodified |
| Initial status | Interrupted or Idle, ready for new input |
The in-session /fork command clones the current conversation into a new thread with a fresh ID[^5]. For forking saved sessions (not the current one), use the codex fork subcommand from the terminal.
When to Fork vs Resume
flowchart TD
A[Want to continue previous work?] -->|Yes, same direction| B[codex resume]
A -->|Yes, but try alternative approach| C[codex fork]
A -->|No, fresh start| D[codex / /new]
B --> E[Original session updated in place]
C --> F[New session branched, original preserved]
D --> G[Clean session, no history]
Use fork when you want to explore an alternative implementation path without losing the original conversation. The parent session remains available for resumption if the fork turns out to be a dead end.
Non-Interactive Resume: CI/CD Patterns
The codex exec resume subcommand brings session continuity to automated pipelines[^1][^7]:
# Stage 1: analyse
codex exec "Review src/ for race conditions" \
--approval-mode full-auto
# Stage 2: fix (resumes the analysis session)
codex exec resume --last "Fix the race conditions you found"
Each resumed exec run preserves the original transcript, plan history, and approvals[^1]. This enables multi-stage CI pipelines where context accumulates across steps rather than being repeated.
A practical three-stage pattern:
# 1. Analyse
codex exec "Audit the authentication module for security issues"
# 2. Fix
codex exec resume --last "Implement fixes for the issues you identified"
# 3. Verify
codex exec resume --last "Write tests proving the fixes work, then run them"
Managing Long Sessions with /compact
Sessions that run for extended periods — Codex supports continuous operation for up to seven hours[^1] — inevitably approach context limits. The /compact slash command replaces earlier turns with a concise summary, freeing tokens whilst preserving critical decisions[^5].
/compact
Codex also compacts automatically when approaching context boundaries, but explicit compaction gives you control over when summarisation happens. Run /compact before switching to a new phase of work to ensure maximum context headroom for the next task.
Session Lifecycle Slash Commands
A complete reference for session-related commands[^5]:
| Command | Purpose |
|---|---|
/resume |
Open session picker, switch to a saved session |
/fork |
Clone current conversation into a new thread |
/new |
Start fresh conversation without leaving the terminal |
/compact |
Summarise history to free context tokens |
/status |
Show session ID, model, token usage, context utilisation |
Practical Patterns
Pattern 1: Investigation → Fix Across Sessions
# Morning: investigate
codex
> Analyse the failing integration tests in tests/api/ and identify root causes
# Afternoon: resume and fix
codex resume --last
> Fix the issues you identified this morning, starting with the auth timeout
Pattern 2: Parallel Exploration via Fork
# Start with a shared analysis
codex
> Review the payment module architecture and suggest two refactoring approaches
# Fork to try approach A
codex fork --last
> Implement approach A: extract PaymentProcessor into a separate service
# In another terminal, fork the original to try approach B
codex fork <original-session-id>
> Implement approach B: introduce the Strategy pattern for payment methods
Pattern 3: Session-Aware CI with GitHub Actions
- name: Analyse changes
run: |
codex exec "Review the PR diff for bugs and style issues" \
--approval-mode full-auto
- name: Apply fixes
run: |
codex exec resume --last "Fix all issues you found" \
--approval-mode full-auto
Known Limitations
- No cross-machine sync: sessions live in
~/.codex/sessions/on the local filesystem. Remote sessions via--remotemaintain their own storage on the server side[^4]. - No session search by content: the picker filters by CWD and sorts by timestamp, but there is no full-text search across transcript content. ⚠️ Thread names (PR #10340) partially mitigate this, but a dedicated search command is not yet available.
- Compaction is lossy:
/compactsummarises earlier turns irreversibly. If you need the full history, fork before compacting. - App re-enablement bug: PR #13533 (merged March 2026) fixed an issue where apps were not re-enabled after
codex resume[^8] — ensure you are on v0.119.0 or later.
Citations
| [^1]: [Features – Codex CLI | OpenAI Developers](https://developers.openai.com/codex/cli/features) | |
| [^2]: [Session Resumption and Forking | openai/codex | DeepWiki](https://deepwiki.com/openai/codex/4.4-session-resumption-and-forking) |
| [^3]: [Session picker shows thread_name if set — PR #10340 | openai/codex](https://github.com/openai/codex/pull/10340) | |
| [^4]: [Command line options – Codex CLI | OpenAI Developers](https://developers.openai.com/codex/cli/reference) | |
| [^5]: [Slash commands in Codex CLI | OpenAI Developers](https://developers.openai.com/codex/cli/slash-commands) | |
| [^6]: [feat(tui): add sortable resume picker with created/updated timestamp toggle — PR #10752 | openai/codex](https://github.com/openai/codex/pull/10752) | |
| [^7]: [Non-interactive mode – Codex | OpenAI Developers](https://developers.openai.com/codex/noninteractive) | |
| [^8]: [[apps] Fix the issue where apps is not enabled after codex resume — PR #13533 | openai/codex](https://github.com/openai/codex/pull/13533) |