ManagedCode.CodexSharpSDK 1.0.1

Prefix Reserved
dotnet add package ManagedCode.CodexSharpSDK --version 1.0.1
                    
NuGet\Install-Package ManagedCode.CodexSharpSDK -Version 1.0.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="ManagedCode.CodexSharpSDK" Version="1.0.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ManagedCode.CodexSharpSDK" Version="1.0.1" />
                    
Directory.Packages.props
<PackageReference Include="ManagedCode.CodexSharpSDK" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add ManagedCode.CodexSharpSDK --version 1.0.1
                    
#r "nuget: ManagedCode.CodexSharpSDK, 1.0.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package ManagedCode.CodexSharpSDK@1.0.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=ManagedCode.CodexSharpSDK&version=1.0.1
                    
Install as a Cake Addin
#tool nuget:?package=ManagedCode.CodexSharpSDK&version=1.0.1
                    
Install as a Cake Tool

ManagedCode.CodexSharpSDK

CI Release CodeQL NuGet License: MIT

ManagedCode.CodexSharpSDK is an open-source .NET SDK for driving the Codex CLI from C#.

It is a CLI-first .NET 10 / C# 14 SDK aligned with real codex runtime behavior, with:

  • thread-based API (start / resume)
  • streamed JSONL events
  • structured output schema support
  • image attachments
  • --config flattening to TOML
  • NativeAOT-friendly implementation and tests on TUnit

All consumer usage examples are documented in this README; this repository intentionally does not keep standalone sample projects.

Installation

dotnet add package ManagedCode.CodexSharpSDK

Prerequisites

Before using this SDK, you must have:

  • codex CLI installed and available in PATH
  • an already authenticated Codex session (codex login)

Quick check:

codex --version
codex login

Quickstart

using ManagedCode.CodexSharpSDK;

using var client = new CodexClient();

var thread = client.StartThread(new ThreadOptions
{
    Model = CodexModels.Gpt54,
    ModelReasoningEffort = ModelReasoningEffort.Medium,
});

var turn = await thread.RunAsync("Diagnose failing tests and propose a fix");

Console.WriteLine(turn.FinalResponse);
Console.WriteLine($"Items: {turn.Items.Count}");

AutoStart is enabled by default, so StartThread() works immediately.

Advanced Configuration (Optional)

using var client = new CodexClient(new CodexClientOptions
{
    CodexOptions = new CodexOptions
    {
        // Override only when `codex` is not discoverable via npm/PATH.
        CodexExecutablePath = "/custom/path/to/codex",
    },
});

var thread = client.StartThread(new ThreadOptions
{
    Model = CodexModels.Gpt54,
    ModelReasoningEffort = ModelReasoningEffort.High,
    SandboxMode = SandboxMode.WorkspaceWrite,
});

Extended CLI Options

ThreadOptions supports full codex exec control.

var thread = client.StartThread(new ThreadOptions
{
    Profile = "strict",
    UseOss = true,
    LocalProvider = OssProvider.LmStudio,
    FullAuto = true,
    Ephemeral = true,
    Color = ExecOutputColor.Auto,
    EnabledFeatures = ["multi_agent"],
    DisabledFeatures = ["steer"],
    AdditionalCliArguments = ["--some-future-flag", "custom-value"],
});

Codex CLI Metadata

using var client = new CodexClient();

var metadata = client.GetCliMetadata();
Console.WriteLine($"Installed codex-cli: {metadata.InstalledVersion}");
Console.WriteLine($"Default model: {metadata.DefaultModel ?? "(not set)"}");

foreach (var model in metadata.Models.Where(model => model.IsListed))
{
    Console.WriteLine(model.Slug);
}

GetCliMetadata() reads:

  • installed CLI version from codex --version
  • default model from ~/.codex/config.toml
  • model catalog from ~/.codex/models_cache.json
var update = client.GetCliUpdateStatus();
if (update.IsUpdateAvailable)
{
    Console.WriteLine(update.UpdateMessage);
    Console.WriteLine(update.UpdateCommand);
}

GetCliUpdateStatus() compares installed CLI version with latest published @openai/codex npm version and returns an update command matched to your install context (bun or npm).

When thread-level web search options are omitted, SDK does not emit a web_search override and leaves your existing CLI/config value as-is.

Client Lifecycle and Thread Safety

  • CodexClient is safe for concurrent use from multiple threads.
  • StartAsync() is idempotent and guarded.
  • StopAsync() cleanly disconnects client state.
  • Dispose() transitions client to Disposed.
  • A single CodexThread instance serializes turns (RunAsync and RunStreamedAsync) to prevent race conditions in shared conversation state.

Streaming

var streamed = await thread.RunStreamedAsync("Implement the fix");

await foreach (var evt in streamed.Events)
{
    switch (evt)
    {
        case ItemCompletedEvent completed:
            Console.WriteLine($"Item: {completed.Item.Type}");
            break;
        case TurnCompletedEvent done:
            Console.WriteLine($"Output tokens: {done.Usage.OutputTokens}");
            break;
    }
}

Structured Output

using System.Text.Json.Serialization;

public sealed record RepositorySummary(string Summary, string Status);

[JsonSerializable(typeof(RepositorySummary))]
internal sealed partial class AppJsonContext : JsonSerializerContext;

var schema = StructuredOutputSchema.Map<RepositorySummary>(
    additionalProperties: false,
    (response => response.Summary, StructuredOutputSchema.PlainText()),
    (response => response.Status, StructuredOutputSchema.PlainText()));

var result = await thread.RunAsync<RepositorySummary>(
    "Summarize repository status",
    schema,
    AppJsonContext.Default.RepositorySummary);
Console.WriteLine(result.TypedResponse.Status);
Console.WriteLine(result.TypedResponse.Summary);

For advanced options (for example cancellation), use the TurnOptions overload:

using var cancellation = new CancellationTokenSource(TimeSpan.FromSeconds(30));

var result = await thread.RunAsync<RepositorySummary>(
    "Summarize repository status",
    AppJsonContext.Default.RepositorySummary,
    new TurnOptions
    {
        OutputSchema = schema,
        CancellationToken = cancellation.Token,
    });

RunAsync<TResponse> always requires OutputSchema (direct parameter or TurnOptions.OutputSchema). For AOT/trimming-safe typed deserialization, pass JsonTypeInfo<TResponse> from a source-generated context. Overloads without JsonTypeInfo<TResponse> are explicitly marked with RequiresDynamicCode and RequiresUnreferencedCode.

Diagnostics Logging (Optional)

using Microsoft.Extensions.Logging;

public sealed class ConsoleCodexLogger : ILogger
{
    public IDisposable BeginScope<TState>(TState state)
        where TState : notnull
    {
        return NullScope.Instance;
    }

    public bool IsEnabled(LogLevel logLevel)
    {
        return true;
    }

    public void Log<TState>(
        LogLevel logLevel,
        EventId eventId,
        TState state,
        Exception? exception,
        Func<TState, Exception?, string> formatter)
    {
        Console.WriteLine($"[{logLevel}] {formatter(state, exception)}");
        if (exception is not null)
        {
            Console.WriteLine(exception);
        }
    }

    private sealed class NullScope : IDisposable
    {
        public static NullScope Instance { get; } = new();
        public void Dispose() { }
    }
}

using var client = new CodexClient(new CodexOptions
{
    Logger = new ConsoleCodexLogger(),
});

Images + Text Input

using var imageStream = File.OpenRead("./photo.png");

var result = await thread.RunAsync(
[
    new TextInput("Describe these images"),
    new LocalImageInput("./ui.png"),
    new LocalImageInput(new FileInfo("./diagram.jpg")),
    new LocalImageInput(imageStream, "photo.png"),
]);

Resume an Existing CodexThread

var resumed = client.ResumeThread("thread_123");
await resumed.RunAsync("Continue from previous plan");

Microsoft.Extensions.AI Integration

An optional adapter package lets you use CodexSharpSDK through the standard IChatClient interface from Microsoft.Extensions.AI.

dotnet add package ManagedCode.CodexSharpSDK.Extensions.AI

Basic usage

using Microsoft.Extensions.AI;
using ManagedCode.CodexSharpSDK.Extensions.AI;

IChatClient client = new CodexChatClient(new CodexChatClientOptions
{
    DefaultModel = CodexModels.Gpt54,
});

var response = await client.GetResponseAsync("Diagnose failing tests and propose a fix");
Console.WriteLine(response.Text);

DI registration

using ManagedCode.CodexSharpSDK.Extensions.AI.Extensions;

builder.Services.AddCodexChatClient(options =>
{
    options.DefaultModel = CodexModels.Gpt54;
});

// Then inject IChatClient anywhere:
app.MapGet("/ask", async (IChatClient client) =>
{
    var response = await client.GetResponseAsync("Summarize the repo");
    return response.Text;
});

Resolve IChatClient from IServiceProvider

using Microsoft.Extensions.AI;
using Microsoft.Extensions.DependencyInjection;
using ManagedCode.CodexSharpSDK.Models;
using ManagedCode.CodexSharpSDK.Extensions.AI.Extensions;

var services = new ServiceCollection();
services.AddCodexChatClient(options =>
{
    options.DefaultModel = CodexModels.Gpt54;
});

using var provider = services.BuildServiceProvider();
var chatClient = provider.GetRequiredService<IChatClient>();

Keyed registration is also supported:

using Microsoft.Extensions.AI;
using Microsoft.Extensions.DependencyInjection;
using ManagedCode.CodexSharpSDK.Models;
using ManagedCode.CodexSharpSDK.Extensions.AI.Extensions;

var services = new ServiceCollection();
services.AddKeyedCodexChatClient("codex-main", options =>
{
    options.DefaultModel = CodexModels.Gpt54;
});

using var provider = services.BuildServiceProvider();
var keyedChatClient = provider.GetRequiredKeyedService<IChatClient>("codex-main");

Streaming

await foreach (var update in client.GetStreamingResponseAsync("Implement the fix"))
{
    Console.Write(update.Text);
}

Codex-specific options via ChatOptions

var options = new ChatOptions
{
    ModelId = CodexModels.Gpt54,
    AdditionalProperties = new AdditionalPropertiesDictionary
    {
        ["codex:sandbox_mode"] = "workspace-write",
        ["codex:reasoning_effort"] = "high",
    },
};

var response = await client.GetResponseAsync("Refactor the auth module", options);

Rich content types

Codex-specific output items (commands, file changes, MCP tool calls, web searches) are preserved as typed AIContent subclasses:

foreach (var content in response.Messages.SelectMany(m => m.Contents))
{
    switch (content)
    {
        case CommandExecutionContent cmd:
            Console.WriteLine($"Command: {cmd.Command} (exit {cmd.ExitCode})");
            break;
        case FileChangeContent file:
            Console.WriteLine($"File changes: {file.Changes.Count}");
            break;
    }
}

See docs/Features/meai-integration.md and ADR 003 for full details.

Build and Test

dotnet build ManagedCode.CodexSharpSDK.slnx -c Release -warnaserror
dotnet test --solution ManagedCode.CodexSharpSDK.slnx -c Release
Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.1 37 3/6/2026
1.0.0 38 3/5/2026
0.1.3 38 3/6/2026