# How Thread Persistence and Resume Functionality Work in Codex: A Deep Dive

> Learn how Codex thread persistence and resume functionality keep long running tasks alive across CLI invocations. Resume your Codex tasks effortlessly.

- Repository: [OpenAI/codex-plugin-cc](https://github.com/openai/codex-plugin-cc)
- Tags: deep-dive
- Published: 2026-08-05

---

**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`.

```javascript
// 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`.

```javascript
// 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:

```javascript
// 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

```bash

# 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

```bash

# 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

```bash

# 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.