How Thread Persistence and Resume Functionality Work in Codex: A Deep Dive
Codex's thread persistence lets you start a long-running task, keep the thread alive across multiple CLI invocations, and resume exactly where you left off using --resume-last or the codex resume <thread-id> command.
The openai/codex-plugin-cc repository implements a durable conversational state that survives CLI restarts. This guide breaks down how persistent threads are created, resumed, and surfaced to users through embedded commands in every output.
Starting a Persistent Thread
When you run a Codex task with persistence enabled, the CLI invokes runAppServerTurn with persistThread: true. This flag propagates through the companion script in codex-companion.mjs and triggers the startThread helper in codex.mjs.
The critical distinction is the ephemeral flag: when persistThread is true, ephemeral is set to false, instructing the Codex server to store the thread rather than discard it after the turn. A thread name is generated or supplied and saved via thread/name/set.
// codex.mjs – start a thread
const response = await client.request("thread/start", buildThreadParams(cwd, {
model,
sandbox,
// persistThread ? false : true → non‑ephemeral when persisting
ephemeral: options.persistThread ? false : true,
threadName: options.persistThread ? options.threadName : options.threadName ?? null
}));
This non-ephemeral thread now lives server-side, independent of your local CLI process.
Resuming a Saved Thread
Thread resume functionality operates through two primary paths: automatic resolution of the latest thread or explicit thread ID specification.
Automatic Resume with --resume-last
When you pass --resume-last (or --resume), the companion script calls resolveLatestTrackedTaskThread to look up the most recent tracked task. It extracts the threadId and passes it as resumeThreadId to runAppServerTurn, which detects this option and delegates to resumeThread.
// codex.mjs – resume a thread
async function resumeThread(client, threadId, cwd, options = {}) {
return client.request("thread/resume", buildResumeParams(threadId, cwd, options));
}
The buildResumeParams function constructs the payload for the thread/resume request, re-establishing the conversation context on the server.
Manual Resume with Thread ID
Every persistent task output includes its threadId, enabling precise manual resumption. Copy the printed command and run it later—the codex resume <thread-id> subcommand re-enters the exact thread state.
Embedding Resume Commands in Output
The resume experience is reinforced through output rendering. Every result type—task completion, review, or stored job—appends a resume command line constructed in render.mjs.
The rendering helpers compute:
// render.mjs – add resume command to output
const threadId = storedJob?.threadId ?? job.threadId ?? null;
const resumeCommand = threadId ? `codex resume ${threadId}` : null;
...
lines.push(`Codex session ID: ${threadId}`);
lines.push(`Resume in Codex: ${resumeCommand}`);
This ensures thread persistence is discoverable and actionable: users never lose track of how to return to a conversation.
CLI Usage Patterns
Start a Persistent Task
# Creates a non-ephemeral thread and prints resume information
codex task --write "Add a logging helper to the project"
Sample output:
Codex session ID: thr_abc123
Resume in Codex: codex resume thr_abc123
Resume the Latest Task Automatically
# Auto-detects most recent thread, resumes it, and runs new prompt
codex task --resume-last "Refactor the logger to use async I/O"
Manual Resume Later
# Re-enters the exact thread from step 1
codex resume thr_abc123
Key Implementation Files
| File | Responsibility |
|---|---|
plugins/codex/scripts/lib/codex.mjs |
Core thread lifecycle: startThread, resumeThread, buildResumeParams, ephemeral flag handling |
plugins/codex/scripts/lib/render.mjs |
Resume command generation in output formatting |
plugins/codex/scripts/codex-companion.mjs |
CLI parsing for --resume-last, task metadata construction, persistThread propagation |
tests/runtime.test.mjs |
Workflow validation for resume operations |
Summary
- Persistent threads are created by setting
ephemeral: falsewhenpersistThread: true, storing state server-side. - Resume paths include automatic resolution (
--resume-last) or explicit thread ID (codex resume <id>). - Discoverability is guaranteed through embedded
Resume in Codexcommands in every output. - State continuity is maintained across CLI restarts via
thread/resumerequests built bybuildResumeParams.
Frequently Asked Questions
What happens if I don't use --write or persistThread?
Without persistThread: true, threads default to ephemeral and are discarded after the turn completes. You cannot resume an ephemeral thread because it was never stored on the Codex server. The ephemeral: true flag in buildThreadParams controls this behavior directly.
How does Codex track which thread is "latest"?
The companion script maintains task metadata through resolveLatestTrackedTaskThread in codex-companion.mjs. This function queries the local tracking state to identify the most recently created or resumed persistent thread, returning its id for automatic resumption.
Can I rename a persistent thread after creation?
Yes. The thread/name/set request is issued during thread creation (startThread), and custom names can be supplied via --thread-name. While the provided code focuses on initial naming, the thread persistence model supports name updates through standard Codex API operations.
Is there a limit to how long threads remain resumeable?
Thread lifetime is governed by the Codex server retention policy, not the CLI. The openai/codex-plugin-cc implementation makes no expiration assumptions—resume commands remain valid as long as the server retains the thread state. Check your Codex service tier for specific retention limits.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →