# Lifecycle of a Codex Task Execution in the OpenAI Codex Plugin

> Explore the 6 stages of a Codex task execution lifecycle managed by the openai/codex-plugin-cc. Learn how jobs progress from creation to UI query using a state store.

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

---

**The openai/codex-plugin-cc manages every unit of work as a durable job that progresses through six distinct stages—creation, state preparation, execution, result persistence, cleanup, and UI query—using a JSON-based state store with automatic pruning to maintain a tiny disk footprint.**

The openai/codex-plugin-cc treats every Codex operation as a persistent job that survives process restarts and session changes. When you invoke commands like `codex review` or `codex result`, the plugin initiates a strict lifecycle that coordinates state management, process execution, and automatic retention policies. Understanding this lifecycle reveals how the plugin maintains durability while keeping resource usage minimal through deterministic state directories and deterministic job identifiers.

## Stage 1: Job Creation and ID Generation

When a user triggers a Codex command, the command handler immediately calls `generateJobId()` to produce a unique identifier based on the job type. The handler then creates an initial job record via `upsertJob()` in `plugins/codex/scripts/lib/state.mjs`, setting the status to **`pending`** and recording timestamps alongside the request payload.

This initial persistence ensures that even if the process crashes milliseconds later, the job intent is recoverable from disk.

## Stage 2: State Directory Preparation

Before executing any code, the plugin establishes where state lives on the filesystem. The `resolveStateDir()` function computes a deterministic path derived from the workspace root and the optional `CLAUDE_PLUGIN_DATA` environment variable. The `ensureStateDir()` helper then creates the directory structure, including [`state.json`](https://github.com/openai/codex-plugin-cc/blob/main/state.json) and a `jobs/` subfolder, if they do not exist.

This approach guarantees that every execution context maps to exactly one state location, enabling consistent recovery across sessions.

## Stage 3: Job Execution and Process Management

Execution control transfers to `plugins/codex/scripts/lib/process.mjs`, which spawns a child process or invokes the Codex API. The process manager streams stdout and stderr to a dedicated log file resolved by `resolveJobLogFile()`, while concurrently updating the job status from **`running`** to **`completed`** or **`failed`** via `upsertJob()`.

The broker endpoint (`broker-endpoint.mjs`) coordinates these HTTP requests from the Codex companion, routing them to the appropriate job instance managed by the process layer.

## Stage 4: Result Persistence and Automatic Pruning

Upon successful completion, `writeJobFile()` serializes the result payload to a JSON file within the jobs directory. The plugin then enforces storage limits through `pruneJobs()`, which sorts the job list by `updatedAt` and retains only the most recent **MAX_JOBS** entries (default 50). For each pruned job, the system calls `removeJobFile()` and `removeFileIfExists()` to delete obsolete JSON files and logs, then commits the updated index via `saveState()`.

This pruning ensures the disk footprint remains tiny regardless of how many tasks execute over time.

## Stage 5: State Cleanup and Deletion

When jobs are explicitly deleted or superseded by newer operations, the plugin removes the corresponding files from the `jobs/` directory and rewrites [`state.json`](https://github.com/openai/codex-plugin-cc/blob/main/state.json) to exclude the deleted entries. This cleanup maintains referential integrity between the central state file and the on-disk job artifacts.

## Stage 6: Query and UI Reflection

Read-only UI commands such as `codex status` and `codex list` invoke `listJobs()` or `getConfig()` from `state.mjs` to query the current persisted state. The UI layer strictly observes separation of concerns—it reads the JSON store without modifying it, ensuring that display logic cannot corrupt execution history.

## Practical Implementation Example

```javascript
import {
  generateJobId,
  upsertJob,
  listJobs,
  writeJobFile,
  resolveJobLogFile,
} from "./plugins/codex/scripts/lib/state.mjs";

// 1️⃣ Create a new job
const jobId = generateJobId("review");
await upsertJob(process.cwd(), {
  id: jobId,
  type: "review",
  status: "pending",
  payload: { files: ["src/index.ts"] },
});

// 2️⃣ Run the job with logging
import { runTask } from "./plugins/codex/scripts/lib/process.mjs";
await runTask(process.cwd(), jobId, async (logStream) => {
  const result = await callCodexApi(jobId);
  await writeJobFile(process.cwd(), jobId, { result });
  logStream.write(JSON.stringify(result));
});

// 3️⃣ Query current jobs
const jobs = await listJobs(process.cwd());
console.table(jobs.map(j => ({ id: j.id, status: j.status, updatedAt: j.updatedAt })));

```

## Key Implementation Files

The lifecycle is implemented across these modules:

- **`plugins/codex/scripts/lib/state.mjs`**: Central state store handling `generateJobId`, `upsertJob`, `pruneJobs`, and directory resolution.
- **`plugins/codex/scripts/lib/process.mjs`**: Process orchestration, log streaming via `resolveJobLogFile`, and status updates during execution.
- **`plugins/codex/scripts/lib/job-control.mjs`**: Helper functions for cancelling, rescuing, and cleaning jobs outside the standard flow.
- **`plugins/codex/scripts/lib/broker-endpoint.mjs`**: HTTP broker that maps incoming Codex companion requests to state-managed job instances.
- **`plugins/codex/scripts/session-lifecycle-hook.mjs`**: Initializes per-session caches while preserving on-disk durability across restarts.
- **`plugins/codex/scripts/lib/workspace.mjs`**: Determines the workspace root used for state directory resolution.

## Summary

- The lifecycle begins with **`generateJobId()`** and **`upsertJob()`** atomically creating a `pending` record in [`state.json`](https://github.com/openai/codex-plugin-cc/blob/main/state.json).
- The plugin uses **`resolveStateDir()`** to establish a deterministic storage location based on workspace root and environment variables.
- **`process.mjs`** handles execution, streaming logs to per-job files while transitioning status via **`upsertJob()`**.
- Results are persisted with **`writeJobFile()`**, and **`pruneJobs()`** enforces the 50-job retention limit by `updatedAt` timestamp.
- UI commands read from the JSON store using **`listJobs()`** and **`getConfig()`** without acquiring write locks.
- Session lifecycle hooks ensure durable state survives while in-memory caches refresh per session.

## Frequently Asked Questions

### Where does the plugin store job state on disk?

The plugin resolves a state directory via **`resolveStateDir()`** in `state.mjs`, which combines the workspace root with the optional `CLAUDE_PLUGIN_DATA` environment variable. Within this directory, it maintains [`state.json`](https://github.com/openai/codex-plugin-cc/blob/main/state.json) as the canonical job index and stores individual job payloads and logs in a `jobs/` subfolder.

### What happens when the job limit is reached?

When the job count exceeds **MAX_JOBS** (default 50), the **`pruneJobs()`** function sorts the job array by `updatedAt` in descending order, retains only the newest 50 entries, and deletes obsolete files via **`removeJobFile()`** and **`removeFileIfExists()`**. It then atomically rewrites [`state.json`](https://github.com/openai/codex-plugin-cc/blob/main/state.json) via **`saveState()`** to reflect the pruned set.

### How does the plugin handle job failures?

During execution in `process.mjs`, the process manager captures non-zero exit codes and unhandled exceptions. It updates the job status to **`failed`** via **`upsertJob()`** and appends error details to the log stream. The broker can then serve these failure states to the UI without re-triggering execution, as the persisted state remains the source of truth.

### Can multiple sessions access the same job state concurrently?

Yes. The **`session-lifecycle-hook.mjs`** initializes each new session with a clean in-memory cache while treating the on-disk [`state.json`](https://github.com/openai/codex-plugin-cc/blob/main/state.json) as the durable source of truth. This architecture allows multiple Codex companion sessions to query job history and status through the broker endpoint without conflicts, as all writes serialize through the state management functions in `state.mjs`.