# How Thread Persistence and Naming Work in OpenAI Codex Companion

> Understand thread persistence and naming in OpenAI Codex Companion. Learn how it saves your IDE sessions to JSON files for seamless continuation.

- Repository: [OpenAI/codex-plugin-cc](https://github.com/openai/codex-plugin-cc)
- Tags: internals
- Published: 2026-07-04

---

**TLDR:** The OpenAI Codex Companion persists conversation threads to a JSON file in a hashed workspace directory, allowing users to resume sessions after closing the IDE.

The openai/codex-plugin-cc repository implements a lightweight thread persistence system that tracks every interaction in durable storage. This architecture enables developers to pause coding sessions, close their IDE, and resume conversations exactly where they left off. Understanding how **thread persistence and naming** function reveals the mechanisms behind session continuity and thread management.

## Where Threads Are Stored

All thread information is stored in a JSON file called **[`state.json`](https://github.com/openai/codex-plugin-cc/blob/main/state.json)** inside a per-workspace state directory. The system resolves this directory through the **`resolveStateDir(cwd)`** function defined in **`plugins/codex/scripts/lib/state.mjs`**.

This function hashes the workspace root to create a unique path:

```text
/tmp/codex-companion/<workspace‑slug>-<hash>/state.json

```

On process startup, **`loadState`** reads this file. If the file is missing or corrupted, the system falls back to an empty **`defaultState`**. The state file is written atomically using `fs.writeFileSync` each time a thread is modified, ensuring data integrity even if the process terminates unexpectedly.

## Thread Data Structure

The `threads` array in [`state.json`](https://github.com/openai/codex-plugin-cc/blob/main/state.json) contains thread objects with specific properties:

- **`id`** – Unique thread identifier (e.g., `thr_1`).
- **`name`** – Optional human-readable name set via the `thread/name/set` command.
- **`preview`** – Short excerpt of the first user message for UI lists.
- **`ephemeral`** – Boolean flag for temporary threads that are not persisted across sessions.
- **`createdAt`** and **`updatedAt`** – ISO timestamps for ordering and tracking.
- **`cwd`** – The working directory associated with the thread.
- **`visibleMessages`** – Array of messages displayed in the UI.

The array is maintained in sorted order by `updatedAt` (newest first), enabling O(1) access to the latest thread.

## Creating a New Thread

When a client sends a **`thread/start`** request, the handler in **`plugins/codex/scripts/lib/render.mjs`** executes the **`nextThread`** function. This generates a fresh ID (`thr_<counter>`), timestamps the creation, and pushes the new thread onto `state.threads`.

The implementation immediately persists the change through `updateState` → `saveState`:

```javascript
case "thread/start": {
  const thread = nextThread(state, message.params.cwd, message.params.ephemeral);
  // ... reply with buildThread(thread) ...
  send({ method: "thread/started", params: { thread: { id: thread.id } } });
}

```

### Starting a Thread Example

```javascript
await codex.send({
  method: "thread/start",
  params: { cwd: process.cwd(), ephemeral: false, model: "gpt-5.4" }
});
// Returns: { thread: { id: "thr_1", ... } }

```

## Naming Threads

Thread names are mutable and persisted across sessions. The client issues a **`thread/name/set`** request to update the display name:

```javascript
case "thread/name/set": {
  const thread = ensureThread(state, message.params.threadId);
  thread.name = message.params.name;       // Persisted name
  thread.updatedAt = now();
  // ... reply with updated thread ...
}

```

The **`ensureThread`** function validates that the thread ID exists, throwing an `unknown thread` error if not found. After assignment, the system saves the entire state back to disk.

### Setting a Thread Name Example

```javascript
await codex.send({
  method: "thread/name/set",
  params: { threadId: "thr_1", name: "Feature X Refactor" }
});
// thread.name is now persisted in state.json

```

## Listing and Resuming Threads

The system provides two primary methods for thread retrieval:

**`thread/list`** filters threads by `cwd` and optional search terms, returning the array sorted by `updatedAt`. This powers the "Recent threads" UI view.

**`thread/resume`** looks up a thread by ID, updates its timestamp to the current time, and returns the full thread object including `visibleMessages`. The client can then replay these messages to reconstruct the conversation state.

### Listing and Resuming Examples

```javascript
// List recent threads
const { data: threads } = await codex.send({
  method: "thread/list",
  params: { cwd: process.cwd(), searchTerm: "" }
});
// Returns array ordered by updatedAt

// Resume a specific thread
await codex.send({
  method: "thread/resume",
  params: { threadId: "thr_1", model: "gpt-5.4" }
});
// Returns full thread object with visibleMessages

```

## Persistence Guarantees and Limits

The persistence layer guarantees atomic writes through synchronous file operations. While **`pruneJobs`** maintains a maximum of **50** job files, thread entries have no hard limit—they persist indefinitely until explicitly deleted by the user.

Ephemeral threads (those with `ephemeral: true`) bypass persistence and are discarded when the session ends, making them suitable for temporary design challenges or throwaway experiments.

## Summary

- Threads are stored in **[`state.json`](https://github.com/openai/codex-plugin-cc/blob/main/state.json)** within a hashed workspace directory resolved by `resolveStateDir` in `plugins/codex/scripts/lib/state.mjs`.
- The **`thread/start`** command in `render.mjs` initializes new threads with unique IDs and timestamps.
- **`thread/name/set`** updates human-readable names through `ensureThread` validation and immediate disk persistence.
- **`thread/list`** and **`thread/resume`** provide filtered retrieval and session continuity by managing `visibleMessages`.
- All state changes are written atomically using `fs.writeFileSync`, ensuring durability across process restarts.

## Frequently Asked Questions

### Where is thread data physically stored?

Thread data is stored in a JSON file named [`state.json`](https://github.com/openai/codex-plugin-cc/blob/main/state.json) located at `/tmp/codex-companion/<workspace-slug>-<hash>/state.json`. The exact path is determined by hashing the workspace root directory via `resolveStateDir` in `plugins/codex/scripts/lib/state.mjs`.

### How do I rename an existing thread?

Send a `thread/name/set` request with the thread ID and desired name. The system validates the ID through `ensureThread` and immediately persists the change to [`state.json`](https://github.com/openai/codex-plugin-cc/blob/main/state.json), making the name available across IDE restarts.

### What is the difference between ephemeral and persistent threads?

Persistent threads are saved to disk and available after restarting the IDE. Ephemeral threads (created with `ephemeral: true`) exist only in memory and are discarded when the session ends, making them ideal for temporary experiments.

### Is there a limit to how many threads can be saved?

Thread entries have no hard limit in the state file. However, the system prunes job files to a maximum of 50 through `pruneJobs`. Threads persist until explicitly deleted by the user, regardless of age.