# How the Codex Plugin Implements Progress Reporting for Long-Running Operations

> Learn how the Codex plugin implements progress reporting for long-running operations. It captures SDK events, logs them, and provides live previews via the codex status command.

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

---

**The Codex plugin implements progress reporting by creating a progress reporter callback that captures SDK-level events, writes them to a log file, and exposes a live preview via the `/codex:status` command.**

The `openai/codex-plugin-cc` repository provides a lightweight, log-driven mechanism for tracking long-running Codex tasks. By normalizing incremental events and storing them in a persistent log, the plugin enables users to monitor job status without polling internal state manually.

## Creating the Progress Reporter

### The createProgressReporter Function

Progress tracking begins with the `createProgressReporter` function in `plugins/codex/scripts/lib/tracked-jobs.mjs`. This factory builds a callback that normalizes each incoming event, optionally echoes messages to `stderr`, appends them to a designated log file, and forwards the event to an optional `onEvent` hook.

The reporter configuration accepts three key parameters:
- **`stderr`** – When `true`, echoes progress messages to the console
- **`logFile`** – Path to the file where events are persisted
- **`onEvent`** – Optional callback for custom event handling

```javascript
// Creating a progress reporter when launching a job
import { createProgressReporter, runTrackedJob } from './lib/tracked-jobs.mjs';

const progress = createProgressReporter({
  stderr: true,          // also echo to console
  logFile: '/tmp/job.log',
  onEvent: (ev) => console.log('Progress event:', ev)
});

await runTrackedJob(job, () => runner(progress), { logFile: '/tmp/job.log' });

```

## Running the Job with Progress Tracking

### Integrating with runTrackedJob

The reporter instance is passed to the Codex runtime through `runTrackedJob`, ensuring every SDK-level progress event is captured during execution. This integration happens in `plugins/codex/scripts/codex-companion.mjs` (lines 580-660), where the plugin wires the reporter to the running Codex job.

The `runTrackedJob` function accepts the job definition, a runner function that receives the progress callback, and options specifying the log file path. This architecture decouples the progress collection from the job execution logic while maintaining a continuous stream of status updates.

## Storing and Reading Progress Previews

### The readJobProgressPreview Function

While the job runs, the plugin periodically reads the log file using `readJobProgressPreview` from `plugins/codex/scripts/lib/job-control.mjs`. This function extracts the most recent lines and stores them in `job.progressPreview`, creating a window into the current activity without loading the entire log history.

```javascript
// Manually reading the preview (what the renderer does)
import { readJobProgressPreview } from './lib/job-control.mjs';

const preview = readJobProgressPreview('/tmp/job.log', 10);
preview.forEach(line => console.log('▶', line));

```

The function accepts the log file path and a line count limit, returning an array of the most recent progress entries. This preview is updated throughout the job lifecycle, providing near real-time visibility into long-running operations.

## Inferring Job Phases

### Legacy Phase Detection with inferLegacyJobPhase

For legacy jobs, the plugin analyzes preview lines using `inferLegacyJobPhase` (defined in `plugins/codex/scripts/lib/job-control.mjs`, lines 9-20). This heuristic examines log content to guess the current phase—such as **starting**, **investigating**, **verifying**, **editing**, or **finalizing**—based on patterns in the progress output.

This inference layer allows older Codex tasks to participate in the progress reporting system without requiring explicit phase annotations from the SDK.

## Rendering Progress to the User

### The /codex:status Command Implementation

When users run `/codex:status`, the `render` function in `plugins/codex/scripts/lib/render.mjs` (lines 158-162) displays the progress preview under a "Progress:" heading. The rendering process uses `buildStatusSnapshot` to aggregate job data, including the preview lines, before formatting them for the terminal.

```javascript
// How the status command shows the preview
import { buildStatusSnapshot } from './lib/job-control.mjs';
import { render } from './lib/render.mjs';

const snapshot = buildStatusSnapshot(process.cwd(), { maxProgressLines: 5 });
console.log(render(snapshot));

```

The `maxProgressLines` option controls how many recent log entries appear in the status output, keeping the display concise while providing sufficient context for understanding current job activity.

## Summary

The Codex plugin progress reporting system combines several components to provide lightweight, real-time feedback:

- **Event Capture**: The `createProgressReporter` function in `plugins/codex/scripts/lib/tracked-jobs.mjs` builds callbacks that normalize and persist SDK events
- **Log Persistence**: All progress events append to a dedicated log file, creating a durable history of job execution
- **Preview Generation**: `readJobProgressPreview` extracts recent lines from the log to populate `job.progressPreview`
- **Phase Inference**: `inferLegacyJobPhase` analyzes log patterns to determine the current job phase for legacy tasks
- **Status Rendering**: The `render` function in `plugins/codex/scripts/lib/render.mjs` displays the preview when users invoke `/codex:status`

## Frequently Asked Questions

### How does the Codex plugin handle progress events from the SDK?

The plugin intercepts SDK-level progress events through a reporter callback created by `createProgressReporter`. This callback normalizes each event, writes it to a log file, optionally echoes it to `stderr`, and forwards it to any custom `onEvent` hook. The reporter is passed directly to the Codex runtime via `runTrackedJob`, ensuring all progress updates are captured during execution.

### Where does the plugin store progress information during job execution?

Progress information is stored in two locations: a persistent log file specified during reporter creation (typically `/tmp/job.log` or similar) and the `job.progressPreview` property. The `readJobProgressPreview` function periodically reads the log file and updates the preview array with the most recent lines, allowing the status command to display current activity without reading the entire log history.

### Can I customize how progress events are processed or displayed?

Yes. The `createProgressReporter` function accepts an `onEvent` callback parameter that receives every normalized event before it is written to the log. You can implement custom filtering, transformation, or external notification logic in this hook. Additionally, when calling `buildStatusSnapshot`, you can specify `maxProgressLines` to control how many log entries appear in the `/codex:status` output.

### How does the plugin determine which phase a legacy job is currently in?

The `inferLegacyJobPhase` function in `plugins/codex/scripts/lib/job-control.mjs` analyzes the content of `job.progressPreview` lines to heuristically determine the current phase. It looks for patterns indicating specific stages—such as "starting," "investigating," "verifying," "editing," or "finalizing"—allowing older Codex tasks to report meaningful progress status without native phase support from the SDK.