Skip to main content

Overview

The CodexExecAdapter captures events from the codex exec --json command by spawning a child process and parsing JSONL output.

Class: CodexExecAdapter

Constructor

constructor(pipeline: IngestPipeline)
pipeline
IngestPipeline
required
Ingest pipeline for event processing

Methods

runAndCapture

Spawns codex exec and captures all events from stdout.
async runAndCapture(
  options: AdapterRunOptions,
  onEvent?: (event: CapturedEventEnvelope) => Promise<void> | void
): Promise<AdapterRunResult>
options
AdapterRunOptions
required
Run configuration options
options.prompt
string
required
User prompt to send to agent
options.cwd
string
required
Working directory for the agent
options.repoId
string
Repository ID (auto-generated from cwd if not provided)
options.model
string
Model name to use
options.resumeThreadId
string
Thread ID to resume existing conversation
onEvent
(event: CapturedEventEnvelope) => Promise<void> | void
Callback invoked for each captured event
sessionId
string
UUID for the capture session
threadId
string | null
Codex thread ID extracted from events
finalResponse
string | null
Final agent message text

Supporting Functions

parseExecJsonLine

Parses a single JSONL line from codex exec output.
function parseExecJsonLine(line: string): ParsedExecLine
line
string
required
Raw JSONL line
Returns:
type ParsedExecLine =
  | { ok: true; event: Record<string, unknown> }
  | { ok: false; error: string };

buildArgs

Builds command-line arguments for codex exec.
function buildArgs(options: AdapterRunOptions): string[]
options
AdapterRunOptions
required
Run options
Returns: Array of command-line arguments Example output:
// New thread:
['exec', '--json', '--cd', '/path/to/repo', '--model', 'gpt-4', 'Fix bug']

// Resume thread:
['exec', 'resume', 'thread-123', '--json', '--cd', '/path/to/repo', 'Continue']

Implementation Details

Command Execution

The adapter spawns codex as a child process:
const child = spawn('codex', args, {
  cwd: options.cwd,
  stdio: ['ignore', 'pipe', 'pipe'],
});

Event Flow

  1. Prompt event: Emits prompt.submitted immediately
  2. Process spawn: Starts codex exec --json
  3. JSONL streaming: Reads stdout line-by-line
  4. Event parsing: Parses each line and ingests into pipeline
  5. Error collection: Captures stderr for error reporting
  6. Exit handling: Waits for process exit and checks exit code

Error Handling

The adapter handles multiple error scenarios:
  • JSON parse errors: Emits error event with raw line
  • Non-zero exit: Emits error event with stderr output
  • Process errors: Propagates as exceptions

Usage Example

import { CodexExecAdapter } from './lib/adapter-codex-exec';
import { IngestPipeline } from './lib/ingest-pipeline';
import { JsonlMirror } from './lib/mirror-jsonl';

const mirror = new JsonlMirror('.codaph');
const pipeline = new IngestPipeline(mirror);
const adapter = new CodexExecAdapter(pipeline);

const result = await adapter.runAndCapture(
  {
    prompt: 'Add unit tests for auth module',
    cwd: process.cwd(),
    model: 'gpt-4',
  },
  async (event) => {
    if (event.eventType === 'item.completed') {
      const item = event.payload.item as { type?: string; text?: string };
      if (item?.type === 'agent_message') {
        console.log('Agent:', item.text);
      }
    }
  }
);

await pipeline.flush();
console.log('Session:', result.sessionId);

Comparison with CodexSdkAdapter

FeatureCodexSdkAdapterCodexExecAdapter
MechanismSDK streaming APIProcess spawn + JSONL parsing
PerformanceLower overheadSpawns subprocess
DependenciesRequires @openai/codex-sdkUses system codex CLI
Error detailsSDK exceptionsstderr capture
Best forProgrammatic integrationCLI-based workflows

Troubleshooting

codex not found

Ensure codex is in your PATH:
which codex  # Unix
where codex  # Windows

Parse errors

If you encounter JSON parse errors, check that you’re using a compatible Codex CLI version that supports --json output.

Build docs developers (and LLMs) love