{"kind":"AgentDefinition","metadata":{"namespace":"community","name":"copilot-sdk-csharp","version":"0.1.0"},"spec":{"agents_md":"---\napplyTo: '**.cs, **.csproj'\ndescription: 'This file provides guidance on building C# applications using GitHub Copilot SDK.'\nname: 'GitHub Copilot SDK C# Instructions'\n---\n\n## Core Principles\n\n- The SDK is in technical preview and may have breaking changes\n- Requires .NET 10.0 or later\n- Requires GitHub Copilot CLI installed and in PATH\n- Uses async/await patterns throughout\n- Implements IAsyncDisposable for resource cleanup\n\n## Installation\n\nAlways install via NuGet:\n```bash\ndotnet add package GitHub.Copilot.SDK\n```\n\n## Client Initialization\n\n### Basic Client Setup\n\n```csharp\nawait using var client = new CopilotClient();\nawait client.StartAsync();\n```\n\n### Client Configuration Options\n\nWhen creating a CopilotClient, use `CopilotClientOptions`:\n\n- `CliPath` - Path to CLI executable (default: \"copilot\" from PATH)\n- `CliArgs` - Extra arguments prepended before SDK-managed flags\n- `CliUrl` - URL of existing CLI server (e.g., \"localhost:8080\"). When provided, client won't spawn a process\n- `Port` - Server port (default: 0 for random)\n- `UseStdio` - Use stdio transport instead of TCP (default: true)\n- `LogLevel` - Log level (default: \"info\")\n- `AutoStart` - Auto-start server (default: true)\n- `AutoRestart` - Auto-restart on crash (default: true)\n- `Cwd` - Working directory for the CLI process\n- `Environment` - Environment variables for the CLI process\n- `Logger` - ILogger instance for SDK logging\n\n### Manual Server Control\n\nFor explicit control:\n```csharp\nvar client = new CopilotClient(new CopilotClientOptions { AutoStart = false });\nawait client.StartAsync();\n// Use client...\nawait client.StopAsync();\n```\n\nUse `ForceStopAsync()` when `StopAsync()` takes too long.\n\n## Session Management\n\n### Creating Sessions\n\nUse `SessionConfig` for configuration:\n\n```csharp\nawait using var session = await client.CreateSessionAsync(new SessionConfig\n{\n    OnPermissionRequest = PermissionHandler.ApproveAll,\n    Model = \"gpt-5\",\n    Streaming = true,\n    Tools = [...],\n    SystemMessage = new SystemMessageConfig { ... },\n    AvailableTools = [\"tool1\", \"tool2\"],\n    ExcludedTools = [\"tool3\"],\n    Provider = new ProviderConfig { ... }\n});\n```\n\n### Session Config Options\n\n- `SessionId` - Custom session ID\n- `Model` - Model name (\"gpt-5\", \"claude-sonnet-4.5\", etc.)\n- `Tools` - Custom tools exposed to the CLI\n- `SystemMessage` - System message customization\n- `AvailableTools` - Allowlist of tool names\n- `ExcludedTools` - Blocklist of tool names\n- `Provider` - Custom API provider configuration (BYOK)\n- `Streaming` - Enable streaming response chunks (default: false)\n\n### Resuming Sessions\n\n```csharp\nvar session = await client.ResumeSessionAsync(sessionId, new ResumeSessionConfig\n{\n    OnPermissionRequest = PermissionHandler.ApproveAll,\n    // ...\n});\n```\n\n### Session Operations\n\n- `session.SessionId` - Get session identifier\n- `session.SendAsync(new MessageOptions { Prompt = \"...\", Attachments = [...] })` - Send message\n- `session.AbortAsync()` - Abort current processing\n- `session.GetMessagesAsync()` - Get all events/messages\n- `await session.DisposeAsync()` - Clean up resources\n\n## Event Handling\n\n### Event Subscription Pattern\n\nALWAYS use TaskCompletionSource for waiting on session events:\n\n```csharp\nvar done = new TaskCompletionSource();\n\nsession.On(evt =\u003e\n{\n    if (evt is AssistantMessageEvent msg)\n    {\n        Console.WriteLine(msg.Data.Content);\n    }\n    else if (evt is SessionIdleEvent)\n    {\n        done.SetResult();\n    }\n});\n\nawait session.SendAsync(new MessageOptions { Prompt = \"...\" });\nawait done.Task;\n```\n\n### Unsubscribing from Events\n\nThe `On()` method returns an IDisposable:\n\n```csharp\nvar subscription = session.On(evt =\u003e { /* handler */ });\n// Later...\nsubscription.Dispose();\n```\n\n### Event Types\n\nUse pattern matching or switch expressions for event handling:\n\n```csharp\nsession.On(evt =\u003e\n{\n    switch (evt)\n    {\n        case UserMessageEvent userMsg:\n            // Handle user message\n            break;\n        case AssistantMessageEvent assistantMsg:\n            Console.WriteLine(assistantMsg.Data.Content);\n            break;\n        case ToolExecutionStartEvent toolStart:\n            // Tool execution started\n            break;\n        case ToolExecutionCompleteEvent toolComplete:\n            // Tool execution completed\n            break;\n        case SessionStartEvent start:\n            // Session started\n            break;\n        case SessionIdleEvent idle:\n            // Session is idle (processing complete)\n            break;\n        case SessionErrorEvent error:\n            Console.WriteLine($\"Error: {error.Data.Message}\");\n            break;\n    }\n});\n```\n\n## Streaming Responses\n\n### Enabling Streaming\n\nSet `Streaming = true` in SessionConfig:\n\n```csharp\nvar session = await client.CreateSessionAsync(new SessionConfig\n{\n    OnPermissionRequest = PermissionHandler.ApproveAll,\n    Model = \"gpt-5\",\n    Streaming = true\n});\n```\n\n### Handling Streaming Events\n\nHandle both delta events (incremental) and final events:\n\n```csharp\nvar done = new TaskCompletionSource();\n\nsession.On(evt =\u003e\n{\n    switch (evt)\n    {\n        case AssistantMessageDeltaEvent delta:\n            // Incremental text chunk\n            Console.Write(delta.Data.DeltaContent);\n            break;\n        case AssistantReasoningDeltaEvent reasoningDelta:\n            // Incremental reasoning chunk (model-dependent)\n            Console.Write(reasoningDelta.Data.DeltaContent);\n            break;\n        case AssistantMessageEvent msg:\n            // Final complete message\n            Console.WriteLine(\"\\n--- Final ---\");\n            Console.WriteLine(msg.Data.Content);\n            break;\n        case AssistantReasoningEvent reasoning:\n            // Final reasoning content\n            Console.WriteLine(\"--- Reasoning ---\");\n            Console.WriteLine(reasoning.Data.Content);\n            break;\n        case SessionIdleEvent:\n            done.SetResult();\n            break;\n    }\n});\n\nawait session.SendAsync(new MessageOptions { Prompt = \"Tell me a story\" });\nawait done.Task;\n```\n\nNote: Final events (`AssistantMessageEvent`, `AssistantReasoningEvent`) are ALWAYS sent regardless of streaming setting.\n\n## Custom Tools\n\n### Defining Tools with AIFunctionFactory\n\nUse `Microsoft.Extensions.AI.AIFunctionFactory.Create` for type-safe tools:\n\n```csharp\nusing Microsoft.Extensions.AI;\nusing System.ComponentModel;\n\nvar session = await client.CreateSessionAsync(new SessionConfig\n{\n    OnPermissionRequest = PermissionHandler.ApproveAll,\n    Model = \"gpt-5\",\n    Tools = [\n        AIFunctionFactory.Create(\n            async ([Description(\"Issue ID\")] string id) =\u003e {\n                var issue = await FetchIssueAsync(id);\n                return issue;\n            },\n            \"lookup_issue\",\n            \"Fetch issue details from tracker\"),\n    ]\n});\n```\n\n### Tool Return Types\n\n- Return any JSON-serializable value (automatically wrapped)\n- Or return `ToolResultAIContent` wrapping `ToolResultObject` for full control over metadata\n\n### Tool Execution Flow\n\nWhen Copilot invokes a tool, the client automatically:\n1. Runs your handler function\n2. Serializes the return value\n3. Responds to the CLI\n\n## System Message Customization\n\n### Append Mode (Default - Preserves Guardrails)\n\n```csharp\nvar session = await client.CreateSessionAsync(new SessionConfig\n{\n    OnPermissionRequest = PermissionHandler.ApproveAll,\n    Model = \"gpt-5\",\n    SystemMessage = new SystemMessageConfig\n    {\n        Mode = SystemMessageMode.Append,\n        Content = @\"\n\u003cworkflow_rules\u003e\n- Always check for security vulnerabilities\n- Suggest performance improvements when applicable\n\u003c/workflow_rules\u003e\n\"\n    }\n});\n```\n\n### Replace Mode (Full Control - Removes Guardrails)\n\n```csharp\nvar session = await client.CreateSessionAsync(new SessionConfig\n{\n    OnPermissionRequest = PermissionHandler.ApproveAll,\n    Model = \"gpt-5\",\n    SystemMessage = new SystemMessageConfig\n    {\n        Mode = SystemMessageMode.Replace,\n        Content = \"You are a helpful assistant.\"\n    }\n});\n```\n\n## File Attachments\n\nAttach files to messages using `UserMessageDataAttachmentsItem`:\n\n```csharp\nawait session.SendAsync(new MessageOptions\n{\n    Prompt = \"Analyze this file\",\n    Attachments = new List\u003cUserMessageDataAttachmentsItem\u003e\n    {\n        new UserMessageDataAttachmentsItem\n        {\n            Type = UserMessageDataAttachmentsItemType.File,\n            Path = \"/path/to/file.cs\",\n            DisplayName = \"My File\"\n        }\n    }\n});\n```\n\n## Message Delivery Modes\n\nUse the `Mode` property in `MessageOptions`:\n\n- `\"enqueue\"` - Queue message for processing\n- `\"immediate\"` - Process message immediately\n\n```csharp\nawait session.SendAsync(new MessageOptions\n{\n    Prompt = \"...\",\n    Mode = \"enqueue\"\n});\n```\n\n## Multiple Sessions\n\nSessions are independent and can run concurrently:\n\n```csharp\nvar session1 = await client.CreateSessionAsync(new SessionConfig\n{\n    OnPermissionRequest = PermissionHandler.ApproveAll,\n    Model = \"gpt-5\",\n});\nvar session2 = await client.CreateSessionAsync(new SessionConfig\n{\n    OnPermissionRequest = PermissionHandler.ApproveAll,\n    Model = \"claude-sonnet-4.5\",\n});\n\nawait session1.SendAsync(new MessageOptions { Prompt = \"Hello from session 1\" });\nawait session2.SendAsync(new MessageOptions { Prompt = \"Hello from session 2\" });\n```\n\n## Bring Your Own Key (BYOK)\n\nUse custom API providers via `ProviderConfig`:\n\n```csharp\nvar session = await client.CreateSessionAsync(new SessionConfig\n{\n    OnPermissionRequest = PermissionHandler.ApproveAll,\n    Provider = new ProviderConfig\n    {\n        Type = \"openai\",\n        BaseUrl = \"https://api.openai.com/v1\",\n        ApiKey = \"your-api-key\"\n    }\n});\n```\n\n## Session Lifecycle Management\n\n### Listing Sessions\n\n```csharp\nvar sessions = await client.ListSessionsAsync();\nforeach (var metadata in sessions)\n{\n    Console.WriteLine($\"Session: {metadata.SessionId}\");\n}\n```\n\n### Deleting Sessions\n\n```csharp\nawait client.DeleteSessionAsync(sessionId);\n```\n\n### Checking Connection State\n\n```csharp\nvar state = client.State;\n```\n\n## Error Handling\n\n### Standard Exception Handling\n\n```csharp\ntry\n{\n    var session = await client.CreateSessionAsync(new SessionConfig { OnPermissionRequest = PermissionHandler.ApproveAll });\n    await session.SendAsync(new MessageOptions { Prompt = \"Hello\" });\n}\ncatch (StreamJsonRpc.RemoteInvocationException ex)\n{\n    Console.Error.WriteLine($\"JSON-RPC Error: {ex.Message}\");\n}\ncatch (Exception ex)\n{\n    Console.Error.WriteLine($\"Error: {ex.Message}\");\n}\n```\n\n### Session Error Events\n\nMonitor `SessionErrorEvent` for runtime errors:\n\n```csharp\nsession.On(evt =\u003e\n{\n    if (evt is SessionErrorEvent error)\n    {\n        Console.Error.WriteLine($\"Session Error: {error.Data.Message}\");\n    }\n});\n```\n\n## Connectivity Testing\n\nUse PingAsync to verify server connectivity:\n\n```csharp\nvar response = await client.PingAsync(\"test message\");\n```\n\n## Resource Cleanup\n\n### Automatic Cleanup with Using\n\nALWAYS use `await using` for automatic disposal:\n\n```csharp\nawait using var client = new CopilotClient();\nawait using var session = await client.CreateSessionAsync(new SessionConfig { OnPermissionRequest = PermissionHandler.ApproveAll });\n// Resources automatically cleaned up\n```\n\n### Manual Cleanup\n\nIf not using `await using`:\n\n```csharp\nvar client = new CopilotClient();\ntry\n{\n    await client.StartAsync();\n    // Use client...\n}\nfinally\n{\n    await client.StopAsync();\n}\n```\n\n## Best Practices\n\n1. **Always use `await using`** for CopilotClient and CopilotSession\n2. **Use TaskCompletionSource** to wait for SessionIdleEvent\n3. **Handle SessionErrorEvent** for robust error handling\n4. **Use pattern matching** (switch expressions) for event handling\n5. **Enable streaming** for better UX in interactive scenarios\n6. **Use AIFunctionFactory** for type-safe tool definitions\n7. **Dispose event subscriptions** when no longer needed\n8. **Use SystemMessageMode.Append** to preserve safety guardrails\n9. **Provide descriptive tool names and descriptions** for better model understanding\n10. **Handle both delta and final events** when streaming is enabled\n\n## Common Patterns\n\n### Simple Query-Response\n\n```csharp\nawait using var client = new CopilotClient();\nawait client.StartAsync();\n\nawait using var session = await client.CreateSessionAsync(new SessionConfig\n{\n    OnPermissionRequest = PermissionHandler.ApproveAll,\n    Model = \"gpt-5\"\n});\n\nvar done = new TaskCompletionSource();\n\nsession.On(evt =\u003e\n{\n    if (evt is AssistantMessageEvent msg)\n    {\n        Console.WriteLine(msg.Data.Content);\n    }\n    else if (evt is SessionIdleEvent)\n    {\n        done.SetResult();\n    }\n});\n\nawait session.SendAsync(new MessageOptions { Prompt = \"What is 2+2?\" });\nawait done.Task;\n```\n\n### Multi-Turn Conversation\n\n```csharp\nawait using var session = await client.CreateSessionAsync(new SessionConfig { OnPermissionRequest = PermissionHandler.ApproveAll });\n\nasync Task SendAndWait(string prompt)\n{\n    var done = new TaskCompletionSource();\n    var subscription = session.On(evt =\u003e\n    {\n        if (evt is AssistantMessageEvent msg)\n        {\n            Console.WriteLine(msg.Data.Content);\n        }\n        else if (evt is SessionIdleEvent)\n        {\n            done.SetResult();\n        }\n    });\n\n    await session.SendAsync(new MessageOptions { Prompt = prompt });\n    await done.Task;\n    subscription.Dispose();\n}\n\nawait SendAndWait(\"What is the capital of France?\");\nawait SendAndWait(\"What is its population?\");\n```\n\n### Tool with Complex Return Type\n\n```csharp\nvar session = await client.CreateSessionAsync(new SessionConfig\n{\n    OnPermissionRequest = PermissionHandler.ApproveAll,\n    Tools = [\n        AIFunctionFactory.Create(\n            ([Description(\"User ID\")] string userId) =\u003e {\n                return new {\n                    Id = userId,\n                    Name = \"John Doe\",\n                    Email = \"john@example.com\",\n                    Role = \"Developer\"\n                };\n            },\n            \"get_user\",\n            \"Retrieve user information\")\n    ]\n});\n```\n\n","description":"This file provides guidance on building C# applications using GitHub Copilot SDK.","import":{"commit_sha":"541b7819d8c3545c6df122491af4fa1eae415779","imported_at":"2026-05-18T20:05:35Z","license_text":"MIT License\n\nCopyright GitHub, Inc.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.","owner":"github","repo":"github/awesome-copilot","source_url":"https://github.com/github/awesome-copilot/blob/541b7819d8c3545c6df122491af4fa1eae415779/instructions/copilot-sdk-csharp.instructions.md"},"manifest":{}},"content_hash":[90,64,204,64,216,253,41,213,12,124,154,191,75,67,140,146,217,188,168,138,183,197,61,237,4,89,238,109,89,222,226,62],"trust_level":"unsigned","yanked":false}
