# How to Use GitHub Copilot SDK with .NET: Complete Integration Guide for C#

> Integrate the GitHub Copilot SDK with .NET C# applications seamlessly. Use strongly-typed objects to manage AI conversations, stream responses, and execute custom tools effortlessly.

- Repository: [GitHub/copilot-sdk](https://github.com/github/copilot-sdk)
- Tags: how-to-guide
- Published: 2026-06-06

---

**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`](https://github.com/github/copilot-sdk/blob/main/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`](https://github.com/github/copilot-sdk/blob/main/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`](https://github.com/github/copilot-sdk/blob/main/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`](https://github.com/github/copilot-sdk/blob/main/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.

1. **Client Construction**: Instantiate `new CopilotClient()` to spawn the CLI process. For custom configurations, supply `CopilotClientOptions`.

2. **Session Creation**: Call `await client.CreateSessionAsync(new SessionConfig { ... })` to initialize a conversation. This method returns a `CopilotSession` configured with your specified parameters.

3. **Permission Handling**: Configure automatic tool approval by setting **`OnPermissionRequest`** to **`PermissionHandler.ApproveAll`** (or implement custom logic) within the `SessionConfig`.

4. **Message Exchange**: Send prompts using **`await session.SendAndWaitAsync(new MessageOptions { Prompt = "..." })`**. The method returns a `MessageResponse` where **`Data.Content`** contains the assistant's text reply.

5. **Streaming Configuration**: Enable real-time output by setting **`Streaming = true`** in `SessionConfig`. The SDK will emit `AssistantMessageDeltaEvent` events for each token chunk rather than buffering the complete response.

6. **Custom Tool Registration**: Add tool definitions to `SessionConfig.Tools` before creating the session. The runtime automatically serializes these using the contracts defined in [`dotnet/src/Generated/Rpc.cs`](https://github.com/github/copilot-sdk/blob/main/dotnet/src/Generated/Rpc.cs) and invokes your handlers as needed.

## Complete C# Implementation Examples

The following patterns demonstrate common usage scenarios extracted from [`dotnet/samples/Chat.cs`](https://github.com/github/copilot-sdk/blob/main/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.

```csharp
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.

```csharp
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.

```csharp
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`](https://github.com/github/copilot-sdk/blob/main/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`](https://github.com/github/copilot-sdk/blob/main/dotnet/src/Client.cs). This ensures compatibility while allowing the SDK to expose strongly-typed C# objects rather than raw JSON payloads.

## Summary

- The **`CopilotClient`** in [`dotnet/src/Client.cs`](https://github.com/github/copilot-sdk/blob/main/dotnet/src/Client.cs) manages the CLI process lifecycle and JSON-RPC connection, handling protocol negotiation automatically.
- **`CopilotSession`** represents a single conversation, exposing events like `AssistantMessageDeltaEvent` for streaming and `SessionIdleEvent` for state detection.
- Use **`SendAndWaitAsync`** with `MessageOptions` for standard requests, or enable `Streaming = true` in `SessionConfig` for token-by-token output.
- Define custom tools with **`CopilotTool.DefineTool`** (located in [`dotnet/src/CopilotTool.cs`](https://github.com/github/copilot-sdk/blob/main/dotnet/src/CopilotTool.cs)) and register them via `SessionConfig.Tools` to 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`](https://github.com/github/copilot-sdk/blob/main/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`](https://github.com/github/copilot-sdk/blob/main/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.