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: false when persistThread: 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 Codex commands in every output.
  • State continuity is maintained across CLI restarts via thread/resume requests built by buildResumeParams.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →