Incursa.OpenAI.Codex is an async-only .NET client for the local Codex runtime. It launches the codex executable as a subprocess, so the machine running your app must already have Codex installed and authenticated.
Source documentation lives in docs/ and is mirrored into incursa-docs for publication. Edit the source repository docs only; do not edit the mirrored output.
The public package is young, but the code comes from day-to-day Incursa Codex automation work rather than a throwaway wrapper. Incursa has processed more than 10,000 Codex messages while hardening local subprocess orchestration, streamed events, typed results, and failure handling around this SDK family.
It provides:
CodexClientfor starting and managing Codex conversationsCodexThreadandCodexTurnfor stateful and turn-level control- typed inputs, events, results, options, and exceptions such as
CodexClientOptions,CodexThreadOptions,CodexTurnOptions,CodexInputItem,CodexThreadEvent,CodexThreadItem,CodexRunResult,CodexThreadSnapshot,CodexAccountReadResult,CodexAccountRateLimitsResult,CodexRuntimeCapabilities,CodexRuntimeMetadata, andCodexException - an optional DI companion package,
Incursa.OpenAI.Codex.Extensions, forIServiceCollectionregistration
Use this SDK when you want a C# wrapper around the local Codex CLI and its thread or turn APIs.
- Good fit: repo-aware automation, server-side orchestration, and workflows that delegate work to a local Codex install.
- Use the OpenAI SDK when you want direct API calls from .NET.
- Use ChatKit when you want a hosted chat UI surface.
- Use the Agents SDK when you want higher-level agent orchestration.
CodexClientOptions.ApiKeyandCodexClientOptions.BaseUrlare forwarded to the Codex subprocess; they do not remove the local Codex installation requirement.- If you want a no-throw preflight for the local executable, call
await client.IsCodexAvailableAsync()beforeInitializeAsync()or any turn operation.
The smallest useful call is a thread plus a single prompt:
using Incursa.OpenAI.Codex;
await using var client = new CodexClient();
CodexThread thread = await client.StartThreadAsync(new CodexThreadOptions
{
SkipGitRepoCheck = true,
});
CodexRunResult result = await thread.RunAsync("Say hello from Codex in one sentence.");
Console.WriteLine(result.FinalResponse);That example assumes the Codex runtime is installed locally and can authenticate through the environment or CodexClientOptions forwarded to the subprocess.
CodexRunResult.FinalResponse can be null when a turn completes with commentary only and never emits a final-answer or phase-less assistant message.
If you need DI, install Incursa.OpenAI.Codex.Extensions and register CodexClient with AddCodex(...).
Use these commands from the repository root:
dotnet restore Incursa.OpenAI.Codex.slnx
dotnet build Incursa.OpenAI.Codex.slnx -c Release --no-restore
dotnet test Incursa.OpenAI.Codex.slnx -c Release --no-build -v minimal
dotnet pack src/Incursa.OpenAI.Codex/Incursa.OpenAI.Codex.csproj -c Release --no-build --output artifacts/packages /p:ContinuousIntegrationBuild=true
dotnet pack src/Incursa.OpenAI.Codex.Extensions/Incursa.OpenAI.Codex.Extensions.csproj -c Release --no-build --output artifacts/packages /p:ContinuousIntegrationBuild=true
git diff --checkSee docs/maintainer-readiness.md for the focused test matrix, live-test opt-in commands, and release-floor details.
The CodexClientOptions type controls the runtime backend through its BackendSelection property.
| Backend | Use it when | Good for | Not available |
|---|---|---|---|
AppServer |
you need the richer conversation surface | thread lifecycle, thread goals, model listing, account login/read/logout, account rate-limit reads, thread read/resume/fork/archive/unarchive, turn steering, turn interruption | N/A |
Exec |
you only need the CLI-backed run/stream path | quick one-shot prompts and streaming responses | thread lifecycle management, thread goals, model listing, account login/read/logout, account rate-limit reads, turn steering, turn interruption |
The package currently defaults to AppServer.
At the transport level:
The main public surfaces are:
CodexClient: root entry point, async-only,IAsyncDisposable,ObserveEventsAsync()for the client-wide raw runtime event stream, account login/read/logout methods,GetAccountRateLimitsAsync()for app-server rate-limit windows, andIsCodexAvailableAsync()for an executable preflightCodexThread: stateful conversation handle withRunAsync,RunStreamedAsync,StartTurnAsync,ReadAsync,SetNameAsync,CompactAsync,GetGoalAsync,SetGoalAsync,SetGoalStatusAsync, andClearGoalAsyncCodexTurn: single-turn handle withStreamAsync,StreamNormalizedAsync,ObserveEventsAsync,ObserveNormalizedEventsAsync,RunAsync,RunToResultAsync,SteerAsync, andInterruptAsyncCodexClientOptions,CodexThreadOptions,CodexTurnOptions: runtime, thread, and turn configurationCodexInputItemand derived types such asCodexTextInput,CodexImageInput,CodexLocalImageInput,CodexSkillInput, andCodexMentionInputCodexThreadEventandCodexThreadItemhierarchies for raw streamed runtime data, includingCodexTurnPlanUpdatedEventfor structured plan updates andCodexAccountRateLimitsUpdatedEventwhen the app-server pushes a rate-limit updateCodexTurnEvent,CodexTurnResult, andCodexTurnTerminalStatefor normalized turn output, final-response capture, terminal-event detection, and stream-ended-without-terminal diagnosticsCodexRunResult,CodexThreadGoal,CodexThreadSnapshot,CodexAccountReadResult,CodexAccountRateLimitsResult,CodexRuntimeCapabilities,CodexRuntimeMetadata, andCodexExceptiontypes for result handling and diagnostics.CodexRunResult.FinalResponsestays nullable for commentary-only turns.
For UI and delivery clients, use CodexClient.ObserveEventsAsync() as the exhaustive raw event channel across the client, and use CodexTurn.ObserveEventsAsync() or CodexTurn.ObserveNormalizedEventsAsync() when a caller needs replayed turn-scoped fan-out. Consumers that want Rx-style operators can layer System.Reactive over these IObservable<T> surfaces without the core package taking a dependency on it. Prefer CodexTurn.StreamNormalizedAsync() or CodexTurn.RunToResultAsync() when you need reliable turn closeout. CodexTurnResult.TerminalEventSeen distinguishes a real Codex terminal event from a stream that ended without turn.completed or turn.failed, and FinalResponseSource records whether the final answer came from the terminal event, a completed item, or accumulated assistant deltas.
Set CodexThreadOptions.ServiceTier or CodexTurnOptions.ServiceTier to CodexServiceTier.Fast to request upstream Fast mode. The SDK sends the current Codex request value, priority, while preserving the public Fast enum name.
The runnable sample in samples/Incursa.OpenAI.Codex.Sample demonstrates:
quickstartstreamingstructured-outputimage-inputerror-handlingturn-controls
See samples/Incursa.OpenAI.Codex.Sample/README.md for the sample overview and docs/sample-modes.md for the mode-by-mode commands.
- Package versioning and shared NuGet metadata live in
Directory.Build.props. - Release cuts are driven by
scripts/release.ps1. - Public API compatibility is tracked through
PublicAPI.Shipped.txtandPublicAPI.Unshipped.txtin each package project. - See
docs/maintainer-readiness.mdfor the release and pack flow.
docs/usage-guide.mddocs/sample-modes.mdsamples/Incursa.OpenAI.Codex.Sample/README.mdsrc/Incursa.OpenAI.Codex/README.mdsrc/Incursa.OpenAI.Codex.Extensions/README.mddocs/maintainer-readiness.mdtests/Incursa.OpenAI.Codex.Tests/README.mdfuzz/README.mdbenchmarks/README.mdquality/testing-intent.yaml
- Read CONTRIBUTING.md before opening a pull request.
- Contributions are accepted under CONTRIBUTOR-AGREEMENT.md.
- Follow CODE_OF_CONDUCT.md in project spaces.
- Report vulnerabilities through SECURITY.md, not public issues.
- Do not commit secrets, local auth state, private transcripts, or repository paths from private worktrees.
docs/is the source-authored documentation tree for this repository.- Mirrored content in
incursa-docsis generated from the source tree and should not be edited directly. - Package-level consumer notes live under
src/<PackageName>/and are part of the source documentation set.
- Live behavior depends on the installed
codexexecutable, local Codex authentication, and upstream runtime behavior. Execintentionally lacks app-server-only lifecycle and control capabilities.- Upstream Python and TypeScript Codex SDK parity must be refreshed when upstream behavior changes.
- The repo still has maintenance items called out in
docs/maintainer-readiness.md.
This repository is licensed under Apache 2.0. See LICENSE.