# How Codex Job Results Are Stored and Retrieved in openai/codex-plugin-cc

> Learn how the openai/codex-plugin-cc stores Codex job results as JSON files, indexed by state.json, and retrieves them using a two-step lookup for efficient access.

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

---

**Codex job results are persisted as JSON files in a per-repository state directory, indexed by a central [`state.json`](https://github.com/openai/codex-plugin-cc/blob/main/state.json) manifest, and retrieved via a two-step lookup that resolves the job ID against the manifest before loading the full payload.**

When a Codex command such as `review`, `task`, or `transfer` completes in the openai/codex-plugin-cc repository, the companion script creates a durable job record that enables post-execution analysis and auditing. Understanding how Codex job results are stored and retrieved is essential for building integrations that consume Codex outputs programmatically or inspect historical runs via the CLI.

## State Directory Structure and Location

### Resolving the State Directory

The storage location is determined by `state.resolveStateDir()` in `plugins/codex/scripts/lib/state.mjs`. This function constructs a path from the repository root, a hash of that path, and either the `CLAUDE_PLUGIN_DATA` environment variable or a fallback temporary directory at `/tmp/codex-companion`.

### File Layout and Persistence

Within the state directory, the system maintains a `jobs/` subdirectory containing paired files for each execution:

- `<job-id>.json` — Stores the full JSON payload including the raw result, rendered markdown, timestamps, and execution metadata. Written by `state.writeJobFile()`.
- `<job-id>.log` — Contains plain-text progress lines captured during execution, created by `tracked-jobs.createJobLogFile()`.

A top-level [`state.json`](https://github.com/openai/codex-plugin-cc/blob/main/state.json) file acts as a manifest, maintaining a rolling array of the most recent jobs (default maximum of 50 entries) with lightweight metadata for `status` and `cancel` commands.

## Job Record Creation and Storage

### Writing the Job File

When `tracked-jobs.runTrackedJob()` executes, it creates an initial running record and persists it via `writeJobFile()`. After the Codex process terminates, the companion updates the file with the final state:

```ts
// After the Codex runner finishes (tracked-jobs.mjs)
writeJobFile(job.workspaceRoot, job.id, {
  ...runningRecord,
  status: completionStatus,
  threadId: execution.threadId,
  turnId: execution.turnId,
  phase: completionStatus === "completed" ? "done" : "failed",
  completedAt,
  result: execution.payload,      // Full Codex output
  rendered: execution.rendered,   // Markdown version
});

```

### Updating the State Manifest

Simultaneously, `state.upsertJob()` updates [`state.json`](https://github.com/openai/codex-plugin-cc/blob/main/state.json) to include the job's metadata (ID, status, timestamps), ensuring the `status` command can list recent jobs without parsing individual JSON files.

## Retrieving Stored Results

### The Result Sub-Command Flow

The `result` sub-command in `codex-companion.mjs` (around line 1055) implements a two-stage retrieval process:

```ts
const { workspaceRoot, job } = resolveResultJob(cwd, reference);
const storedJob = readStoredJob(workspaceRoot, job.id);

```

- `resolveResultJob()` (in `job-control.mjs`) selects a finished job (status of `completed`, `failed`, or `cancelled`) by ID or prefix match.
- `readStoredJob()` loads the `<job-id>.json` file from the state directory.

### Rendering and Presentation

For human consumption, `renderStoredJobResult()` in `render.mjs` formats the stored payload into a readable view containing the verdict, summary, findings, artifacts, and follow-up commands. For programmatic access, the `--json` flag returns the raw payload directly.

## Programmatic Access Patterns

### Fetching Results via CLI

To retrieve a specific job from the terminal:

```bash

# Display formatted result

codex result task-abc123

# Get raw JSON payload

codex result task-abc123 --json

```

### Accessing Results via Node.js API

For integration with other tools, import the state and job-control modules:

```ts
import { resolveJobFile, readJobFile } from "./lib/state.mjs";
import { resolveResultJob } from "./lib/job-control.mjs";

async function getJobResult(cwd, jobId) {
  const { workspaceRoot, job } = resolveResultJob(cwd, jobId);
  const resultPath = resolveJobFile(workspaceRoot, job.id);
  const payload = readJobFile(resultPath); // Contains `result` and `rendered`
  return payload;
}

```

## Key Source Files and Responsibilities

- **`state.mjs`** — Handles state directory resolution, [`state.json`](https://github.com/openai/codex-plugin-cc/blob/main/state.json) manifest management, and per-job file I/O (`writeJobFile`, `readJobFile`).
- **`tracked-jobs.mjs`** — Orchestrates job lifecycle, creates log files, and persists final results via `writeJobFile()`.
- **`job-control.mjs`** — Provides `resolveResultJob()` for job selection and `readStoredJob()` for file retrieval.
- **`render.mjs`** — Transforms stored JSON into human-readable output via `renderStoredJobResult()`.
- **`codex-companion.mjs`** — CLI entry point that wires the `result` command to the storage subsystem.

## Summary

- Codex job results are stored as JSON files in a repository-specific state directory under `<state-dir>/jobs/<job-id>.json`.
- A [`state.json`](https://github.com/openai/codex-plugin-cc/blob/main/state.json) manifest tracks the most recent 50 jobs for quick listing and status checks.
- Each job includes a companion `.log` file containing execution progress.
- Retrieval requires resolving the job ID against the manifest, then loading the specific JSON payload via `readStoredJob()`.
- Results can be rendered as formatted markdown or exported as raw JSON using the `--json` flag.

## Frequently Asked Questions

### Where are Codex job results physically stored?

The companion script writes results to a directory resolved by `state.resolveStateDir()` in `plugins/codex/scripts/lib/state.mjs`. This location combines the repository root path hash with the `CLAUDE_PLUGIN_DATA` environment variable or falls back to `/tmp/codex-companion`, creating a `jobs/` subdirectory containing `<job-id>.json` and `<job-id>.log` files.

### How long are job results retained?

The system maintains a rolling window of the most recent 50 jobs in [`state.json`](https://github.com/openai/codex-plugin-cc/blob/main/state.json) for quick reference, but the individual JSON and log files in the `jobs/` directory persist indefinitely until manually deleted or the state directory is cleared.

### Can I retrieve a job result using only a partial ID?

Yes. The `resolveResultJob()` function in `job-control.mjs` accepts job ID prefixes and resolves them to full IDs, provided the prefix uniquely identifies a finished job (completed, failed, or cancelled).

### What is the difference between the `result` and `rendered` fields in the stored JSON?

The `result` field contains the raw, structured payload returned by the Codex model, while the `rendered` field contains a pre-formatted markdown representation suitable for terminal display without additional processing.