How to Use GitHub Copilot SDK with .NET: Complete Integration Guide for C#
The GitHub Copilot SDK enables .NET applications to communicate with the Copilot CLI runtime over JSON-RPC, providing strongly-typed C# objects like CopilotClient and CopilotSession to manage AI conversations, stream responses token-by-token, and execute custom tools without handling raw protocol details.
The GitHub Copilot SDK allows developers to embed GitHub Copilot's AI capabilities directly into .NET console applications and services using an idiomatic C# API. According to the github/copilot-sdk source code, the SDK manages the lifecycle of the Copilot CLI process and exposes high-level abstractions over the underlying JSON-RPC channel, letting you focus on building features rather than managing inter-process communication.
Core Components of the GitHub Copilot SDK for .NET
CopilotClient and Process Management
The CopilotClient class, implemented in dotnet/src/Client.cs, serves as the primary entry point for the SDK. When instantiated, it automatically starts or connects to a Copilot CLI process and establishes a JSON-RPC channel. The client provides server-scoped methods such as PingAsync and GetStatusAsync for health checks, and manages protocol version negotiation (enforcing a minimum version of 3 via MinProtocolVersion). You can optionally pass CopilotClientOptions to the constructor to specify an external CLI path or custom configuration.
Session Lifecycle and Event Model
A CopilotSession, defined in dotnet/src/Session.cs, represents a single conversation thread with the AI. You create sessions by calling CopilotClient.CreateSessionAsync, which internally invokes the private InitializeSession method around line 3600 in Client.cs to build the session object. Each session holds a unique identifier and exposes an event-driven architecture where all runtime events derive from SessionEvent. Subscribe to specific event types—such as AssistantMessageEvent for complete messages, AssistantMessageDeltaEvent for streaming tokens, or SessionIdleEvent for conversation state changes—using the generic handler session.On<SessionEvent>(...).
Custom Tool Registration with CopilotTool
To extend Copilot's capabilities, the SDK provides the CopilotTool helper class in dotnet/src/CopilotTool.cs. This utility transforms C# methods into ToolDefinition objects that the runtime understands. You define tools using CopilotTool.DefineTool or the AIFunctionFactory API, then register them in the SessionConfig.Tools collection. When the model decides to invoke a tool, the SDK routes the request to your handler and returns the result to the conversation.
Implementing the Integration Workflow
Building a functional integration requires six discrete steps that transition from client initialization to message exchange.
-
Client Construction: Instantiate
new CopilotClient()to spawn the CLI process. For custom configurations, supplyCopilotClientOptions. -
Session Creation: Call
await client.CreateSessionAsync(new SessionConfig { ... })to initialize a conversation. This method returns aCopilotSessionconfigured with your specified parameters. -
Permission Handling: Configure automatic tool approval by setting
OnPermissionRequesttoPermissionHandler.ApproveAll(or implement custom logic) within theSessionConfig. -
Message Exchange: Send prompts using
await session.SendAndWaitAsync(new MessageOptions { Prompt = "..." }). The method returns aMessageResponsewhereData.Contentcontains the assistant's text reply. -
Streaming Configuration: Enable real-time output by setting
Streaming = trueinSessionConfig. The SDK will emitAssistantMessageDeltaEventevents for each token chunk rather than buffering the complete response. -
Custom Tool Registration: Add tool definitions to
SessionConfig.Toolsbefore creating the session. The runtime automatically serializes these using the contracts defined indotnet/src/Generated/Rpc.csand invokes your handlers as needed.
Complete C# Implementation Examples
The following patterns demonstrate common usage scenarios extracted from dotnet/samples/Chat.cs and the core SDK implementation.
Basic Query with SendAndWaitAsync
For simple request-response interactions where you need a complete answer before proceeding, use the synchronous-style SendAndWaitAsync method.
using GitHub.Copilot;
await using var client = new CopilotClient();
await using var session = await client.CreateSessionAsync(new SessionConfig
{
Model = "gpt-4.1",
OnPermissionRequest = PermissionHandler.ApproveAll
});
var response = await session.SendAndWaitAsync(new MessageOptions { Prompt = "What is 2 + 2?" });
Console.WriteLine(response?.Data.Content);
This example demonstrates automatic CLI startup, session configuration with model selection, and direct access to the response content via Data.Content.
Real-Time Streaming with AssistantMessageDeltaEvent
For interactive applications requiring immediate feedback, enable streaming and subscribe to delta events.
using GitHub.Copilot;
await using var client = new CopilotClient();
await using var session = await client.CreateSessionAsync(new SessionConfig
{
Model = "gpt-4.1",
Streaming = true,
OnPermissionRequest = PermissionHandler.ApproveAll
});
session.On<SessionEvent>(ev =>
{
if (ev is AssistantMessageDeltaEvent delta)
Console.Write(delta.Data.DeltaContent);
else if (ev is SessionIdleEvent)
Console.WriteLine();
});
await session.SendAndWaitAsync(new MessageOptions { Prompt = "Tell me a short joke" });
Key implementation details include setting Streaming = true in the configuration and checking for SessionIdleEvent to detect when the stream concludes.
Extending Copilot with Custom Tools
Define domain-specific functions that the AI can invoke using the CopilotTool helper and AIFunctionFactory attributes.
using GitHub.Copilot;
using System.ComponentModel;
var getWeather = CopilotTool.DefineTool(
([Description("The city name")] string city) =>
{
var conditions = new[] { "sunny", "cloudy", "rainy", "partly cloudy" };
var temp = Random.Shared.Next(50, 80);
var condition = conditions[Random.Shared.Next(conditions.Length)];
return new { city, temperature = $"{temp}°F", condition };
},
factoryOptions: new AIFunctionFactoryOptions
{
Name = "get_weather",
Description = "Get the current weather for a city"
});
await using var client = new CopilotClient();
await using var session = await client.CreateSessionAsync(new SessionConfig
{
Model = "gpt-4.1",
Streaming = true,
OnPermissionRequest = PermissionHandler.ApproveAll,
Tools = [getWeather]
});
session.On<SessionEvent>(ev =>
{
if (ev is AssistantMessageDeltaEvent delta) Console.Write(delta.Data.DeltaContent);
else if (ev is SessionIdleEvent) Console.WriteLine();
});
await session.SendAndWaitAsync(new MessageOptions { Prompt = "What's the weather like in Seattle?" });
The [Description] attributes and AIFunctionFactoryOptions provide the runtime with the metadata necessary to construct the JSON-RPC ToolDefinition sent to the CLI.
JSON-RPC Protocol Abstraction
While the SDK abstracts the wire format, it operates over a JSON-RPC channel where the CopilotClient handles serialization details using contracts from dotnet/src/Generated/Rpc.cs. The implementation automatically negotiates the protocol version with the CLI runtime, requiring a minimum version of 3 as specified by the MinProtocolVersion constant in dotnet/src/Client.cs. This ensures compatibility while allowing the SDK to expose strongly-typed C# objects rather than raw JSON payloads.
Summary
- The
CopilotClientindotnet/src/Client.csmanages the CLI process lifecycle and JSON-RPC connection, handling protocol negotiation automatically. CopilotSessionrepresents a single conversation, exposing events likeAssistantMessageDeltaEventfor streaming andSessionIdleEventfor state detection.- Use
SendAndWaitAsyncwithMessageOptionsfor standard requests, or enableStreaming = trueinSessionConfigfor token-by-token output. - Define custom tools with
CopilotTool.DefineTool(located indotnet/src/CopilotTool.cs) and register them viaSessionConfig.Toolsto extend AI capabilities. - The SDK requires protocol version 3 or higher and abstracts all JSON-RPC communication through strongly-typed C# objects.
Frequently Asked Questions
How does the CopilotClient manage the CLI process lifecycle?
The CopilotClient constructor automatically spawns a Copilot CLI process if one is not already running, then establishes a JSON-RPC communication channel. According to dotnet/src/Client.cs, the client monitors the process health and provides methods like PingAsync and GetStatusAsync to verify connectivity.
What is the difference between AssistantMessageEvent and AssistantMessageDeltaEvent?
AssistantMessageEvent fires when the server has generated a complete response message, supplying the full text content. AssistantMessageDeltaEvent fires during streaming mode (Streaming = true), providing incremental token chunks via DeltaContent that can be displayed in real-time before the complete message is assembled.
How do I handle tool permission requests in the GitHub Copilot SDK?
Supply a permission handler delegate to the OnPermissionRequest property of SessionConfig. For development or trusted scenarios, use the built-in PermissionHandler.ApproveAll to automatically approve tool invocations, or implement custom logic to inspect the tool call and prompt the user for confirmation.
Where are the RPC contracts defined in the source code?
The auto-generated JSON-RPC request and response contracts—such as CreateSessionRequest and MessageResponse—are located in dotnet/src/Generated/Rpc.cs. These classes define the wire format used by CopilotClient to communicate with the CLI runtime, though you typically interact with the higher-level CopilotSession API instead.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →