diff --git a/README.md b/README.md
index 461734f5..935f833a 100644
--- a/README.md
+++ b/README.md
@@ -21,6 +21,7 @@ Discover our curated collections of prompts, instructions, and agents organized
| Name | Description | Items | Tags |
| ---- | ----------- | ----- | ---- |
| [Awesome Copilot](collections/awesome-copilot.md) | Meta prompts that help you discover and generate curated GitHub Copilot chat modes, collections, instructions, prompts, and agents. | 6 items | github-copilot, discovery, meta, prompt-engineering, agents |
+| [Copilot SDK](collections/copilot-sdk.md) | Build applications with the GitHub Copilot SDK across multiple programming languages. Includes comprehensive instructions for C#, Go, Node.js/TypeScript, and Python to help you create AI-powered applications. | 4 items | copilot-sdk, sdk, csharp, go, nodejs, typescript, python, ai, github-copilot |
| [Partners](collections/partners.md) | Custom agents that have been created by GitHub partners | 20 items | devops, security, database, cloud, infrastructure, observability, feature-flags, cicd, migration, performance |
diff --git a/collections/copilot-sdk.collection.yml b/collections/copilot-sdk.collection.yml
new file mode 100644
index 00000000..1f1b534a
--- /dev/null
+++ b/collections/copilot-sdk.collection.yml
@@ -0,0 +1,17 @@
+id: copilot-sdk
+name: Copilot SDK
+description: Build applications with the GitHub Copilot SDK across multiple programming languages. Includes comprehensive instructions for C#, Go, Node.js/TypeScript, and Python to help you create AI-powered applications.
+tags: [copilot-sdk, sdk, csharp, go, nodejs, typescript, python, ai, github-copilot]
+items:
+ - path: instructions/copilot-sdk-csharp.instructions.md
+ kind: instruction
+ - path: instructions/copilot-sdk-go.instructions.md
+ kind: instruction
+ - path: instructions/copilot-sdk-nodejs.instructions.md
+ kind: instruction
+ - path: instructions/copilot-sdk-python.instructions.md
+ kind: instruction
+display:
+ ordering: manual
+ show_badge: true
+ featured: true
diff --git a/collections/copilot-sdk.md b/collections/copilot-sdk.md
new file mode 100644
index 00000000..c5fa1fac
--- /dev/null
+++ b/collections/copilot-sdk.md
@@ -0,0 +1,17 @@
+# Copilot SDK
+
+Build applications with the GitHub Copilot SDK across multiple programming languages. Includes comprehensive instructions for C#, Go, Node.js/TypeScript, and Python to help you create AI-powered applications.
+
+**Tags:** copilot-sdk, sdk, csharp, go, nodejs, typescript, python, ai, github-copilot
+
+## Items in this Collection
+
+| Title | Type | Description |
+| ----- | ---- | ----------- |
+| [GitHub Copilot SDK C# Instructions](../instructions/copilot-sdk-csharp.instructions.md)
[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fcopilot-sdk-csharp.instructions.md)
[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fcopilot-sdk-csharp.instructions.md) | Instruction | This file provides guidance on building C# applications using GitHub Copilot SDK. |
+| [GitHub Copilot SDK Go Instructions](../instructions/copilot-sdk-go.instructions.md)
[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fcopilot-sdk-go.instructions.md)
[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fcopilot-sdk-go.instructions.md) | Instruction | This file provides guidance on building Go applications using GitHub Copilot SDK. |
+| [GitHub Copilot SDK Node.js Instructions](../instructions/copilot-sdk-nodejs.instructions.md)
[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fcopilot-sdk-nodejs.instructions.md)
[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fcopilot-sdk-nodejs.instructions.md) | Instruction | This file provides guidance on building Node.js/TypeScript applications using GitHub Copilot SDK. |
+| [GitHub Copilot SDK Python Instructions](../instructions/copilot-sdk-python.instructions.md)
[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fcopilot-sdk-python.instructions.md)
[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fcopilot-sdk-python.instructions.md) | Instruction | This file provides guidance on building Python applications using GitHub Copilot SDK. |
+
+---
+*This collection includes 4 curated items for **Copilot SDK**.*
\ No newline at end of file
diff --git a/docs/README.collections.md b/docs/README.collections.md
index 02f29460..9785b4ab 100644
--- a/docs/README.collections.md
+++ b/docs/README.collections.md
@@ -17,6 +17,7 @@ Curated collections of related prompts, instructions, and agents organized aroun
| Name | Description | Items | Tags |
| ---- | ----------- | ----- | ---- |
| [⭐ Awesome Copilot](../collections/awesome-copilot.md) | Meta prompts that help you discover and generate curated GitHub Copilot chat modes, collections, instructions, prompts, and agents. | 6 items | github-copilot, discovery, meta, prompt-engineering, agents |
+| [⭐ Copilot SDK](../collections/copilot-sdk.md) | Build applications with the GitHub Copilot SDK across multiple programming languages. Includes comprehensive instructions for C#, Go, Node.js/TypeScript, and Python to help you create AI-powered applications. | 4 items | copilot-sdk, sdk, csharp, go, nodejs, typescript, python, ai, github-copilot |
| [⭐ Partners](../collections/partners.md) | Custom agents that have been created by GitHub partners | 20 items | devops, security, database, cloud, infrastructure, observability, feature-flags, cicd, migration, performance |
| [Azure & Cloud Development](../collections/azure-cloud-development.md) | Comprehensive Azure cloud development tools including Infrastructure as Code, serverless functions, architecture patterns, and cost optimization for building scalable cloud applications. | 18 items | azure, cloud, infrastructure, bicep, terraform, serverless, architecture, devops |
| [C# .NET Development](../collections/csharp-dotnet-development.md) | Essential prompts, instructions, and chat modes for C# and .NET development including testing, documentation, and best practices. | 8 items | csharp, dotnet, aspnet, testing |
diff --git a/docs/README.instructions.md b/docs/README.instructions.md
index 4574b3d5..ab17703c 100644
--- a/docs/README.instructions.md
+++ b/docs/README.instructions.md
@@ -82,6 +82,10 @@ Team and project-specific instructions to enhance GitHub Copilot's behavior for
| [Get Tooling for Power Apps Component Framework](../instructions/pcf-tooling.instructions.md)
[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fpcf-tooling.instructions.md)
[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fpcf-tooling.instructions.md) | Get Microsoft Power Platform CLI tooling for Power Apps Component Framework |
| [Gilfoyle Code Review Instructions](../instructions/gilfoyle-code-review.instructions.md)
[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fgilfoyle-code-review.instructions.md)
[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fgilfoyle-code-review.instructions.md) | Gilfoyle-style code review instructions that channel the sardonic technical supremacy of Silicon Valley's most arrogant systems architect. |
| [GitHub Actions CI/CD Best Practices](../instructions/github-actions-ci-cd-best-practices.instructions.md)
[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fgithub-actions-ci-cd-best-practices.instructions.md)
[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fgithub-actions-ci-cd-best-practices.instructions.md) | Comprehensive guide for building robust, secure, and efficient CI/CD pipelines using GitHub Actions. Covers workflow structure, jobs, steps, environment variables, secret management, caching, matrix strategies, testing, and deployment strategies. |
+| [GitHub Copilot SDK C# Instructions](../instructions/copilot-sdk-csharp.instructions.md)
[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fcopilot-sdk-csharp.instructions.md)
[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fcopilot-sdk-csharp.instructions.md) | This file provides guidance on building C# applications using GitHub Copilot SDK. |
+| [GitHub Copilot SDK Go Instructions](../instructions/copilot-sdk-go.instructions.md)
[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fcopilot-sdk-go.instructions.md)
[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fcopilot-sdk-go.instructions.md) | This file provides guidance on building Go applications using GitHub Copilot SDK. |
+| [GitHub Copilot SDK Node.js Instructions](../instructions/copilot-sdk-nodejs.instructions.md)
[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fcopilot-sdk-nodejs.instructions.md)
[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fcopilot-sdk-nodejs.instructions.md) | This file provides guidance on building Node.js/TypeScript applications using GitHub Copilot SDK. |
+| [GitHub Copilot SDK Python Instructions](../instructions/copilot-sdk-python.instructions.md)
[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fcopilot-sdk-python.instructions.md)
[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fcopilot-sdk-python.instructions.md) | This file provides guidance on building Python applications using GitHub Copilot SDK. |
| [Go Development Instructions](../instructions/go.instructions.md)
[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fgo.instructions.md)
[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fgo.instructions.md) | Instructions for writing Go code following idiomatic Go practices and community standards |
| [Go MCP Server Development Guidelines](../instructions/go-mcp-server.instructions.md)
[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fgo-mcp-server.instructions.md)
[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fgo-mcp-server.instructions.md) | Best practices and patterns for building Model Context Protocol (MCP) servers in Go using the official github.com/modelcontextprotocol/go-sdk package. |
| [Guidance for Localization](../instructions/localization.instructions.md)
[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Flocalization.instructions.md)
[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Flocalization.instructions.md) | Guidelines for localizing markdown documents |
diff --git a/instructions/copilot-sdk-csharp.instructions.md b/instructions/copilot-sdk-csharp.instructions.md
new file mode 100644
index 00000000..87d04b82
--- /dev/null
+++ b/instructions/copilot-sdk-csharp.instructions.md
@@ -0,0 +1,550 @@
+---
+applyTo: '**.cs, **.csproj'
+description: 'This file provides guidance on building C# applications using GitHub Copilot SDK.'
+name: 'GitHub Copilot SDK C# Instructions'
+---
+
+## Core Principles
+
+- The SDK is in technical preview and may have breaking changes
+- Requires .NET 10.0 or later
+- Requires GitHub Copilot CLI installed and in PATH
+- Uses async/await patterns throughout
+- Implements IAsyncDisposable for resource cleanup
+
+## Installation
+
+Always install via NuGet:
+```bash
+dotnet add package GitHub.Copilot.SDK
+```
+
+## Client Initialization
+
+### Basic Client Setup
+
+```csharp
+await using var client = new CopilotClient();
+await client.StartAsync();
+```
+
+### Client Configuration Options
+
+When creating a CopilotClient, use `CopilotClientOptions`:
+
+- `CliPath` - Path to CLI executable (default: "copilot" from PATH)
+- `CliArgs` - Extra arguments prepended before SDK-managed flags
+- `CliUrl` - URL of existing CLI server (e.g., "localhost:8080"). When provided, client won't spawn a process
+- `Port` - Server port (default: 0 for random)
+- `UseStdio` - Use stdio transport instead of TCP (default: true)
+- `LogLevel` - Log level (default: "info")
+- `AutoStart` - Auto-start server (default: true)
+- `AutoRestart` - Auto-restart on crash (default: true)
+- `Cwd` - Working directory for the CLI process
+- `Environment` - Environment variables for the CLI process
+- `Logger` - ILogger instance for SDK logging
+
+### Manual Server Control
+
+For explicit control:
+```csharp
+var client = new CopilotClient(new CopilotClientOptions { AutoStart = false });
+await client.StartAsync();
+// Use client...
+await client.StopAsync();
+```
+
+Use `ForceStopAsync()` when `StopAsync()` takes too long.
+
+## Session Management
+
+### Creating Sessions
+
+Use `SessionConfig` for configuration:
+
+```csharp
+await using var session = await client.CreateSessionAsync(new SessionConfig
+{
+ Model = "gpt-5",
+ Streaming = true,
+ Tools = [...],
+ SystemMessage = new SystemMessageConfig { ... },
+ AvailableTools = ["tool1", "tool2"],
+ ExcludedTools = ["tool3"],
+ Provider = new ProviderConfig { ... }
+});
+```
+
+### Session Config Options
+
+- `SessionId` - Custom session ID
+- `Model` - Model name ("gpt-5", "claude-sonnet-4.5", etc.)
+- `Tools` - Custom tools exposed to the CLI
+- `SystemMessage` - System message customization
+- `AvailableTools` - Allowlist of tool names
+- `ExcludedTools` - Blocklist of tool names
+- `Provider` - Custom API provider configuration (BYOK)
+- `Streaming` - Enable streaming response chunks (default: false)
+
+### Resuming Sessions
+
+```csharp
+var session = await client.ResumeSessionAsync(sessionId, new ResumeSessionConfig { ... });
+```
+
+### Session Operations
+
+- `session.SessionId` - Get session identifier
+- `session.SendAsync(new MessageOptions { Prompt = "...", Attachments = [...] })` - Send message
+- `session.AbortAsync()` - Abort current processing
+- `session.GetMessagesAsync()` - Get all events/messages
+- `await session.DisposeAsync()` - Clean up resources
+
+## Event Handling
+
+### Event Subscription Pattern
+
+ALWAYS use TaskCompletionSource for waiting on session events:
+
+```csharp
+var done = new TaskCompletionSource();
+
+session.On(evt =>
+{
+ if (evt is AssistantMessageEvent msg)
+ {
+ Console.WriteLine(msg.Data.Content);
+ }
+ else if (evt is SessionIdleEvent)
+ {
+ done.SetResult();
+ }
+});
+
+await session.SendAsync(new MessageOptions { Prompt = "..." });
+await done.Task;
+```
+
+### Unsubscribing from Events
+
+The `On()` method returns an IDisposable:
+
+```csharp
+var subscription = session.On(evt => { /* handler */ });
+// Later...
+subscription.Dispose();
+```
+
+### Event Types
+
+Use pattern matching or switch expressions for event handling:
+
+```csharp
+session.On(evt =>
+{
+ switch (evt)
+ {
+ case UserMessageEvent userMsg:
+ // Handle user message
+ break;
+ case AssistantMessageEvent assistantMsg:
+ Console.WriteLine(assistantMsg.Data.Content);
+ break;
+ case ToolExecutionStartEvent toolStart:
+ // Tool execution started
+ break;
+ case ToolExecutionCompleteEvent toolComplete:
+ // Tool execution completed
+ break;
+ case SessionStartEvent start:
+ // Session started
+ break;
+ case SessionIdleEvent idle:
+ // Session is idle (processing complete)
+ break;
+ case SessionErrorEvent error:
+ Console.WriteLine($"Error: {error.Data.Message}");
+ break;
+ }
+});
+```
+
+## Streaming Responses
+
+### Enabling Streaming
+
+Set `Streaming = true` in SessionConfig:
+
+```csharp
+var session = await client.CreateSessionAsync(new SessionConfig
+{
+ Model = "gpt-5",
+ Streaming = true
+});
+```
+
+### Handling Streaming Events
+
+Handle both delta events (incremental) and final events:
+
+```csharp
+var done = new TaskCompletionSource();
+
+session.On(evt =>
+{
+ switch (evt)
+ {
+ case AssistantMessageDeltaEvent delta:
+ // Incremental text chunk
+ Console.Write(delta.Data.DeltaContent);
+ break;
+ case AssistantReasoningDeltaEvent reasoningDelta:
+ // Incremental reasoning chunk (model-dependent)
+ Console.Write(reasoningDelta.Data.DeltaContent);
+ break;
+ case AssistantMessageEvent msg:
+ // Final complete message
+ Console.WriteLine("\n--- Final ---");
+ Console.WriteLine(msg.Data.Content);
+ break;
+ case AssistantReasoningEvent reasoning:
+ // Final reasoning content
+ Console.WriteLine("--- Reasoning ---");
+ Console.WriteLine(reasoning.Data.Content);
+ break;
+ case SessionIdleEvent:
+ done.SetResult();
+ break;
+ }
+});
+
+await session.SendAsync(new MessageOptions { Prompt = "Tell me a story" });
+await done.Task;
+```
+
+Note: Final events (`AssistantMessageEvent`, `AssistantReasoningEvent`) are ALWAYS sent regardless of streaming setting.
+
+## Custom Tools
+
+### Defining Tools with AIFunctionFactory
+
+Use `Microsoft.Extensions.AI.AIFunctionFactory.Create` for type-safe tools:
+
+```csharp
+using Microsoft.Extensions.AI;
+using System.ComponentModel;
+
+var session = await client.CreateSessionAsync(new SessionConfig
+{
+ Model = "gpt-5",
+ Tools = [
+ AIFunctionFactory.Create(
+ async ([Description("Issue ID")] string id) => {
+ var issue = await FetchIssueAsync(id);
+ return issue;
+ },
+ "lookup_issue",
+ "Fetch issue details from tracker"),
+ ]
+});
+```
+
+### Tool Return Types
+
+- Return any JSON-serializable value (automatically wrapped)
+- Or return `ToolResultAIContent` wrapping `ToolResultObject` for full control over metadata
+
+### Tool Execution Flow
+
+When Copilot invokes a tool, the client automatically:
+1. Runs your handler function
+2. Serializes the return value
+3. Responds to the CLI
+
+## System Message Customization
+
+### Append Mode (Default - Preserves Guardrails)
+
+```csharp
+var session = await client.CreateSessionAsync(new SessionConfig
+{
+ Model = "gpt-5",
+ SystemMessage = new SystemMessageConfig
+ {
+ Mode = SystemMessageMode.Append,
+ Content = @"
+
+- Always check for security vulnerabilities
+- Suggest performance improvements when applicable
+
+"
+ }
+});
+```
+
+### Replace Mode (Full Control - Removes Guardrails)
+
+```csharp
+var session = await client.CreateSessionAsync(new SessionConfig
+{
+ Model = "gpt-5",
+ SystemMessage = new SystemMessageConfig
+ {
+ Mode = SystemMessageMode.Replace,
+ Content = "You are a helpful assistant."
+ }
+});
+```
+
+## File Attachments
+
+Attach files to messages using `UserMessageDataAttachmentsItem`:
+
+```csharp
+await session.SendAsync(new MessageOptions
+{
+ Prompt = "Analyze this file",
+ Attachments = new List
+ {
+ new UserMessageDataAttachmentsItem
+ {
+ Type = UserMessageDataAttachmentsItemType.File,
+ Path = "/path/to/file.cs",
+ DisplayName = "My File"
+ }
+ }
+});
+```
+
+## Message Delivery Modes
+
+Use the `Mode` property in `MessageOptions`:
+
+- `"enqueue"` - Queue message for processing
+- `"immediate"` - Process message immediately
+
+```csharp
+await session.SendAsync(new MessageOptions
+{
+ Prompt = "...",
+ Mode = "enqueue"
+});
+```
+
+## Multiple Sessions
+
+Sessions are independent and can run concurrently:
+
+```csharp
+var session1 = await client.CreateSessionAsync(new SessionConfig { Model = "gpt-5" });
+var session2 = await client.CreateSessionAsync(new SessionConfig { Model = "claude-sonnet-4.5" });
+
+await session1.SendAsync(new MessageOptions { Prompt = "Hello from session 1" });
+await session2.SendAsync(new MessageOptions { Prompt = "Hello from session 2" });
+```
+
+## Bring Your Own Key (BYOK)
+
+Use custom API providers via `ProviderConfig`:
+
+```csharp
+var session = await client.CreateSessionAsync(new SessionConfig
+{
+ Provider = new ProviderConfig
+ {
+ Type = "openai",
+ BaseUrl = "https://api.openai.com/v1",
+ ApiKey = "your-api-key"
+ }
+});
+```
+
+## Session Lifecycle Management
+
+### Listing Sessions
+
+```csharp
+var sessions = await client.ListSessionsAsync();
+foreach (var metadata in sessions)
+{
+ Console.WriteLine($"Session: {metadata.SessionId}");
+}
+```
+
+### Deleting Sessions
+
+```csharp
+await client.DeleteSessionAsync(sessionId);
+```
+
+### Checking Connection State
+
+```csharp
+var state = client.State;
+```
+
+## Error Handling
+
+### Standard Exception Handling
+
+```csharp
+try
+{
+ var session = await client.CreateSessionAsync();
+ await session.SendAsync(new MessageOptions { Prompt = "Hello" });
+}
+catch (StreamJsonRpc.RemoteInvocationException ex)
+{
+ Console.Error.WriteLine($"JSON-RPC Error: {ex.Message}");
+}
+catch (Exception ex)
+{
+ Console.Error.WriteLine($"Error: {ex.Message}");
+}
+```
+
+### Session Error Events
+
+Monitor `SessionErrorEvent` for runtime errors:
+
+```csharp
+session.On(evt =>
+{
+ if (evt is SessionErrorEvent error)
+ {
+ Console.Error.WriteLine($"Session Error: {error.Data.Message}");
+ }
+});
+```
+
+## Connectivity Testing
+
+Use PingAsync to verify server connectivity:
+
+```csharp
+var response = await client.PingAsync("test message");
+```
+
+## Resource Cleanup
+
+### Automatic Cleanup with Using
+
+ALWAYS use `await using` for automatic disposal:
+
+```csharp
+await using var client = new CopilotClient();
+await using var session = await client.CreateSessionAsync();
+// Resources automatically cleaned up
+```
+
+### Manual Cleanup
+
+If not using `await using`:
+
+```csharp
+var client = new CopilotClient();
+try
+{
+ await client.StartAsync();
+ // Use client...
+}
+finally
+{
+ await client.StopAsync();
+}
+```
+
+## Best Practices
+
+1. **Always use `await using`** for CopilotClient and CopilotSession
+2. **Use TaskCompletionSource** to wait for SessionIdleEvent
+3. **Handle SessionErrorEvent** for robust error handling
+4. **Use pattern matching** (switch expressions) for event handling
+5. **Enable streaming** for better UX in interactive scenarios
+6. **Use AIFunctionFactory** for type-safe tool definitions
+7. **Dispose event subscriptions** when no longer needed
+8. **Use SystemMessageMode.Append** to preserve safety guardrails
+9. **Provide descriptive tool names and descriptions** for better model understanding
+10. **Handle both delta and final events** when streaming is enabled
+
+## Common Patterns
+
+### Simple Query-Response
+
+```csharp
+await using var client = new CopilotClient();
+await client.StartAsync();
+
+await using var session = await client.CreateSessionAsync(new SessionConfig
+{
+ Model = "gpt-5"
+});
+
+var done = new TaskCompletionSource();
+
+session.On(evt =>
+{
+ if (evt is AssistantMessageEvent msg)
+ {
+ Console.WriteLine(msg.Data.Content);
+ }
+ else if (evt is SessionIdleEvent)
+ {
+ done.SetResult();
+ }
+});
+
+await session.SendAsync(new MessageOptions { Prompt = "What is 2+2?" });
+await done.Task;
+```
+
+### Multi-Turn Conversation
+
+```csharp
+await using var session = await client.CreateSessionAsync();
+
+async Task SendAndWait(string prompt)
+{
+ var done = new TaskCompletionSource();
+ var subscription = session.On(evt =>
+ {
+ if (evt is AssistantMessageEvent msg)
+ {
+ Console.WriteLine(msg.Data.Content);
+ }
+ else if (evt is SessionIdleEvent)
+ {
+ done.SetResult();
+ }
+ });
+
+ await session.SendAsync(new MessageOptions { Prompt = prompt });
+ await done.Task;
+ subscription.Dispose();
+}
+
+await SendAndWait("What is the capital of France?");
+await SendAndWait("What is its population?");
+```
+
+### Tool with Complex Return Type
+
+```csharp
+var session = await client.CreateSessionAsync(new SessionConfig
+{
+ Tools = [
+ AIFunctionFactory.Create(
+ ([Description("User ID")] string userId) => {
+ return new {
+ Id = userId,
+ Name = "John Doe",
+ Email = "john@example.com",
+ Role = "Developer"
+ };
+ },
+ "get_user",
+ "Retrieve user information")
+ ]
+});
+```
+
diff --git a/instructions/copilot-sdk-go.instructions.md b/instructions/copilot-sdk-go.instructions.md
new file mode 100644
index 00000000..b8741721
--- /dev/null
+++ b/instructions/copilot-sdk-go.instructions.md
@@ -0,0 +1,626 @@
+---
+applyTo: "**.go, go.mod"
+description: "This file provides guidance on building Go applications using GitHub Copilot SDK."
+name: "GitHub Copilot SDK Go Instructions"
+---
+
+## Core Principles
+
+- The SDK is in technical preview and may have breaking changes
+- Requires Go 1.21 or later
+- Requires GitHub Copilot CLI installed and in PATH
+- Uses goroutines and channels for concurrent operations
+- No external dependencies beyond the standard library
+
+## Installation
+
+Always install via Go modules:
+
+```bash
+go get github.com/github/copilot-sdk/go
+```
+
+## Client Initialization
+
+### Basic Client Setup
+
+```go
+import "github.com/github/copilot-sdk/go"
+
+client := copilot.NewClient(nil)
+if err := client.Start(); err != nil {
+ log.Fatal(err)
+}
+defer client.Stop()
+```
+
+### Client Configuration Options
+
+When creating a CopilotClient, use `ClientOptions`:
+
+- `CLIPath` - Path to CLI executable (default: "copilot" from PATH)
+- `CLIUrl` - URL of existing CLI server (e.g., "localhost:8080"). When provided, client won't spawn a process
+- `Port` - Server port (default: 0 for random)
+- `UseStdio` - Use stdio transport instead of TCP (default: true)
+- `LogLevel` - Log level (default: "info")
+- `AutoStart` - Auto-start server (default: true, use pointer: `boolPtr(true)`)
+- `AutoRestart` - Auto-restart on crash (default: true, use pointer: `boolPtr(true)`)
+- `Cwd` - Working directory for the CLI process
+- `Env` - Environment variables for the CLI process ([]string)
+
+### Manual Server Control
+
+For explicit control:
+
+```go
+autoStart := false
+client := copilot.NewClient(&copilot.ClientOptions{AutoStart: &autoStart})
+if err := client.Start(); err != nil {
+ log.Fatal(err)
+}
+// Use client...
+client.Stop()
+```
+
+Use `ForceStop()` when `Stop()` takes too long.
+
+## Session Management
+
+### Creating Sessions
+
+Use `SessionConfig` for configuration:
+
+```go
+session, err := client.CreateSession(&copilot.SessionConfig{
+ Model: "gpt-5",
+ Streaming: true,
+ Tools: []copilot.Tool{...},
+ SystemMessage: &copilot.SystemMessageConfig{ ... },
+ AvailableTools: []string{"tool1", "tool2"},
+ ExcludedTools: []string{"tool3"},
+ Provider: &copilot.ProviderConfig{ ... },
+})
+if err != nil {
+ log.Fatal(err)
+}
+```
+
+### Session Config Options
+
+- `SessionID` - Custom session ID
+- `Model` - Model name ("gpt-5", "claude-sonnet-4.5", etc.)
+- `Tools` - Custom tools exposed to the CLI ([]Tool)
+- `SystemMessage` - System message customization (\*SystemMessageConfig)
+- `AvailableTools` - Allowlist of tool names ([]string)
+- `ExcludedTools` - Blocklist of tool names ([]string)
+- `Provider` - Custom API provider configuration (BYOK) (\*ProviderConfig)
+- `Streaming` - Enable streaming response chunks (bool)
+- `MCPServers` - MCP server configurations
+- `CustomAgents` - Custom agent configurations
+- `ConfigDir` - Config directory override
+- `SkillDirectories` - Skill directories ([]string)
+- `DisabledSkills` - Disabled skills ([]string)
+
+### Resuming Sessions
+
+```go
+session, err := client.ResumeSession("session-id")
+// Or with options:
+session, err := client.ResumeSessionWithOptions("session-id", &copilot.ResumeSessionConfig{ ... })
+```
+
+### Session Operations
+
+- `session.SessionID` - Get session identifier (string)
+- `session.Send(copilot.MessageOptions{Prompt: "...", Attachments: []copilot.Attachment{...}})` - Send message, returns (messageID string, error)
+- `session.SendAndWait(options, timeout)` - Send and wait for idle, returns (\*SessionEvent, error)
+- `session.Abort()` - Abort current processing, returns error
+- `session.GetMessages()` - Get all events/messages, returns ([]SessionEvent, error)
+- `session.Destroy()` - Clean up session, returns error
+
+## Event Handling
+
+### Event Subscription Pattern
+
+ALWAYS use channels or done signals for waiting on session events:
+
+```go
+done := make(chan struct{})
+
+unsubscribe := session.On(func(evt copilot.SessionEvent) {
+ switch evt.Type {
+ case copilot.AssistantMessage:
+ fmt.Println(*evt.Data.Content)
+ case copilot.SessionIdle:
+ close(done)
+ }
+})
+defer unsubscribe()
+
+session.Send(copilot.MessageOptions{Prompt: "..."})
+<-done
+```
+
+### Unsubscribing from Events
+
+The `On()` method returns a function that unsubscribes:
+
+```go
+unsubscribe := session.On(func(evt copilot.SessionEvent) {
+ // handler
+})
+// Later...
+unsubscribe()
+```
+
+### Event Types
+
+Use type switches for event handling:
+
+```go
+session.On(func(evt copilot.SessionEvent) {
+ switch evt.Type {
+ case copilot.UserMessage:
+ // Handle user message
+ case copilot.AssistantMessage:
+ if evt.Data.Content != nil {
+ fmt.Println(*evt.Data.Content)
+ }
+ case copilot.ToolExecutionStart:
+ // Tool execution started
+ case copilot.ToolExecutionComplete:
+ // Tool execution completed
+ case copilot.SessionStart:
+ // Session started
+ case copilot.SessionIdle:
+ // Session is idle (processing complete)
+ case copilot.SessionError:
+ if evt.Data.Message != nil {
+ fmt.Println("Error:", *evt.Data.Message)
+ }
+ }
+})
+```
+
+## Streaming Responses
+
+### Enabling Streaming
+
+Set `Streaming: true` in SessionConfig:
+
+```go
+session, err := client.CreateSession(&copilot.SessionConfig{
+ Model: "gpt-5",
+ Streaming: true,
+})
+```
+
+### Handling Streaming Events
+
+Handle both delta events (incremental) and final events:
+
+```go
+done := make(chan struct{})
+
+session.On(func(evt copilot.SessionEvent) {
+ switch evt.Type {
+ case copilot.AssistantMessageDelta:
+ // Incremental text chunk
+ if evt.Data.DeltaContent != nil {
+ fmt.Print(*evt.Data.DeltaContent)
+ }
+ case copilot.AssistantReasoningDelta:
+ // Incremental reasoning chunk (model-dependent)
+ if evt.Data.DeltaContent != nil {
+ fmt.Print(*evt.Data.DeltaContent)
+ }
+ case copilot.AssistantMessage:
+ // Final complete message
+ fmt.Println("\n--- Final ---")
+ if evt.Data.Content != nil {
+ fmt.Println(*evt.Data.Content)
+ }
+ case copilot.AssistantReasoning:
+ // Final reasoning content
+ fmt.Println("--- Reasoning ---")
+ if evt.Data.Content != nil {
+ fmt.Println(*evt.Data.Content)
+ }
+ case copilot.SessionIdle:
+ close(done)
+ }
+})
+
+session.Send(copilot.MessageOptions{Prompt: "Tell me a story"})
+<-done
+```
+
+Note: Final events (`AssistantMessage`, `AssistantReasoning`) are ALWAYS sent regardless of streaming setting.
+
+## Custom Tools
+
+### Defining Tools
+
+```go
+session, err := client.CreateSession(&copilot.SessionConfig{
+ Model: "gpt-5",
+ Tools: []copilot.Tool{
+ {
+ Name: "lookup_issue",
+ Description: "Fetch issue details from tracker",
+ Parameters: map[string]interface{}{
+ "type": "object",
+ "properties": map[string]interface{}{
+ "id": map[string]interface{}{
+ "type": "string",
+ "description": "Issue ID",
+ },
+ },
+ "required": []string{"id"},
+ },
+ Handler: func(inv copilot.ToolInvocation) (copilot.ToolResult, error) {
+ args := inv.Arguments.(map[string]interface{})
+ issueID := args["id"].(string)
+
+ issue, err := fetchIssue(issueID)
+ if err != nil {
+ return copilot.ToolResult{}, err
+ }
+
+ return copilot.ToolResult{
+ TextResultForLLM: fmt.Sprintf("Issue: %v", issue),
+ ResultType: "success",
+ ToolTelemetry: map[string]interface{}{},
+ }, nil
+ },
+ },
+ },
+})
+```
+
+### Tool Return Types
+
+- Return `ToolResult` struct with fields:
+ - `TextResultForLLM` (string) - Result text for the LLM
+ - `ResultType` (string) - "success" or "failure"
+ - `Error` (string, optional) - Internal error message (not shown to LLM)
+ - `ToolTelemetry` (map[string]interface{}) - Telemetry data
+
+### Tool Execution Flow
+
+When Copilot invokes a tool, the client automatically:
+
+1. Runs your handler function
+2. Returns the ToolResult
+3. Responds to the CLI
+
+## System Message Customization
+
+### Append Mode (Default - Preserves Guardrails)
+
+```go
+session, err := client.CreateSession(&copilot.SessionConfig{
+ Model: "gpt-5",
+ SystemMessage: &copilot.SystemMessageConfig{
+ Mode: "append",
+ Content: `
+
+- Always check for security vulnerabilities
+- Suggest performance improvements when applicable
+
+`,
+ },
+})
+```
+
+### Replace Mode (Full Control - Removes Guardrails)
+
+```go
+session, err := client.CreateSession(&copilot.SessionConfig{
+ Model: "gpt-5",
+ SystemMessage: &copilot.SystemMessageConfig{
+ Mode: "replace",
+ Content: "You are a helpful assistant.",
+ },
+})
+```
+
+## File Attachments
+
+Attach files to messages using `Attachment`:
+
+```go
+messageID, err := session.Send(copilot.MessageOptions{
+ Prompt: "Analyze this file",
+ Attachments: []copilot.Attachment{
+ {
+ Type: "file",
+ Path: "/path/to/file.go",
+ DisplayName: "My File",
+ },
+ },
+})
+```
+
+## Message Delivery Modes
+
+Use the `Mode` field in `MessageOptions`:
+
+- `"enqueue"` - Queue message for processing
+- `"immediate"` - Process message immediately
+
+```go
+session.Send(copilot.MessageOptions{
+ Prompt: "...",
+ Mode: "enqueue",
+})
+```
+
+## Multiple Sessions
+
+Sessions are independent and can run concurrently:
+
+```go
+session1, _ := client.CreateSession(&copilot.SessionConfig{Model: "gpt-5"})
+session2, _ := client.CreateSession(&copilot.SessionConfig{Model: "claude-sonnet-4.5"})
+
+session1.Send(copilot.MessageOptions{Prompt: "Hello from session 1"})
+session2.Send(copilot.MessageOptions{Prompt: "Hello from session 2"})
+```
+
+## Bring Your Own Key (BYOK)
+
+Use custom API providers via `ProviderConfig`:
+
+```go
+session, err := client.CreateSession(&copilot.SessionConfig{
+ Provider: &copilot.ProviderConfig{
+ Type: "openai",
+ BaseURL: "https://api.openai.com/v1",
+ APIKey: "your-api-key",
+ },
+})
+```
+
+## Session Lifecycle Management
+
+### Checking Connection State
+
+```go
+state := client.GetState()
+// Returns: "disconnected", "connecting", "connected", or "error"
+```
+
+## Error Handling
+
+### Standard Exception Handling
+
+```go
+session, err := client.CreateSession(&copilot.SessionConfig{})
+if err != nil {
+ log.Fatalf("Failed to create session: %v", err)
+}
+
+_, err = session.Send(copilot.MessageOptions{Prompt: "Hello"})
+if err != nil {
+ log.Printf("Failed to send: %v", err)
+}
+```
+
+### Session Error Events
+
+Monitor `SessionError` type for runtime errors:
+
+```go
+session.On(func(evt copilot.SessionEvent) {
+ if evt.Type == copilot.SessionError {
+ if evt.Data.Message != nil {
+ fmt.Fprintf(os.Stderr, "Session Error: %s\n", *evt.Data.Message)
+ }
+ }
+})
+```
+
+## Connectivity Testing
+
+Use Ping to verify server connectivity:
+
+```go
+resp, err := client.Ping("test message")
+if err != nil {
+ log.Printf("Server unreachable: %v", err)
+} else {
+ log.Printf("Server responded at %d", resp.Timestamp)
+}
+```
+
+## Resource Cleanup
+
+### Cleanup with Defer
+
+ALWAYS use `defer` for cleanup:
+
+```go
+client := copilot.NewClient(nil)
+if err := client.Start(); err != nil {
+ log.Fatal(err)
+}
+defer client.Stop()
+
+session, err := client.CreateSession(nil)
+if err != nil {
+ log.Fatal(err)
+}
+defer session.Destroy()
+```
+
+### Manual Cleanup
+
+If not using defer:
+
+```go
+client := copilot.NewClient(nil)
+err := client.Start()
+if err != nil {
+ log.Fatal(err)
+}
+
+session, err := client.CreateSession(nil)
+if err != nil {
+ client.Stop()
+ log.Fatal(err)
+}
+
+// Use session...
+
+session.Destroy()
+errors := client.Stop()
+for _, err := range errors {
+ log.Printf("Cleanup error: %v", err)
+}
+```
+
+## Best Practices
+
+1. **Always use `defer`** for cleanup of clients and sessions
+2. **Use channels** to wait for SessionIdle event
+3. **Handle SessionError** events for robust error handling
+4. **Use type switches** for event handling
+5. **Enable streaming** for better UX in interactive scenarios
+6. **Provide descriptive tool names and descriptions** for better model understanding
+7. **Call unsubscribe functions** when no longer needed
+8. **Use SystemMessageConfig with Mode: "append"** to preserve safety guardrails
+9. **Handle both delta and final events** when streaming is enabled
+10. **Check nil pointers** in event data (Content, Message, etc. are pointers)
+
+## Common Patterns
+
+### Simple Query-Response
+
+```go
+client := copilot.NewClient(nil)
+if err := client.Start(); err != nil {
+ log.Fatal(err)
+}
+defer client.Stop()
+
+session, err := client.CreateSession(&copilot.SessionConfig{Model: "gpt-5"})
+if err != nil {
+ log.Fatal(err)
+}
+defer session.Destroy()
+
+done := make(chan struct{})
+
+session.On(func(evt copilot.SessionEvent) {
+ if evt.Type == copilot.AssistantMessage && evt.Data.Content != nil {
+ fmt.Println(*evt.Data.Content)
+ } else if evt.Type == copilot.SessionIdle {
+ close(done)
+ }
+})
+
+session.Send(copilot.MessageOptions{Prompt: "What is 2+2?"})
+<-done
+```
+
+### Multi-Turn Conversation
+
+```go
+session, _ := client.CreateSession(nil)
+defer session.Destroy()
+
+sendAndWait := func(prompt string) error {
+ done := make(chan struct{})
+ var eventErr error
+
+ unsubscribe := session.On(func(evt copilot.SessionEvent) {
+ switch evt.Type {
+ case copilot.AssistantMessage:
+ if evt.Data.Content != nil {
+ fmt.Println(*evt.Data.Content)
+ }
+ case copilot.SessionIdle:
+ close(done)
+ case copilot.SessionError:
+ if evt.Data.Message != nil {
+ eventErr = fmt.Errorf(*evt.Data.Message)
+ }
+ }
+ })
+ defer unsubscribe()
+
+ if _, err := session.Send(copilot.MessageOptions{Prompt: prompt}); err != nil {
+ return err
+ }
+ <-done
+ return eventErr
+}
+
+sendAndWait("What is the capital of France?")
+sendAndWait("What is its population?")
+```
+
+### SendAndWait Helper
+
+```go
+// Use built-in SendAndWait for simpler synchronous interaction
+response, err := session.SendAndWait(copilot.MessageOptions{
+ Prompt: "What is 2+2?",
+}, 0) // 0 uses default 60s timeout
+
+if err != nil {
+ log.Printf("Error: %v", err)
+}
+if response != nil && response.Data.Content != nil {
+ fmt.Println(*response.Data.Content)
+}
+```
+
+### Tool with Struct Return Type
+
+```go
+type UserInfo struct {
+ ID string `json:"id"`
+ Name string `json:"name"`
+ Email string `json:"email"`
+ Role string `json:"role"`
+}
+
+session, _ := client.CreateSession(&copilot.SessionConfig{
+ Tools: []copilot.Tool{
+ {
+ Name: "get_user",
+ Description: "Retrieve user information",
+ Parameters: map[string]interface{}{
+ "type": "object",
+ "properties": map[string]interface{}{
+ "user_id": map[string]interface{}{
+ "type": "string",
+ "description": "User ID",
+ },
+ },
+ "required": []string{"user_id"},
+ },
+ Handler: func(inv copilot.ToolInvocation) (copilot.ToolResult, error) {
+ args := inv.Arguments.(map[string]interface{})
+ userID := args["user_id"].(string)
+
+ user := UserInfo{
+ ID: userID,
+ Name: "John Doe",
+ Email: "john@example.com",
+ Role: "Developer",
+ }
+
+ jsonBytes, _ := json.Marshal(user)
+ return copilot.ToolResult{
+ TextResultForLLM: string(jsonBytes),
+ ResultType: "success",
+ ToolTelemetry: map[string]interface{}{},
+ }, nil
+ },
+ },
+ },
+})
+```
diff --git a/instructions/copilot-sdk-nodejs.instructions.md b/instructions/copilot-sdk-nodejs.instructions.md
new file mode 100644
index 00000000..78c6f2b2
--- /dev/null
+++ b/instructions/copilot-sdk-nodejs.instructions.md
@@ -0,0 +1,717 @@
+---
+applyTo: "**.ts, **.js, package.json"
+description: "This file provides guidance on building Node.js/TypeScript applications using GitHub Copilot SDK."
+name: "GitHub Copilot SDK Node.js Instructions"
+---
+
+## Core Principles
+
+- The SDK is in technical preview and may have breaking changes
+- Requires Node.js 18.0 or later
+- Requires GitHub Copilot CLI installed and in PATH
+- Built with TypeScript for type safety
+- Uses async/await patterns throughout
+- Provides full TypeScript type definitions
+
+## Installation
+
+Always install via npm/pnpm/yarn:
+
+```bash
+npm install @github/copilot-sdk
+# or
+pnpm add @github/copilot-sdk
+# or
+yarn add @github/copilot-sdk
+```
+
+## Client Initialization
+
+### Basic Client Setup
+
+```typescript
+import { CopilotClient } from "@github/copilot-sdk";
+
+const client = new CopilotClient();
+await client.start();
+// Use client...
+await client.stop();
+```
+
+### Client Configuration Options
+
+When creating a CopilotClient, use `CopilotClientOptions`:
+
+- `cliPath` - Path to CLI executable (default: "copilot" from PATH)
+- `cliArgs` - Extra arguments prepended before SDK-managed flags (string[])
+- `cliUrl` - URL of existing CLI server (e.g., "localhost:8080"). When provided, client won't spawn a process
+- `port` - Server port (default: 0 for random)
+- `useStdio` - Use stdio transport instead of TCP (default: true)
+- `logLevel` - Log level (default: "debug")
+- `autoStart` - Auto-start server (default: true)
+- `autoRestart` - Auto-restart on crash (default: true)
+- `cwd` - Working directory for the CLI process (default: process.cwd())
+- `env` - Environment variables for the CLI process (default: process.env)
+
+### Manual Server Control
+
+For explicit control:
+
+```typescript
+const client = new CopilotClient({ autoStart: false });
+await client.start();
+// Use client...
+await client.stop();
+```
+
+Use `forceStop()` when `stop()` takes too long.
+
+## Session Management
+
+### Creating Sessions
+
+Use `SessionConfig` for configuration:
+
+```typescript
+const session = await client.createSession({
+ model: "gpt-5",
+ streaming: true,
+ tools: [...],
+ systemMessage: { ... },
+ availableTools: ["tool1", "tool2"],
+ excludedTools: ["tool3"],
+ provider: { ... }
+});
+```
+
+### Session Config Options
+
+- `sessionId` - Custom session ID (string)
+- `model` - Model name ("gpt-5", "claude-sonnet-4.5", etc.)
+- `tools` - Custom tools exposed to the CLI (Tool[])
+- `systemMessage` - System message customization (SystemMessageConfig)
+- `availableTools` - Allowlist of tool names (string[])
+- `excludedTools` - Blocklist of tool names (string[])
+- `provider` - Custom API provider configuration (BYOK) (ProviderConfig)
+- `streaming` - Enable streaming response chunks (boolean)
+- `mcpServers` - MCP server configurations (MCPServerConfig[])
+- `customAgents` - Custom agent configurations (CustomAgentConfig[])
+- `configDir` - Config directory override (string)
+- `skillDirectories` - Skill directories (string[])
+- `disabledSkills` - Disabled skills (string[])
+- `onPermissionRequest` - Permission request handler (PermissionHandler)
+
+### Resuming Sessions
+
+```typescript
+const session = await client.resumeSession("session-id", {
+ tools: [myNewTool],
+});
+```
+
+### Session Operations
+
+- `session.sessionId` - Get session identifier (string)
+- `await session.send({ prompt: "...", attachments: [...] })` - Send message, returns Promise
+- `await session.sendAndWait({ prompt: "..." }, timeout)` - Send and wait for idle, returns Promise
+- `await session.abort()` - Abort current processing
+- `await session.getMessages()` - Get all events/messages, returns Promise
+- `await session.destroy()` - Clean up session
+
+## Event Handling
+
+### Event Subscription Pattern
+
+ALWAYS use async/await or Promises for waiting on session events:
+
+```typescript
+await new Promise((resolve) => {
+ session.on((event) => {
+ if (event.type === "assistant.message") {
+ console.log(event.data.content);
+ } else if (event.type === "session.idle") {
+ resolve();
+ }
+ });
+
+ session.send({ prompt: "..." });
+});
+```
+
+### Unsubscribing from Events
+
+The `on()` method returns a function that unsubscribes:
+
+```typescript
+const unsubscribe = session.on((event) => {
+ // handler
+});
+// Later...
+unsubscribe();
+```
+
+### Event Types
+
+Use discriminated unions with type guards for event handling:
+
+```typescript
+session.on((event) => {
+ switch (event.type) {
+ case "user.message":
+ // Handle user message
+ break;
+ case "assistant.message":
+ console.log(event.data.content);
+ break;
+ case "tool.executionStart":
+ // Tool execution started
+ break;
+ case "tool.executionComplete":
+ // Tool execution completed
+ break;
+ case "session.start":
+ // Session started
+ break;
+ case "session.idle":
+ // Session is idle (processing complete)
+ break;
+ case "session.error":
+ console.error(`Error: ${event.data.message}`);
+ break;
+ }
+});
+```
+
+## Streaming Responses
+
+### Enabling Streaming
+
+Set `streaming: true` in SessionConfig:
+
+```typescript
+const session = await client.createSession({
+ model: "gpt-5",
+ streaming: true,
+});
+```
+
+### Handling Streaming Events
+
+Handle both delta events (incremental) and final events:
+
+```typescript
+await new Promise((resolve) => {
+ session.on((event) => {
+ switch (event.type) {
+ case "assistant.message.delta":
+ // Incremental text chunk
+ process.stdout.write(event.data.deltaContent);
+ break;
+ case "assistant.reasoning.delta":
+ // Incremental reasoning chunk (model-dependent)
+ process.stdout.write(event.data.deltaContent);
+ break;
+ case "assistant.message":
+ // Final complete message
+ console.log("\n--- Final ---");
+ console.log(event.data.content);
+ break;
+ case "assistant.reasoning":
+ // Final reasoning content
+ console.log("--- Reasoning ---");
+ console.log(event.data.content);
+ break;
+ case "session.idle":
+ resolve();
+ break;
+ }
+ });
+
+ session.send({ prompt: "Tell me a story" });
+});
+```
+
+Note: Final events (`assistant.message`, `assistant.reasoning`) are ALWAYS sent regardless of streaming setting.
+
+## Custom Tools
+
+### Defining Tools with defineTool
+
+Use `defineTool` for type-safe tool definitions:
+
+```typescript
+import { defineTool } from "@github/copilot-sdk";
+
+const session = await client.createSession({
+ model: "gpt-5",
+ tools: [
+ defineTool({
+ name: "lookup_issue",
+ description: "Fetch issue details from tracker",
+ parameters: {
+ type: "object",
+ properties: {
+ id: { type: "string", description: "Issue ID" },
+ },
+ required: ["id"],
+ },
+ handler: async (args) => {
+ const issue = await fetchIssue(args.id);
+ return issue;
+ },
+ }),
+ ],
+});
+```
+
+### Using Zod for Parameters
+
+The SDK supports Zod schemas for parameters:
+
+```typescript
+import { z } from "zod";
+
+const session = await client.createSession({
+ tools: [
+ defineTool({
+ name: "get_weather",
+ description: "Get weather for a location",
+ parameters: z.object({
+ location: z.string().describe("City name"),
+ units: z.enum(["celsius", "fahrenheit"]).optional(),
+ }),
+ handler: async (args) => {
+ return { temperature: 72, units: args.units || "fahrenheit" };
+ },
+ }),
+ ],
+});
+```
+
+### Tool Return Types
+
+- Return any JSON-serializable value (automatically wrapped)
+- Or return `ToolResultObject` for full control over metadata:
+
+```typescript
+{
+ textResultForLlm: string; // Result shown to LLM
+ resultType: "success" | "failure";
+ error?: string; // Internal error (not shown to LLM)
+ toolTelemetry?: Record;
+}
+```
+
+### Tool Execution Flow
+
+When Copilot invokes a tool, the client automatically:
+
+1. Runs your handler function
+2. Serializes the return value
+3. Responds to the CLI
+
+## System Message Customization
+
+### Append Mode (Default - Preserves Guardrails)
+
+```typescript
+const session = await client.createSession({
+ model: "gpt-5",
+ systemMessage: {
+ mode: "append",
+ content: `
+
+- Always check for security vulnerabilities
+- Suggest performance improvements when applicable
+
+`,
+ },
+});
+```
+
+### Replace Mode (Full Control - Removes Guardrails)
+
+```typescript
+const session = await client.createSession({
+ model: "gpt-5",
+ systemMessage: {
+ mode: "replace",
+ content: "You are a helpful assistant.",
+ },
+});
+```
+
+## File Attachments
+
+Attach files to messages:
+
+```typescript
+await session.send({
+ prompt: "Analyze this file",
+ attachments: [
+ {
+ type: "file",
+ path: "/path/to/file.ts",
+ displayName: "My File",
+ },
+ ],
+});
+```
+
+## Message Delivery Modes
+
+Use the `mode` property in message options:
+
+- `"enqueue"` - Queue message for processing
+- `"immediate"` - Process message immediately
+
+```typescript
+await session.send({
+ prompt: "...",
+ mode: "enqueue",
+});
+```
+
+## Multiple Sessions
+
+Sessions are independent and can run concurrently:
+
+```typescript
+const session1 = await client.createSession({ model: "gpt-5" });
+const session2 = await client.createSession({ model: "claude-sonnet-4.5" });
+
+await Promise.all([
+ session1.send({ prompt: "Hello from session 1" }),
+ session2.send({ prompt: "Hello from session 2" }),
+]);
+```
+
+## Bring Your Own Key (BYOK)
+
+Use custom API providers via `provider`:
+
+```typescript
+const session = await client.createSession({
+ provider: {
+ type: "openai",
+ baseUrl: "https://api.openai.com/v1",
+ apiKey: "your-api-key",
+ },
+});
+```
+
+## Session Lifecycle Management
+
+### Listing Sessions
+
+```typescript
+const sessions = await client.listSessions();
+for (const metadata of sessions) {
+ console.log(`${metadata.sessionId}: ${metadata.summary}`);
+}
+```
+
+### Deleting Sessions
+
+```typescript
+await client.deleteSession(sessionId);
+```
+
+### Getting Last Session ID
+
+```typescript
+const lastId = await client.getLastSessionId();
+if (lastId) {
+ const session = await client.resumeSession(lastId);
+}
+```
+
+### Checking Connection State
+
+```typescript
+const state = client.getState();
+// Returns: "disconnected" | "connecting" | "connected" | "error"
+```
+
+## Error Handling
+
+### Standard Exception Handling
+
+```typescript
+try {
+ const session = await client.createSession();
+ await session.send({ prompt: "Hello" });
+} catch (error) {
+ console.error(`Error: ${error.message}`);
+}
+```
+
+### Session Error Events
+
+Monitor `session.error` event type for runtime errors:
+
+```typescript
+session.on((event) => {
+ if (event.type === "session.error") {
+ console.error(`Session Error: ${event.data.message}`);
+ }
+});
+```
+
+## Connectivity Testing
+
+Use ping to verify server connectivity:
+
+```typescript
+const response = await client.ping("health check");
+console.log(`Server responded at ${new Date(response.timestamp)}`);
+```
+
+## Resource Cleanup
+
+### Automatic Cleanup with Try-Finally
+
+ALWAYS use try-finally or cleanup in a finally block:
+
+```typescript
+const client = new CopilotClient();
+try {
+ await client.start();
+ const session = await client.createSession();
+ try {
+ // Use session...
+ } finally {
+ await session.destroy();
+ }
+} finally {
+ await client.stop();
+}
+```
+
+### Cleanup Function Pattern
+
+```typescript
+async function withClient(
+ fn: (client: CopilotClient) => Promise,
+): Promise {
+ const client = new CopilotClient();
+ try {
+ await client.start();
+ return await fn(client);
+ } finally {
+ await client.stop();
+ }
+}
+
+async function withSession(
+ client: CopilotClient,
+ fn: (session: CopilotSession) => Promise,
+): Promise {
+ const session = await client.createSession();
+ try {
+ return await fn(session);
+ } finally {
+ await session.destroy();
+ }
+}
+
+// Usage
+await withClient(async (client) => {
+ await withSession(client, async (session) => {
+ await session.send({ prompt: "Hello!" });
+ });
+});
+```
+
+## Best Practices
+
+1. **Always use try-finally** for resource cleanup
+2. **Use Promises** to wait for session.idle event
+3. **Handle session.error** events for robust error handling
+4. **Use type guards or switch statements** for event handling
+5. **Enable streaming** for better UX in interactive scenarios
+6. **Use defineTool** for type-safe tool definitions
+7. **Use Zod schemas** for runtime parameter validation
+8. **Dispose event subscriptions** when no longer needed
+9. **Use systemMessage with mode: "append"** to preserve safety guardrails
+10. **Handle both delta and final events** when streaming is enabled
+11. **Leverage TypeScript types** for compile-time safety
+
+## Common Patterns
+
+### Simple Query-Response
+
+```typescript
+import { CopilotClient } from "@github/copilot-sdk";
+
+const client = new CopilotClient();
+try {
+ await client.start();
+
+ const session = await client.createSession({ model: "gpt-5" });
+ try {
+ await new Promise((resolve) => {
+ session.on((event) => {
+ if (event.type === "assistant.message") {
+ console.log(event.data.content);
+ } else if (event.type === "session.idle") {
+ resolve();
+ }
+ });
+
+ session.send({ prompt: "What is 2+2?" });
+ });
+ } finally {
+ await session.destroy();
+ }
+} finally {
+ await client.stop();
+}
+```
+
+### Multi-Turn Conversation
+
+```typescript
+const session = await client.createSession();
+
+async function sendAndWait(prompt: string): Promise {
+ await new Promise((resolve, reject) => {
+ const unsubscribe = session.on((event) => {
+ if (event.type === "assistant.message") {
+ console.log(event.data.content);
+ } else if (event.type === "session.idle") {
+ unsubscribe();
+ resolve();
+ } else if (event.type === "session.error") {
+ unsubscribe();
+ reject(new Error(event.data.message));
+ }
+ });
+
+ session.send({ prompt });
+ });
+}
+
+await sendAndWait("What is the capital of France?");
+await sendAndWait("What is its population?");
+```
+
+### SendAndWait Helper
+
+```typescript
+// Use built-in sendAndWait for simpler synchronous interaction
+const response = await session.sendAndWait({ prompt: "What is 2+2?" }, 60000);
+
+if (response) {
+ console.log(response.data.content);
+}
+```
+
+### Tool with Type-Safe Parameters
+
+```typescript
+import { z } from "zod";
+import { defineTool } from "@github/copilot-sdk";
+
+interface UserInfo {
+ id: string;
+ name: string;
+ email: string;
+ role: string;
+}
+
+const session = await client.createSession({
+ tools: [
+ defineTool({
+ name: "get_user",
+ description: "Retrieve user information",
+ parameters: z.object({
+ userId: z.string().describe("User ID"),
+ }),
+ handler: async (args): Promise => {
+ return {
+ id: args.userId,
+ name: "John Doe",
+ email: "john@example.com",
+ role: "Developer",
+ };
+ },
+ }),
+ ],
+});
+```
+
+### Streaming with Progress
+
+```typescript
+let currentMessage = "";
+
+const unsubscribe = session.on((event) => {
+ if (event.type === "assistant.message.delta") {
+ currentMessage += event.data.deltaContent;
+ process.stdout.write(event.data.deltaContent);
+ } else if (event.type === "assistant.message") {
+ console.log("\n\n=== Complete ===");
+ console.log(`Total length: ${event.data.content.length} chars`);
+ } else if (event.type === "session.idle") {
+ unsubscribe();
+ }
+});
+
+await session.send({ prompt: "Write a long story" });
+```
+
+### Error Recovery
+
+```typescript
+session.on((event) => {
+ if (event.type === "session.error") {
+ console.error("Session error:", event.data.message);
+ // Optionally retry or handle error
+ }
+});
+
+try {
+ await session.send({ prompt: "risky operation" });
+} catch (error) {
+ // Handle send errors
+ console.error("Failed to send:", error);
+}
+```
+
+## TypeScript-Specific Features
+
+### Type Inference
+
+```typescript
+import type { SessionEvent, AssistantMessageEvent } from "@github/copilot-sdk";
+
+session.on((event: SessionEvent) => {
+ if (event.type === "assistant.message") {
+ // TypeScript knows event is AssistantMessageEvent here
+ const content: string = event.data.content;
+ }
+});
+```
+
+### Generic Helper
+
+```typescript
+async function waitForEvent(
+ session: CopilotSession,
+ eventType: T,
+): Promise> {
+ return new Promise((resolve) => {
+ const unsubscribe = session.on((event) => {
+ if (event.type === eventType) {
+ unsubscribe();
+ resolve(event as Extract);
+ }
+ });
+ });
+}
+
+// Usage
+const message = await waitForEvent(session, "assistant.message");
+console.log(message.data.content);
+```
diff --git a/instructions/copilot-sdk-python.instructions.md b/instructions/copilot-sdk-python.instructions.md
new file mode 100644
index 00000000..e4b08e02
--- /dev/null
+++ b/instructions/copilot-sdk-python.instructions.md
@@ -0,0 +1,806 @@
+---
+applyTo: "**.py, pyproject.toml, setup.py"
+description: "This file provides guidance on building Python applications using GitHub Copilot SDK."
+name: "GitHub Copilot SDK Python Instructions"
+---
+
+## Core Principles
+
+- The SDK is in technical preview and may have breaking changes
+- Requires Python 3.9 or later
+- Requires GitHub Copilot CLI installed and in PATH
+- Uses async/await patterns throughout (asyncio)
+- Supports both async context managers and manual lifecycle management
+- Type hints provided for better IDE support
+
+## Installation
+
+Always install via pip:
+
+```bash
+pip install copilot-sdk
+# or with poetry
+poetry add copilot-sdk
+# or with uv
+uv add copilot-sdk
+```
+
+## Client Initialization
+
+### Basic Client Setup
+
+```python
+from copilot import CopilotClient
+
+async with CopilotClient() as client:
+ # Use client...
+ pass
+```
+
+### Client Configuration Options
+
+When creating a CopilotClient, use a dict with these keys:
+
+- `cli_path` - Path to CLI executable (default: "copilot" from PATH or COPILOT_CLI_PATH env var)
+- `cli_url` - URL of existing CLI server (e.g., "localhost:8080"). When provided, client won't spawn a process
+- `port` - Server port (default: 0 for random)
+- `use_stdio` - Use stdio transport instead of TCP (default: True)
+- `log_level` - Log level (default: "info")
+- `auto_start` - Auto-start server (default: True)
+- `auto_restart` - Auto-restart on crash (default: True)
+- `cwd` - Working directory for the CLI process (default: os.getcwd())
+- `env` - Environment variables for the CLI process (dict)
+
+### Manual Server Control
+
+For explicit control:
+
+```python
+client = CopilotClient({"auto_start": False})
+await client.start()
+# Use client...
+await client.stop()
+```
+
+Use `force_stop()` when `stop()` takes too long.
+
+## Session Management
+
+### Creating Sessions
+
+Use a dict for SessionConfig:
+
+```python
+session = await client.create_session({
+ "model": "gpt-5",
+ "streaming": True,
+ "tools": [...],
+ "system_message": { ... },
+ "available_tools": ["tool1", "tool2"],
+ "excluded_tools": ["tool3"],
+ "provider": { ... }
+})
+```
+
+### Session Config Options
+
+- `session_id` - Custom session ID (str)
+- `model` - Model name ("gpt-5", "claude-sonnet-4.5", etc.)
+- `tools` - Custom tools exposed to the CLI (list[Tool])
+- `system_message` - System message customization (dict)
+- `available_tools` - Allowlist of tool names (list[str])
+- `excluded_tools` - Blocklist of tool names (list[str])
+- `provider` - Custom API provider configuration (BYOK) (ProviderConfig)
+- `streaming` - Enable streaming response chunks (bool)
+- `mcp_servers` - MCP server configurations (list)
+- `custom_agents` - Custom agent configurations (list)
+- `config_dir` - Config directory override (str)
+- `skill_directories` - Skill directories (list[str])
+- `disabled_skills` - Disabled skills (list[str])
+- `on_permission_request` - Permission request handler (callable)
+
+### Resuming Sessions
+
+```python
+session = await client.resume_session("session-id", {
+ "tools": [my_new_tool]
+})
+```
+
+### Session Operations
+
+- `session.session_id` - Get session identifier (str)
+- `await session.send({"prompt": "...", "attachments": [...]})` - Send message, returns str (message ID)
+- `await session.send_and_wait({"prompt": "..."}, timeout=60.0)` - Send and wait for idle, returns SessionEvent | None
+- `await session.abort()` - Abort current processing
+- `await session.get_messages()` - Get all events/messages, returns list[SessionEvent]
+- `await session.destroy()` - Clean up session
+
+## Event Handling
+
+### Event Subscription Pattern
+
+ALWAYS use asyncio events or futures for waiting on session events:
+
+```python
+import asyncio
+
+done = asyncio.Event()
+
+def handler(event):
+ if event.type == "assistant.message":
+ print(event.data.content)
+ elif event.type == "session.idle":
+ done.set()
+
+session.on(handler)
+await session.send({"prompt": "..."})
+await done.wait()
+```
+
+### Unsubscribing from Events
+
+The `on()` method returns a function that unsubscribes:
+
+```python
+unsubscribe = session.on(lambda event: print(event.type))
+# Later...
+unsubscribe()
+```
+
+### Event Types
+
+Use attribute access for event type checking:
+
+```python
+def handler(event):
+ if event.type == "user.message":
+ # Handle user message
+ pass
+ elif event.type == "assistant.message":
+ print(event.data.content)
+ elif event.type == "tool.executionStart":
+ # Tool execution started
+ pass
+ elif event.type == "tool.executionComplete":
+ # Tool execution completed
+ pass
+ elif event.type == "session.start":
+ # Session started
+ pass
+ elif event.type == "session.idle":
+ # Session is idle (processing complete)
+ pass
+ elif event.type == "session.error":
+ print(f"Error: {event.data.message}")
+
+session.on(handler)
+```
+
+## Streaming Responses
+
+### Enabling Streaming
+
+Set `streaming: True` in SessionConfig:
+
+```python
+session = await client.create_session({
+ "model": "gpt-5",
+ "streaming": True
+})
+```
+
+### Handling Streaming Events
+
+Handle both delta events (incremental) and final events:
+
+```python
+import asyncio
+
+done = asyncio.Event()
+
+def handler(event):
+ if event.type == "assistant.message.delta":
+ # Incremental text chunk
+ print(event.data.delta_content, end="", flush=True)
+ elif event.type == "assistant.reasoning.delta":
+ # Incremental reasoning chunk (model-dependent)
+ print(event.data.delta_content, end="", flush=True)
+ elif event.type == "assistant.message":
+ # Final complete message
+ print("\n--- Final ---")
+ print(event.data.content)
+ elif event.type == "assistant.reasoning":
+ # Final reasoning content
+ print("--- Reasoning ---")
+ print(event.data.content)
+ elif event.type == "session.idle":
+ done.set()
+
+session.on(handler)
+await session.send({"prompt": "Tell me a story"})
+await done.wait()
+```
+
+Note: Final events (`assistant.message`, `assistant.reasoning`) are ALWAYS sent regardless of streaming setting.
+
+## Custom Tools
+
+### Defining Tools with define_tool
+
+Use `define_tool` for tool definitions:
+
+```python
+from copilot import define_tool
+
+async def fetch_issue(issue_id: str):
+ # Fetch issue from tracker
+ return {"id": issue_id, "status": "open"}
+
+session = await client.create_session({
+ "model": "gpt-5",
+ "tools": [
+ define_tool(
+ name="lookup_issue",
+ description="Fetch issue details from tracker",
+ parameters={
+ "type": "object",
+ "properties": {
+ "id": {"type": "string", "description": "Issue ID"}
+ },
+ "required": ["id"]
+ },
+ handler=lambda args, inv: fetch_issue(args["id"])
+ )
+ ]
+})
+```
+
+### Using Pydantic for Parameters
+
+The SDK works well with Pydantic models:
+
+```python
+from pydantic import BaseModel, Field
+
+class WeatherArgs(BaseModel):
+ location: str = Field(description="City name")
+ units: str = Field(default="fahrenheit", description="Temperature units")
+
+async def get_weather(args: WeatherArgs, inv):
+ return {"temperature": 72, "units": args.units}
+
+session = await client.create_session({
+ "tools": [
+ define_tool(
+ name="get_weather",
+ description="Get weather for a location",
+ parameters=WeatherArgs.model_json_schema(),
+ handler=lambda args, inv: get_weather(WeatherArgs(**args), inv)
+ )
+ ]
+})
+```
+
+### Tool Return Types
+
+- Return any JSON-serializable value (automatically wrapped)
+- Or return a ToolResult dict for full control:
+
+```python
+{
+ "text_result_for_llm": str, # Result shown to LLM
+ "result_type": "success" | "failure",
+ "error": str, # Optional: Internal error (not shown to LLM)
+ "tool_telemetry": dict # Optional: Telemetry data
+}
+```
+
+### Tool Handler Signature
+
+Tool handlers receive two arguments:
+
+- `args` (dict) - The tool arguments passed by the LLM
+- `invocation` (ToolInvocation) - Metadata about the invocation
+ - `invocation.session_id` - Session ID
+ - `invocation.tool_call_id` - Tool call ID
+ - `invocation.tool_name` - Tool name
+ - `invocation.arguments` - Same as args parameter
+
+### Tool Execution Flow
+
+When Copilot invokes a tool, the client automatically:
+
+1. Runs your handler function
+2. Serializes the return value
+3. Responds to the CLI
+
+## System Message Customization
+
+### Append Mode (Default - Preserves Guardrails)
+
+```python
+session = await client.create_session({
+ "model": "gpt-5",
+ "system_message": {
+ "mode": "append",
+ "content": """
+
+- Always check for security vulnerabilities
+- Suggest performance improvements when applicable
+
+"""
+ }
+})
+```
+
+### Replace Mode (Full Control - Removes Guardrails)
+
+```python
+session = await client.create_session({
+ "model": "gpt-5",
+ "system_message": {
+ "mode": "replace",
+ "content": "You are a helpful assistant."
+ }
+})
+```
+
+## File Attachments
+
+Attach files to messages:
+
+```python
+await session.send({
+ "prompt": "Analyze this file",
+ "attachments": [
+ {
+ "type": "file",
+ "path": "/path/to/file.py",
+ "display_name": "My File"
+ }
+ ]
+})
+```
+
+## Message Delivery Modes
+
+Use the `mode` key in message options:
+
+- `"enqueue"` - Queue message for processing
+- `"immediate"` - Process message immediately
+
+```python
+await session.send({
+ "prompt": "...",
+ "mode": "enqueue"
+})
+```
+
+## Multiple Sessions
+
+Sessions are independent and can run concurrently:
+
+```python
+session1 = await client.create_session({"model": "gpt-5"})
+session2 = await client.create_session({"model": "claude-sonnet-4.5"})
+
+await asyncio.gather(
+ session1.send({"prompt": "Hello from session 1"}),
+ session2.send({"prompt": "Hello from session 2"})
+)
+```
+
+## Bring Your Own Key (BYOK)
+
+Use custom API providers via `provider`:
+
+```python
+session = await client.create_session({
+ "provider": {
+ "type": "openai",
+ "base_url": "https://api.openai.com/v1",
+ "api_key": "your-api-key"
+ }
+})
+```
+
+## Session Lifecycle Management
+
+### Listing Sessions
+
+```python
+sessions = await client.list_sessions()
+for metadata in sessions:
+ print(f"{metadata.session_id}: {metadata.summary}")
+```
+
+### Deleting Sessions
+
+```python
+await client.delete_session(session_id)
+```
+
+### Getting Last Session ID
+
+```python
+last_id = await client.get_last_session_id()
+if last_id:
+ session = await client.resume_session(last_id)
+```
+
+### Checking Connection State
+
+```python
+state = client.get_state()
+# Returns: "disconnected" | "connecting" | "connected" | "error"
+```
+
+## Error Handling
+
+### Standard Exception Handling
+
+```python
+try:
+ session = await client.create_session()
+ await session.send({"prompt": "Hello"})
+except Exception as e:
+ print(f"Error: {e}")
+```
+
+### Session Error Events
+
+Monitor `session.error` event type for runtime errors:
+
+```python
+def handler(event):
+ if event.type == "session.error":
+ print(f"Session Error: {event.data.message}")
+
+session.on(handler)
+```
+
+## Connectivity Testing
+
+Use ping to verify server connectivity:
+
+```python
+response = await client.ping("health check")
+print(f"Server responded at {response['timestamp']}")
+```
+
+## Resource Cleanup
+
+### Automatic Cleanup with Context Managers
+
+ALWAYS use async context managers for automatic cleanup:
+
+```python
+async with CopilotClient() as client:
+ async with await client.create_session() as session:
+ # Use session...
+ await session.send({"prompt": "Hello"})
+ # Session automatically destroyed
+# Client automatically stopped
+```
+
+### Manual Cleanup with Try-Finally
+
+```python
+client = CopilotClient()
+try:
+ await client.start()
+ session = await client.create_session()
+ try:
+ # Use session...
+ pass
+ finally:
+ await session.destroy()
+finally:
+ await client.stop()
+```
+
+## Best Practices
+
+1. **Always use async context managers** (`async with`) for automatic cleanup
+2. **Use asyncio.Event or asyncio.Future** to wait for session.idle event
+3. **Handle session.error** events for robust error handling
+4. **Use if/elif chains** for event type checking
+5. **Enable streaming** for better UX in interactive scenarios
+6. **Use define_tool** for tool definitions
+7. **Use Pydantic models** for type-safe parameter validation
+8. **Dispose event subscriptions** when no longer needed
+9. **Use system_message with mode: "append"** to preserve safety guardrails
+10. **Handle both delta and final events** when streaming is enabled
+11. **Use type hints** for better IDE support and code clarity
+
+## Common Patterns
+
+### Simple Query-Response
+
+```python
+from copilot import CopilotClient
+import asyncio
+
+async def main():
+ async with CopilotClient() as client:
+ async with await client.create_session({"model": "gpt-5"}) as session:
+ done = asyncio.Event()
+
+ def handler(event):
+ if event.type == "assistant.message":
+ print(event.data.content)
+ elif event.type == "session.idle":
+ done.set()
+
+ session.on(handler)
+ await session.send({"prompt": "What is 2+2?"})
+ await done.wait()
+
+asyncio.run(main())
+```
+
+### Multi-Turn Conversation
+
+```python
+async def send_and_wait(session, prompt: str):
+ done = asyncio.Event()
+ result = []
+
+ def handler(event):
+ if event.type == "assistant.message":
+ result.append(event.data.content)
+ print(event.data.content)
+ elif event.type == "session.idle":
+ done.set()
+ elif event.type == "session.error":
+ result.append(None)
+ done.set()
+
+ unsubscribe = session.on(handler)
+ await session.send({"prompt": prompt})
+ await done.wait()
+ unsubscribe()
+
+ return result[0] if result else None
+
+async with await client.create_session() as session:
+ await send_and_wait(session, "What is the capital of France?")
+ await send_and_wait(session, "What is its population?")
+```
+
+### SendAndWait Helper
+
+```python
+# Use built-in send_and_wait for simpler synchronous interaction
+async with await client.create_session() as session:
+ response = await session.send_and_wait(
+ {"prompt": "What is 2+2?"},
+ timeout=60.0
+ )
+
+ if response and response.type == "assistant.message":
+ print(response.data.content)
+```
+
+### Tool with Dataclass Return Type
+
+```python
+from dataclasses import dataclass, asdict
+from copilot import define_tool
+
+@dataclass
+class UserInfo:
+ id: str
+ name: str
+ email: str
+ role: str
+
+async def get_user(args, inv) -> dict:
+ user = UserInfo(
+ id=args["user_id"],
+ name="John Doe",
+ email="john@example.com",
+ role="Developer"
+ )
+ return asdict(user)
+
+session = await client.create_session({
+ "tools": [
+ define_tool(
+ name="get_user",
+ description="Retrieve user information",
+ parameters={
+ "type": "object",
+ "properties": {
+ "user_id": {"type": "string", "description": "User ID"}
+ },
+ "required": ["user_id"]
+ },
+ handler=get_user
+ )
+ ]
+})
+```
+
+### Streaming with Progress
+
+```python
+import asyncio
+
+current_message = []
+done = asyncio.Event()
+
+def handler(event):
+ if event.type == "assistant.message.delta":
+ current_message.append(event.data.delta_content)
+ print(event.data.delta_content, end="", flush=True)
+ elif event.type == "assistant.message":
+ print(f"\n\n=== Complete ===")
+ print(f"Total length: {len(event.data.content)} chars")
+ elif event.type == "session.idle":
+ done.set()
+
+unsubscribe = session.on(handler)
+await session.send({"prompt": "Write a long story"})
+await done.wait()
+unsubscribe()
+```
+
+### Error Recovery
+
+```python
+def handler(event):
+ if event.type == "session.error":
+ print(f"Session error: {event.data.message}")
+ # Optionally retry or handle error
+
+session.on(handler)
+
+try:
+ await session.send({"prompt": "risky operation"})
+except Exception as e:
+ # Handle send errors
+ print(f"Failed to send: {e}")
+```
+
+### Using TypedDict for Type Safety
+
+```python
+from typing import TypedDict, List
+
+class MessageOptions(TypedDict, total=False):
+ prompt: str
+ attachments: List[dict]
+ mode: str
+
+class SessionConfig(TypedDict, total=False):
+ model: str
+ streaming: bool
+ tools: List
+
+# Usage with type hints
+options: MessageOptions = {
+ "prompt": "Hello",
+ "mode": "enqueue"
+}
+await session.send(options)
+
+config: SessionConfig = {
+ "model": "gpt-5",
+ "streaming": True
+}
+session = await client.create_session(config)
+```
+
+### Async Generator for Streaming
+
+```python
+from typing import AsyncGenerator
+
+async def stream_response(session, prompt: str) -> AsyncGenerator[str, None]:
+ """Stream response chunks as an async generator."""
+ queue = asyncio.Queue()
+ done = asyncio.Event()
+
+ def handler(event):
+ if event.type == "assistant.message.delta":
+ queue.put_nowait(event.data.delta_content)
+ elif event.type == "session.idle":
+ done.set()
+
+ unsubscribe = session.on(handler)
+ await session.send({"prompt": prompt})
+
+ while not done.is_set():
+ try:
+ chunk = await asyncio.wait_for(queue.get(), timeout=0.1)
+ yield chunk
+ except asyncio.TimeoutError:
+ continue
+
+ # Drain remaining items
+ while not queue.empty():
+ yield queue.get_nowait()
+
+ unsubscribe()
+
+# Usage
+async for chunk in stream_response(session, "Tell me a story"):
+ print(chunk, end="", flush=True)
+```
+
+### Decorator Pattern for Tools
+
+```python
+from typing import Callable, Any
+from copilot import define_tool
+
+def copilot_tool(
+ name: str,
+ description: str,
+ parameters: dict
+) -> Callable:
+ """Decorator to convert a function into a Copilot tool."""
+ def decorator(func: Callable) -> Any:
+ return define_tool(
+ name=name,
+ description=description,
+ parameters=parameters,
+ handler=lambda args, inv: func(**args)
+ )
+ return decorator
+
+@copilot_tool(
+ name="calculate",
+ description="Perform a calculation",
+ parameters={
+ "type": "object",
+ "properties": {
+ "expression": {"type": "string", "description": "Math expression"}
+ },
+ "required": ["expression"]
+ }
+)
+def calculate(expression: str) -> float:
+ return eval(expression)
+
+session = await client.create_session({"tools": [calculate]})
+```
+
+## Python-Specific Features
+
+### Async Context Manager Protocol
+
+The SDK implements `__aenter__` and `__aexit__`:
+
+```python
+class CopilotClient:
+ async def __aenter__(self):
+ await self.start()
+ return self
+
+ async def __aexit__(self, exc_type, exc_val, exc_tb):
+ await self.stop()
+ return False
+
+class CopilotSession:
+ async def __aenter__(self):
+ return self
+
+ async def __aexit__(self, exc_type, exc_val, exc_tb):
+ await self.destroy()
+ return False
+```
+
+### Dataclass Support
+
+Event data is available as attributes:
+
+```python
+def handler(event):
+ # Access event attributes directly
+ print(event.type)
+ print(event.data.content) # For assistant.message
+ print(event.data.delta_content) # For assistant.message.delta
+```