Skip to content

Repository files navigation

OpenAI Codex SDK for C#

Note

This document was generated by Codex

A .NET SDK for interacting with OpenAI Codex through the Codex CLI, providing buffered turns, streamed events, resumable threads, structured output, local image input, and Microsoft Agent Framework integration.

Status & Version

NuGet Version (with prereleases) NuGet Version (with prereleases)

Features

  • Buffered turns via Thread.RunAsync
  • Real-time JSONL event streaming via Thread.RunStreamedAsync
  • Resumable Codex threads with StartThread and ResumeThread
  • Strongly typed event and item models for agent messages, command execution, file changes, MCP tool calls, web search, reasoning, and to-do lists
  • Structured output through JSON Schema with TurnOptions.OutputSchema
  • Local image input through Input.FromParts, TextInput, and LocalImageInput
  • Codex CLI configuration for models, context windows, automatic compaction thresholds, sandboxing, approval policy, reasoning effort, web search, additional directories, base URL, API key, and environment variables
  • Microsoft Agent Framework integration through CodexSdk.MAF
  • .NET 10.0 target with nullable reference types and implicit usings enabled

Installation

Core SDK

Install via NuGet:

dotnet add package CodexSdk --prerelease

Microsoft Agent Framework Integration (Optional)

For Microsoft Agent Framework support:

dotnet add package CodexSdk.MAF --prerelease

Prerequisites

  • .NET 10.0 SDK
  • Node.js, when installing the Codex CLI through npm
  • Codex CLI:
npm install -g @openai/codex
  • OpenAI API key available to the CLI. Set CODEX_API_KEY in the environment, or pass CodexOptions.ApiKey.

Quick Start

Buffered Turn

using OpenAI.CodexSdk;
using CodexClient = OpenAI.CodexSdk.Codex;

var codex = new CodexClient();
var thread = codex.StartThread();

var turn = await thread.RunAsync("List the files in the current directory.");

Console.WriteLine(turn.FinalResponse);
Console.WriteLine($"Thread ID: {thread.Id}");

Streaming Events

using OpenAI.CodexSdk;
using CodexClient = OpenAI.CodexSdk.Codex;

var codex = new CodexClient();
var thread = codex.StartThread();

await foreach (var evt in thread.RunStreamedAsync("Summarize this repository."))
{
    switch (evt)
    {
        case ItemCompletedEvent { Item: AgentMessageItem msg }:
            Console.WriteLine($"[agent] {msg.Text}");
            break;

        case ItemCompletedEvent { Item: CommandExecutionItem cmd }:
            Console.WriteLine($"[cmd] {cmd.Command} exit={cmd.ExitCode}");
            Console.WriteLine(cmd.AggregatedOutput);
            break;

        case TurnCompletedEvent completed:
            Console.WriteLine($"[usage] in={completed.Usage.InputTokens} out={completed.Usage.OutputTokens}");
            break;
    }
}

Structured Output

using OpenAI.CodexSdk;
using CodexClient = OpenAI.CodexSdk.Codex;

var codex = new CodexClient();
var thread = codex.StartThread();

var schema = new Dictionary<string, object?>
{
    ["type"] = "object",
    ["properties"] = new Dictionary<string, object?>
    {
        ["summary"] = new Dictionary<string, object?> { ["type"] = "string" },
        ["status"] = new Dictionary<string, object?>
        {
            ["type"] = "string",
            ["enum"] = new[] { "ok", "action_required" },
        },
    },
    ["required"] = new[] { "summary", "status" },
    ["additionalProperties"] = false,
};

var turn = await thread.RunAsync(
    "Summarize the git status of the current repository.",
    new TurnOptions { OutputSchema = schema });

Console.WriteLine(turn.FinalResponse);

Local Image Input and Resume

using OpenAI.CodexSdk;
using CodexClient = OpenAI.CodexSdk.Codex;

var codex = new CodexClient();

var thread = codex.StartThread(new ThreadOptions
{
    SandboxMode = SandboxMode.ReadOnly,
});

var turn = await thread.RunAsync(Input.FromParts(
[
    new TextInput("Describe what you see in these screenshots."),
    new LocalImageInput("./ui.png"),
    new LocalImageInput("./diagram.jpg"),
]));

Console.WriteLine(turn.FinalResponse);

var savedThreadId = thread.Id ?? throw new InvalidOperationException("Thread ID was not set.");
var resumed = codex.ResumeThread(savedThreadId);
var followUp = await resumed.RunAsync("Continue the analysis from where we left off.");

Console.WriteLine(followUp.FinalResponse);

Microsoft Agent Framework Integration

using Microsoft.Agents.AI;
using OpenAI.CodexSdk.MAF;

var agent = new CodexAIAgent();
var session = await agent.CreateSessionAsync();

var response = await agent.RunAsync(
    "Explain what this project does in one paragraph.",
    session);

Console.WriteLine(response.Text);

await foreach (var update in agent.RunStreamingAsync(
    "List the files in the samples directory.",
    session))
{
    if (!string.IsNullOrWhiteSpace(update.Text))
    {
        Console.Write(update.Text);
    }
}

Architecture

The SDK uses a thin process bridge over codex exec --experimental-json, then maps the JSONL event stream into .NET types.

Core Components

Codex - Main SDK entry point

  • Creates new threads with StartThread
  • Resumes existing threads with ResumeThread
  • Owns global CodexOptions
  • Reuses the same Codex CLI execution bridge across threads

Thread - Conversation and turn API

  • Runs buffered prompts with RunAsync
  • Streams events with RunStreamedAsync
  • Stores the current thread ID after thread.started
  • Supports text, local image inputs, and per-turn structured output

CodexExec - Codex CLI subprocess bridge

  • Resolves the codex executable from CodexOptions.CodexPathOverride or PATH
  • Starts codex exec --experimental-json
  • Sends prompts through stdin
  • Yields stdout JSONL lines as an async stream
  • Applies CLI arguments, config overrides, and environment variables

Event Types

All streamed events derive from ThreadEvent:

  • ThreadStartedEvent - contains the resumable thread ID
  • TurnStartedEvent - emitted when a prompt starts processing
  • TurnCompletedEvent - contains token usage
  • TurnFailedEvent - contains terminal turn errors
  • ItemStartedEvent - emitted when a thread item begins
  • ItemUpdatedEvent - emitted as a thread item changes
  • ItemCompletedEvent - emitted when an item reaches a terminal state
  • ThreadErrorEvent - emitted for unrecoverable stream errors

Item Types

All thread items derive from ThreadItem:

  • AgentMessageItem - final or intermediate agent text
  • ReasoningItem - reasoning summary text
  • CommandExecutionItem - command, status, output, and exit code
  • FileChangeItem - file patch changes and apply status
  • McpToolCallItem - MCP server, tool, arguments, result, and errors
  • WebSearchItem - web search query information
  • TodoListItem - agent task list state
  • ErrorItem - non-fatal item-level errors

Microsoft Agent Framework Integration

The CodexSdk.MAF package provides a Microsoft.Agents.AI bridge backed by Codex threads.

CodexAIAgent

  • Implements AIAgent
  • Supports buffered RunAsync and streaming RunStreamingAsync
  • Converts Codex usage into UsageDetails
  • Uses ChatHistoryProvider when configured
  • Converts image DataContent inputs to temporary local image arguments for the duration of each turn
  • Maps assistant responses to ChatMessage and AgentResponseUpdate

CodexAgentSession

  • Stores the Codex ThreadId
  • Serializes and deserializes session state
  • Enables conversation continuity across processes or requests

CodexAIAgentOptions

  • Accepts core CodexOptions
  • Accepts per-thread ThreadOptions
  • Supports explicit ThreadId
  • Uses IsResume to resume an existing Codex thread selected by options
  • Accepts an optional ChatHistoryProvider

Configuration

Environment Variables

The SDK forwards environment variables to the Codex CLI process.

  • CODEX_API_KEY - API key used by the CLI. Set from CodexOptions.ApiKey when provided.
  • CODEX_INTERNAL_ORIGINATOR_OVERRIDE - set by the SDK to identify C# SDK-originated CLI calls.

When CodexOptions.Env is provided, the SDK uses that dictionary as the process environment. When it is not provided, the SDK inherits the current process environment.

CodexOptions

Global options for the Codex client:

using OpenAI.CodexSdk;
using CodexClient = OpenAI.CodexSdk.Codex;

var codex = new CodexClient(new CodexOptions
{
    CodexPathOverride = "/path/to/codex",
    BaseUrl = "https://api.openai.com/v1",
    ApiKey = "sk-...",
    Config = new Dictionary<string, CodexConfigValue>
    {
        ["model_provider"] = "openai",
        ["approval_policy"] = "on-request",
    },
    Env = new Dictionary<string, string>
    {
        ["CODEX_API_KEY"] = "sk-...",
    },
});

ThreadOptions

Per-thread options forwarded to codex exec:

var thread = codex.StartThread(new ThreadOptions
{
    Model = "gpt-5.6-sol",
    SandboxMode = SandboxMode.WorkspaceWrite,
    WorkingDirectory = "/path/to/project",
    SkipGitRepoCheck = true,
    ModelReasoningEffort = ModelReasoningEffort.High,
    ModelContextWindow = 1_000_000,
    ModelAutoCompactTokenLimit = 900_000,
    NetworkAccessEnabled = true,
    WebSearchMode = WebSearchMode.Live,
    ApprovalPolicy = ApprovalMode.OnRequest,
    AdditionalDirectories = ["/path/to/shared/context"],
});

ModelContextWindow and ModelAutoCompactTokenLimit are forwarded only when their values are greater than zero. Null, zero, and negative values are omitted. The Codex CLI may cap the effective context window based on the selected model's supported maximum.

TurnOptions

Per-turn options:

using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));

var turn = await thread.RunAsync(
    "Return a JSON summary of this repository.",
    new TurnOptions
    {
        OutputSchema = schema,
        CancellationToken = cts.Token,
    });

Development

Building

dotnet restore codexsdk.slnx
dotnet build codexsdk.slnx --configuration Debug
dotnet build codexsdk.slnx --configuration Release

Testing

Tests are not currently present. When a test project is added, run it with:

dotnet test <path-to-test-csproj>

Formatting

dotnet format codexsdk.slnx

Running Samples

dotnet run --project samples/samples.csproj

Packaging NuGet Packages

dotnet pack codexsdk.slnx -o ./releases -c Release

Or use the repository helper script:

./publish.sh 0.0.1-preview.1

Examples

The samples/ folder contains runnable examples:

  • BasicStreaming - streamed event handling and buffered turns
  • StructuredOutput - JSON Schema output with TurnOptions.OutputSchema
  • ImageAndResume - local image input and thread resumption
  • CodexMafAgent - Microsoft Agent Framework integration, streaming, buffered responses, and session serialization

Run all enabled samples:

dotnet run --project samples/samples.csproj

Key Behaviors

Message Streaming and Termination

  • RunStreamedAsync yields each parsed Codex JSONL event.
  • RunAsync buffers completed items and returns a Turn.
  • RunAsync stores the latest AgentMessageItem.Text as Turn.FinalResponse.
  • RunAsync throws an InvalidOperationException when a TurnFailedEvent is received.

Thread Resumption

  • Thread.Id is populated from the ThreadStartedEvent.
  • Codex.ResumeThread(id) resumes a thread persisted by the Codex CLI.
  • MAF sessions serialize the Codex thread ID through CodexAgentSession.

JSON Serialization

  • Polymorphic event and item models use the type discriminator emitted by the CLI.
  • Enum values are parsed from snake_case JSON names.
  • Structured output schemas are written to a temporary JSON file and passed to codex exec --output-schema.

Resource Management

  • Each turn starts a Codex CLI subprocess and closes stdin after sending the prompt.
  • Cancellation tokens terminate the underlying process when cancellation is requested.
  • The SDK captures stderr and includes it when the CLI exits with a non-zero code.

Troubleshooting

"codex not found"

Install the Codex CLI globally:

npm install -g @openai/codex

If the CLI is installed in a custom location, pass the executable path:

var codex = new Codex(new CodexOptions
{
    CodexPathOverride = "/path/to/codex",
});

Node.js Is Missing

Install Node.js from https://nodejs.org/, then install the Codex CLI:

npm install -g @openai/codex

Authentication Errors

Set your API key:

# macOS/Linux
export CODEX_API_KEY="your-api-key"

# Windows PowerShell
$env:CODEX_API_KEY="your-api-key"

# Windows Command Prompt
set CODEX_API_KEY=your-api-key

Or pass it via options:

var codex = new Codex(new CodexOptions
{
    ApiKey = "your-api-key",
});

Git Repository Check

If you intentionally run Codex outside a Git repository, enable:

var thread = codex.StartThread(new ThreadOptions
{
    SkipGitRepoCheck = true,
});

Sandbox and Approval Issues

Adjust the thread policy:

var thread = codex.StartThread(new ThreadOptions
{
    SandboxMode = SandboxMode.WorkspaceWrite,
    ApprovalPolicy = ApprovalMode.OnRequest,
    NetworkAccessEnabled = true,
});

Contributing

Contributions are welcome. Please keep changes focused, update samples when behavior changes, and run:

dotnet format codexsdk.slnx
dotnet build codexsdk.slnx --configuration Release

License

MIT License - see LICENSE for details.

Links

About

Codex SDK for C#

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages