# How the Codex Plugin Handles Progress Reporting for Long-Running Tasks

> Discover how the Codex plugin reports progress for long-running tasks. Learn about its incremental SDK event capture, logging, and status command for real-time updates.

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

---

**The Codex plugin creates a progress reporter that captures incremental SDK events, writes them to a log file and optionally stderr, then surfaces the most recent lines when users run the status command.**

The `openai/codex-plugin-cc` repository implements a lightweight, log-driven progress reporting system for long-running Codex tasks. Instead of requiring complex state polling or in-memory tracking, the plugin persists progress events to the filesystem and infers job phases from log content. This design ensures users receive real-time feedback even during extended operations.

## Creating the Progress Reporter

When a job starts, the `createProgressReporter` function in `plugins/codex/scripts/lib/tracked-jobs.mjs` constructs a callback that normalizes incoming events. The reporter supports three output channels: it can echo messages to stderr, append them to a designated log file, and forward events to an optional `onEvent` hook for custom processing.

The reporter accepts a configuration object controlling verbosity and destination:

```javascript
import { createProgressReporter, runTrackedJob } from './lib/tracked-jobs.mjs';

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

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

```

## Capturing Events During Execution

The reporter integrates with the Codex runtime through `runTrackedJob`, which passes the callback directly to the SDK-level task runner. Every progress event emitted by the Codex engine triggers the reporter, ensuring no incremental updates are lost. The wiring occurs in `plugins/codex/scripts/codex-companion.mjs`, where the plugin initializes the reporter before spawning the job process.

This architecture decouples the progress consumer from the execution context. Because events write immediately to disk, the system remains resilient to crashes or disconnections—the log file serves as the persistent source of truth.

## Storing Progress Previews and Inferring Phases

While the job executes, the plugin periodically reads the log file via `readJobProgressPreview` in `plugins/codex/scripts/lib/job-control.mjs`. This function extracts the most recent lines and stores them in `job.progressPreview` for quick access.

For legacy job formats, the plugin analyzes preview content using `inferLegacyJobPhase` to determine the current operational phase. The function examines log line patterns to classify status as **starting**, **investigating**, **verifying**, **editing**, or **finalizing**:

```javascript
import { readJobProgressPreview } from './lib/job-control.mjs';

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

```

## Rendering Status to Users

When users execute `/codex:status`, the `render` function in `plugins/codex/scripts/lib/render.mjs` formats the progress preview under a "Progress:" heading. The rendering pipeline first builds a status snapshot via `buildStatusSnapshot`, which aggregates the job state and preview lines, then outputs a human-readable summary.

You can programmatically access this rendering pipeline:

```javascript
import { buildStatusSnapshot } from './lib/job-control.mjs';
import { render } from './lib/render.mjs';

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

```

## Summary

- **Log-driven architecture**: Progress events persist immediately to disk via `createProgressReporter`, ensuring durability across process restarts.
- **Multi-channel output**: The reporter simultaneously writes to log files, stderr, and optional event hooks defined in `tracked-jobs.mjs`.
- **Phase inference**: Legacy jobs benefit from automatic phase detection through `inferLegacyJobPhase` in `job-control.mjs`.
- **Simple status rendering**: The `render` function in `render.mjs` displays concise progress previews without requiring users to parse raw logs manually.

## Frequently Asked Questions

### Where is the progress reporter initialized in the codebase?

The progress reporter initializes in `plugins/codex/scripts/codex-companion.mjs` between lines 580-660, where `createProgressReporter` builds the callback and passes it to `runTrackedJob` for the duration of the Codex execution.

### Can I customize how many lines appear in the status output?

Yes. The `buildStatusSnapshot` function accepts a `maxProgressLines` option that controls how many recent log lines appear in the rendered status. The default behavior captures the tail of the log file to provide context without overwhelming the terminal.

### Does the plugin support real-time streaming without polling?

The plugin writes events synchronously to the log file as they occur, but status rendering requires polling the filesystem via `readJobProgressPreview`. There is no persistent WebSocket or socket connection; instead, the design favors simple file I/O that works across different execution environments and survives network interruptions.

### What happens to progress logs after a job completes?

The log file specified during `createProgressReporter` initialization persists on disk after completion, serving as an audit trail. The plugin does not automatically truncate these files, allowing post-hoc analysis of the full progress history for debugging or compliance purposes.