Skip to main content

Quick Start

The most basic usage involves creating a Codex client, starting a thread, and running a turn:
import { Codex } from "@openai/codex-sdk";

const codex = new Codex();
const thread = codex.startThread();
const turn = await thread.run("Diagnose the test failure and propose a fix");

console.log(turn.finalResponse);
console.log(turn.items);

Core SDK Exports

The SDK exports the following main classes and types:

Main Classes

Codex
class
Main client for interacting with the Codex agent. Used to create and resume threads.
Thread
class
Represents a conversation with the agent. Supports multiple consecutive turns.

Type Exports

import type {
  ThreadEvent,
  ThreadStartedEvent,
  TurnStartedEvent,
  TurnCompletedEvent,
  TurnFailedEvent,
  ItemStartedEvent,
  ItemUpdatedEvent,
  ItemCompletedEvent,
  ThreadError,
  ThreadErrorEvent,
  Usage,
} from "@openai/codex-sdk";

Creating a Codex Client

The Codex class accepts optional configuration:
import { Codex } from "@openai/codex-sdk";

const codex = new Codex({
  // API configuration
  baseUrl: "https://api.openai.com/v1",
  apiKey: process.env.OPENAI_API_KEY,
  
  // CLI path override (if codex is not in PATH)
  codexPathOverride: "/custom/path/to/codex",
  
  // Environment variables for the CLI process
  env: {
    PATH: process.env.PATH,
    HOME: process.env.HOME,
  },
  
  // Additional CLI configuration overrides
  config: {
    show_raw_agent_reasoning: true,
    sandbox_workspace_write: {
      network_access: true,
    },
  },
});
baseUrl
string
Custom API base URL. Defaults to the OpenAI API endpoint.
apiKey
string
OpenAI API key. Can also be set via OPENAI_API_KEY environment variable.
codexPathOverride
string
Path to the codex CLI binary. Used when codex is not in your PATH.
env
Record<string, string>
Environment variables passed to the Codex CLI process. When provided, the SDK will not inherit from process.env.
config
CodexConfigObject
Additional --config overrides passed to the CLI. The SDK flattens this object into dotted paths.

Starting a Thread

Create a new conversation thread with optional configuration:
const thread = codex.startThread({
  workingDirectory: "/path/to/project",
  sandboxMode: "workspace-write",
  model: "gpt-4",
  skipGitRepoCheck: false,
  modelReasoningEffort: "medium",
  networkAccessEnabled: true,
  webSearchMode: "cached",
  approvalPolicy: "on-request",
  additionalDirectories: ["/path/to/extra/context"],
});

Thread Options

workingDirectory
string
Working directory for the agent. Defaults to the current directory.
sandboxMode
'read-only' | 'workspace-write' | 'danger-full-access'
File system access level for the agent.
model
string
Model to use for this thread (e.g., "gpt-4", "gpt-4-turbo").
skipGitRepoCheck
boolean
Skip the Git repository check. Defaults to false.
modelReasoningEffort
'minimal' | 'low' | 'medium' | 'high' | 'xhigh'
Amount of reasoning effort the model should apply.
networkAccessEnabled
boolean
Enable network access for the agent.
webSearchMode
'disabled' | 'cached' | 'live'
Web search configuration for the agent.
approvalPolicy
'never' | 'on-request' | 'on-failure' | 'untrusted'
When to request user approval for actions.
additionalDirectories
string[]
Additional directories to include in the agent’s context.

Running a Turn

Buffered Execution

Use run() to execute a turn and wait for the complete result:
const turn = await thread.run("Fix the failing tests");

console.log("Response:", turn.finalResponse);
console.log("Items:", turn.items);
console.log("Usage:", turn.usage);
The returned Turn object contains:
finalResponse
string
The agent’s final text response (or JSON if using structured output).
items
ThreadItem[]
Array of all items produced during the turn (commands, file changes, tool calls, etc.).
usage
Usage | null
Token usage statistics for the turn.

Streaming Events

Use runStreamed() to receive real-time events as the agent works:
const { events } = await thread.runStreamed("Analyze this codebase");

for await (const event of events) {
  switch (event.type) {
    case "thread.started":
      console.log("Thread ID:", event.thread_id);
      break;
      
    case "turn.started":
      console.log("Turn started");
      break;
      
    case "item.started":
      console.log("Item started:", event.item);
      break;
      
    case "item.updated":
      console.log("Item updated:", event.item);
      break;
      
    case "item.completed":
      console.log("Item completed:", event.item);
      break;
      
    case "turn.completed":
      console.log("Turn completed. Usage:", event.usage);
      break;
      
    case "turn.failed":
      console.error("Turn failed:", event.error.message);
      break;
      
    case "error":
      console.error("Fatal error:", event.message);
      break;
  }
}

Structured Output

Provide a JSON schema to get structured responses:
const schema = {
  type: "object",
  properties: {
    summary: { type: "string" },
    status: { type: "string", enum: ["ok", "action_required"] },
    issues: {
      type: "array",
      items: {
        type: "object",
        properties: {
          file: { type: "string" },
          line: { type: "number" },
          description: { type: "string" },
        },
        required: ["file", "description"],
      },
    },
  },
  required: ["summary", "status"],
  additionalProperties: false,
} as const;

const turn = await thread.run("Analyze the codebase for issues", {
  outputSchema: schema,
});

const result = JSON.parse(turn.finalResponse);
console.log(result.summary);
console.log(result.issues);

Using Zod Schemas

You can also use Zod schemas with the zod-to-json-schema package:
import { z } from "zod";
import { zodToJsonSchema } from "zod-to-json-schema";

const schema = z.object({
  summary: z.string(),
  status: z.enum(["ok", "action_required"]),
  issues: z.array(
    z.object({
      file: z.string(),
      line: z.number().optional(),
      description: z.string(),
    })
  ),
});

const turn = await thread.run("Analyze the codebase", {
  outputSchema: zodToJsonSchema(schema, { target: "openAi" }),
});

const result = schema.parse(JSON.parse(turn.finalResponse));

Attaching Images

Provide images alongside text prompts:
const turn = await thread.run([
  { type: "text", text: "Describe these UI screenshots and suggest improvements" },
  { type: "local_image", path: "./screenshots/dashboard.png" },
  { type: "local_image", path: "./screenshots/settings.png" },
]);
Image entries must use the local_image type with an absolute or relative path to the image file.

Resuming Threads

Threads are persisted in ~/.codex/sessions. Resume a previous conversation:
// Save the thread ID from a previous session
const threadId = thread.id;

// Later, resume the thread
const resumedThread = codex.resumeThread(threadId);
const nextTurn = await resumedThread.run("Continue from where we left off");

Working with Thread Items

Each turn produces various item types representing the agent’s work:
if (item.type === "agent_message") {
  console.log("Agent says:", item.text);
}

Token Usage

Access detailed token usage after each turn:
const turn = await thread.run("Refactor this module");

if (turn.usage) {
  console.log("Input tokens:", turn.usage.input_tokens);
  console.log("Cached input tokens:", turn.usage.cached_input_tokens);
  console.log("Output tokens:", turn.usage.output_tokens);
  
  const total = turn.usage.input_tokens + turn.usage.output_tokens;
  const cacheHitRate = turn.usage.cached_input_tokens / turn.usage.input_tokens;
  console.log("Total tokens:", total);
  console.log("Cache hit rate:", (cacheHitRate * 100).toFixed(2) + "%");
}

Aborting a Turn

Cancel a turn using an AbortSignal:
const controller = new AbortController();

// Cancel after 30 seconds
setTimeout(() => controller.abort(), 30000);

try {
  const turn = await thread.run("Long running task", {
    signal: controller.signal,
  });
} catch (error) {
  if (error.name === "AbortError") {
    console.log("Turn was cancelled");
  }
}

Error Handling

Handle errors gracefully:
try {
  const turn = await thread.run("Fix the bug");
  console.log(turn.finalResponse);
} catch (error) {
  if (error.message.includes("rate limit")) {
    console.error("Rate limit exceeded. Retrying...");
    // Implement retry logic
  } else if (error.message.includes("authentication")) {
    console.error("Invalid API key");
  } else {
    console.error("Unexpected error:", error.message);
  }
}

Advanced Example

Here’s a complete example combining multiple features:
import { Codex } from "@openai/codex-sdk";
import { z } from "zod";
import { zodToJsonSchema } from "zod-to-json-schema";

// Define structured output schema
const analysisSchema = z.object({
  summary: z.string(),
  filesAnalyzed: z.number(),
  issues: z.array(
    z.object({
      severity: z.enum(["low", "medium", "high"]),
      file: z.string(),
      description: z.string(),
    })
  ),
  recommendations: z.array(z.string()),
});

// Create Codex client
const codex = new Codex({
  apiKey: process.env.OPENAI_API_KEY,
  config: {
    show_raw_agent_reasoning: true,
  },
});

// Start thread with configuration
const thread = codex.startThread({
  workingDirectory: "/path/to/project",
  sandboxMode: "read-only",
  modelReasoningEffort: "high",
});

// Run analysis with streaming
const { events } = await thread.runStreamed(
  "Analyze the codebase for security issues and best practices",
  {
    outputSchema: zodToJsonSchema(analysisSchema, { target: "openAi" }),
  }
);

// Process events
for await (const event of events) {
  if (event.type === "item.completed") {
    const item = event.item;
    
    if (item.type === "command_execution") {
      console.log(`Executed: ${item.command}`);
    } else if (item.type === "agent_message") {
      const analysis = analysisSchema.parse(JSON.parse(item.text));
      
      console.log("\nAnalysis Complete");
      console.log("Summary:", analysis.summary);
      console.log("Files analyzed:", analysis.filesAnalyzed);
      console.log("\nIssues found:");
      
      analysis.issues.forEach(issue => {
        console.log(`  [${issue.severity.toUpperCase()}] ${issue.file}`);
        console.log(`    ${issue.description}`);
      });
      
      console.log("\nRecommendations:");
      analysis.recommendations.forEach((rec, i) => {
        console.log(`  ${i + 1}. ${rec}`);
      });
    }
  }
  
  if (event.type === "turn.completed") {
    console.log("\nToken usage:", event.usage);
  }
}