OpenCodeDotNet.Sdk 0.9.0-preview.6

Prefix Reserved
This is a prerelease version of OpenCodeDotNet.Sdk.
dotnet add package OpenCodeDotNet.Sdk --version 0.9.0-preview.6
                    
NuGet\Install-Package OpenCodeDotNet.Sdk -Version 0.9.0-preview.6
                    
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="OpenCodeDotNet.Sdk" Version="0.9.0-preview.6" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="OpenCodeDotNet.Sdk" Version="0.9.0-preview.6" />
                    
Directory.Packages.props
<PackageReference Include="OpenCodeDotNet.Sdk" />
                    
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 OpenCodeDotNet.Sdk --version 0.9.0-preview.6
                    
#r "nuget: OpenCodeDotNet.Sdk, 0.9.0-preview.6"
                    
#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 OpenCodeDotNet.Sdk@0.9.0-preview.6
                    
#: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=OpenCodeDotNet.Sdk&version=0.9.0-preview.6&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=OpenCodeDotNet.Sdk&version=0.9.0-preview.6&prerelease
                    
Install as a Cake Tool

opencode SDK for .NET

License: MIT NuGet CI Linux Tests

πŸš€ Quick Start: Install | Quick start | Guide | API coverage

Unofficial. This project is not affiliated with or endorsed by the opencode team.

πŸ“¦ New package ids and a new home (0.9.0-preview.5). The packages are now OpenCodeDotNet.Sdk and OpenCodeDotNet.Sdk.Extensions; OpenCodeAI.Sdk and OpenCodeAI.Sdk.Extensions are deprecated. Namespaces are unchanged, so only the PackageReference changes. The repository moved to the opencode-dotnet organization, and old links redirect.

A strongly typed .NET client for the opencode server β€” the HTTP API that every opencode front-end (TUI, desktop, web UI, plugins) uses. The SDK speaks the OpenCode 2.x API; the 1.x server API is not supported.

await using var server = await OpenCodeServer.StartAsync();
using var client = server.CreateClient();

var created = await client.Sessions.CreateSessionAsync(new SessionCreateRequest { Title = "hello from .NET" });
Console.WriteLine($"session {created.Session.Id}");

πŸŽ‰ Project Status

Pre-1.0, and the protocol surface is complete. All 140 operations in the pinned OpenAPI snapshot are callable β€” 138 as generated HTTP calls, and the two terminal WebSocket connections through hand-written transports. All three connection modes work: a private server the SDK starts, a server you already run, and the background service that the opencode CLI registers.

  • 🚧 Releases are 0.9.0-preview.N. A reviewed baseline locks the public surface, but it can still change before 1.0.0. See CHANGELOG.md.
  • πŸ“Œ The SDK builds against a snapshot of an upstream release tag, never a live branch. spec/SNAPSHOT.md owns the exact pin and the refresh procedure.
  • πŸ”œ An MCP server over this SDK is planned, not started. It will live in its own repository in the opencode-dotnet organization.

πŸ’‘ Why this SDK?

  • Typed all the way down. Every operation has a generated request type, a generated response envelope, and typed error models. That includes opencode's unions without a discriminator, which off-the-shelf .NET OpenAPI generators did not represent correctly.
  • One transport for every connection mode. The same pipeline owns endpoint authority, authentication, buffering, and failure mapping, whether you start the server, point at one, or discover the CLI's background service.
  • Errors you can branch on. A call throws a typed exception by default. With OpenCodeRequestOptions.NoThrow, it returns the failure as data instead β€” useful when a 404 is a normal answer.
  • Broad .NET reach. net472 is a first-class target, so the SDK works in .NET Framework hosts, not only in modern apps; netstandard2.0 is a compatibility asset for other runtimes.
  • No reflection serialization. System.Text.Json source generation throughout. Both packages declare IsAotCompatible on net10.0.
  • A pinned protocol. Each refresh to a new upstream release comes with a receipt, so a regeneration is a diff that you can review.

🧭 API Coverage

OpenCodeClient exposes one sub-client per area of the API. Every sub-client is also injectable on its own when you use dependency injection.

Area Entry point Guide
Sessions, messages, prompts, session logs client.Sessions Requests, Pagination
The global event bus client.Events Streaming
Terminals and persistent terminals client.Ptys, client.PersistentPtys Terminals
Shell commands client.Shells Requests
Files and version control client.FileSystem, client.Vcs, client.Worktrees Requests
Permissions and forms client.Permissions, client.Forms Requests
Models and providers client.Providers, client.LanguageModels, client.Credentials β€”
Agents, commands, skills, plugins client.Agents, client.Commands, client.Skills, client.Plugins β€”
MCP servers and integrations client.McpServers, client.Integrations β€”
Configuration, projects, references client.Config, client.Projects, client.References β€”
Server info and pairing client.Server Connection modes
Locations client.GetLocationAsync, client.ReloadLocationsAsync, client.Debug Requests
Web search and RPC client.Websearch, client.Rpc β€”
Operations upstream marks experimental client.Experimental β€”

The two terminal connections (pty.connect, persistentPty.connect) are WebSocket upgrades that the HTTP pipeline cannot carry. They are fully usable through the hand-written PtySession and PersistentPtySession types. Nothing is declined: src/OpenCode.Sdk/.generation-incomplete is the machine-readable map that the build reads.

πŸ“¦ Installation

dotnet add package OpenCodeDotNet.Sdk --prerelease
dotnet add package OpenCodeDotNet.Sdk.Extensions --prerelease   # dependency injection, optional

The package id is not the namespace. You install OpenCodeDotNet.Sdk, and you write using OpenCode.Sdk;. nuget.org reserves the OpenCode. id prefix for an unrelated owner, so only the PackageReference carries the OpenCodeDotNet name. The earlier ids, OpenCodeAI.Sdk and OpenCodeAI.Sdk.Extensions, receive no further versions.

You also need the opencode CLI, from the @opencode/cli npm scope. Install the release that this repository pins β€” later releases usually work, but they are not what the tests run against:

npm install -g @opencode/cli@2.0.22

You do not have to start it. OpenCodeServer.StartAsync() in the quick start starts a private server for you.

Nightly builds (GitHub Packages)

Every code push to master publishes 0.9.0-nightly.{yyyyMMdd}.{shortSha} to GitHub Packages:

# Add the GitHub Packages source (PAT: classic token with the read:packages scope)
dotnet nuget add source https://nuget.pkg.github.com/opencode-dotnet/index.json \
  --name github-opencode-sdk \
  --username YOUR_GITHUB_USERNAME \
  --password YOUR_GITHUB_PAT \
  --store-password-in-clear-text

# Install the nightly packages
dotnet add package OpenCodeDotNet.Sdk --prerelease --source github-opencode-sdk
dotnet add package OpenCodeDotNet.Sdk.Extensions --prerelease --source github-opencode-sdk

<details> <summary>Keep the token out of shell history with a <code>nuget.config</code></summary>

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <packageSources>
    <add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
    <add key="github-opencode-sdk" value="https://nuget.pkg.github.com/opencode-dotnet/index.json" />
  </packageSources>
  <packageSourceCredentials>
    <github-opencode-sdk>
      <add key="Username" value="%GITHUB_USERNAME%" />
      <add key="ClearTextPassword" value="%GITHUB_PAT%" />
    </github-opencode-sdk>
  </packageSourceCredentials>
</configuration>

</details>

πŸ”‘ GitHub Packages authentication: GitHub Packages requires a classic Personal Access Token with the read:packages scope, even for public packages. The NuGet registry does not accept fine-grained tokens. Linux and macOS need --store-password-in-clear-text, because NuGet cannot encrypt stored credentials there. Never commit a real token. Inside GitHub Actions you need no PAT: the workflow's own GITHUB_TOKEN works as the password.

πŸš€ Quick Start

Pick the connection mode that matches where your server lives:

You want… Use Who stops the server
A private server for this app only OpenCodeServer.StartAsync() The SDK, when you dispose it
A server you already run new OpenCodeClient(options) You
The background service the CLI shares with other clients OpenCodeServer.DiscoverAsync() or EnsureAsync() Nobody, unless you call StopAsync()

The SDK starts the server

The launcher starts a private opencode serve child, creates its password, and gives you a client bound to it. It resolves opencode from PATH as a shell does, PATHEXT included, so the npm .cmd shim works on Windows.

using OpenCode.Sdk;
using OpenCode.Sdk.Models;

await using var server = await OpenCodeServer.StartAsync();
using var client = server.CreateClient();

var info = await client.Server.GetInfoAsync();
Console.WriteLine($"opencode {info.ServerInfo.Version} (pid {info.ServerInfo.Pid})");

using var window = new CancellationTokenSource(TimeSpan.FromSeconds(30));
await foreach (var @event in client.Events.SubscribeAsync(window.Token))
{
    Console.WriteLine($"{@event.GetType().Name} ({@event.Type})");
}

A server you already run

using var client = new OpenCodeClient(new OpenCodeClientOptions
{
    Endpoint = new Uri("http://127.0.0.1:4096"),
    Password = Environment.GetEnvironmentVariable("OPENCODE_PASSWORD"),
});

The client reads no environment variables of its own. The caller decides where the password comes from, as opencode's own CLI does.

The background service the CLI runs

DiscoverAsync reads the CLI's registration file with the CLI's own rules and checks the daemon's authenticated status. It returns a handle that owns nothing: disposing it never stops the service that other clients share. Null means no ready service. EnsureAsync starts one through the CLI's own election when none is running.

var server = await OpenCodeServer.DiscoverAsync();
if (server is null)
{
    return; // no ready registered service
}

using var client = server.CreateClient();

The connection guide has every option, EnsureAsync, StopAsync, launcher output capture, and pairing another client.

Dependency injection

OpenCode.Sdk.Extensions registers one singleton client that owns its transport for the container's lifetime. The client is thread-safe. Every sub-client resolves from that same instance, so you can inject SessionsClient, EventsClient, or PtysClient directly.

builder.Services.AddOpenCode(options =>
{
    options.Endpoint = new Uri("http://127.0.0.1:4096");
    options.Password = Environment.GetEnvironmentVariable("OPENCODE_PASSWORD");
});

internal sealed class SessionWorker(SessionsClient sessions) : BackgroundService
{
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        var page = await sessions.ListSessionsAsync(
            new SessionListRequest { Limit = "10", Order = ListOrder.Descending },
            cancellationToken: stoppingToken);

        Console.WriteLine($"{page.Sessions.Count} sessions, next cursor {page.Cursor.Next ?? "<none>"}");
    }
}

AddOpenCode(IConfiguration) binds the same options from a configuration section. Configuration binding uses reflection, so that overload is annotated [RequiresDynamicCode] and [RequiresUnreferencedCode]. Under trimming or native AOT, use the configure-action overload.

πŸ“š Documentation

Guide What it covers
The guide Index of every page below, in reading order
Getting started Install, first call, and the shape of the client family
Connection modes The standalone launcher, an external server, the background service, pairing, and DI registration
Streaming The global event bus and per-session server-sent event streams
Terminals PTY and persistent-PTY sessions over the WebSocket doors
Errors and responses Throwing versus NoThrow, and the typed error model
Pagination Cursor-carrying list envelopes, Enumerate*Async, and its Pages
Requests Request records, the absent/null/set states of Optional<T>, query members, per-call location, and the permission, worktree, and shell-timeout members

Architecture, decision records, and engineering policy live under docs/. Start at AGENTS.md for the internals.

πŸš€ Platform Compatibility & Quality Status

Supported Platforms

Both packages target netstandard2.0;net472;net8.0;net9.0;net10.0. The whole suite runs on net472 on Windows, real-process launcher tests included, and on net8.0, net9.0, and net10.0 on Windows, Linux, and macOS. A .NET Framework project needs a newer C# version than its default; the getting-started guide has the two properties to set.

Build & Test Matrix

Category Platform/Type Status Description
πŸ”§ Build Cross-Platform CI Matrix: Windows, Linux, macOS
πŸ§ͺ Tests Linux Linux Tests net8.0, net9.0, net10.0
πŸ§ͺ Tests Windows Windows Tests net472 plus every modern target
πŸ§ͺ Tests macOS macOS Tests net8.0, net9.0, net10.0
πŸ“‘ Consumer leg Linux, Windows Consumer leg Weekly and on demand: the same suite against the published @opencode/cli build for the pin

πŸ“¦ Package Status

Package NuGet.org GitHub Packages
OpenCodeDotNet.Sdk NuGet GitHub Packages
OpenCodeDotNet.Sdk.Extensions NuGet GitHub Packages

Known Issues

  • The event bus has no replay. EventsClient.SubscribeAsync is a live stream: events published while you are disconnected are lost, and a consumer slower than the producer can overflow and fail the stream. This is the server's contract, not an SDK limitation. See the streaming guide.

  • A CLI-started server's session log holds only the sync marker. The per-session log reads from the server's event store, and the distributed opencode CLI starts its server without event persistence. No flag, environment variable, or configuration key turns it on (confirmed at the pin; observed on @opencode/cli@2.0.15). SessionClient.GetLogAsync does not fail: with or without Follow, it delivers one EventLogSynced marker and no durable events. For live session activity, subscribe to the global event bus and filter by session id. Persisted replay needs a host that embeds the opencode server library with persistence enabled.

  • On net472 and netstandard2.0, two costs are larger than on modern targets. A response body over 1 MB is copied once at wire size, because the downlevel array pool caps its buckets at 1 MB. On Unix (Mono), owner-only files that discovery and EnsureAsync write get mode 0600 through a chmod child process, which does not quote the path or check the exit code. No CI leg runs .NET Framework or Mono on Unix.

  • Each terminal connection allocates a 16 KiB receive buffer, reused across reads. The receiver also queues frames that nobody reads, so a slow or absent consumer can grow memory. See the terminal lifetime contract.

Developing

We appreciate contributions in the form of feedback, bug reports, and pull requests. Read CONTRIBUTING.md first β€” it has the full gate and the commit convention.

git clone --recurse-submodules https://github.com/opencode-dotnet/opencode-sdk-dotnet.git
cd opencode-sdk-dotnet
dotnet build --configuration Release

external/ holds read-only upstream submodules: protocol evidence, and the pinned server that the fixture-backed tests run. Those tests also need Bun, the pinned server's dependencies, and ripgrep; docs/engineering/quality-gates.md has the versions and the full completion gate.

tests/OpenCode.Sdk.Sandbox is a committed playground that drives the SDK against a real opencode serve under a debugger.

Community

Got questions or wild feature ideas?

πŸ‘‰ Open an issue β€” bug reports, questions, and proposals all land there for now.

Changelog

Please refer to CHANGELOG.md to see the complete list of changes for each release.

License

Licensed under MIT, see LICENSE for the full text. Content derived from upstream opencode carries its own notice in THIRD-PARTY-NOTICES.md.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  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. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 is compatible.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on OpenCodeDotNet.Sdk:

Package Downloads
OpenCodeDotNet.Sdk.Extensions

Dependency injection integration for the unofficial OpenCode .NET SDK, a typed client for the OpenCode 2.x server HTTP API (OpenCode 1.x servers are not supported): registers one singleton client and every sub-client from it. The package id is OpenCodeDotNet.Sdk.Extensions; the assembly and every namespace are OpenCode.Sdk.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.9.0-preview.6 0 10/4/2026
0.9.0-preview.5 56 9/29/2026
0.9.0-preview.4 51 9/27/2026
0.9.0-preview.3 59 9/24/2026