{"id":39947881,"url":"https://github.com/ajgit/claude.agentsdk","last_synced_at":"2026-02-08T10:01:06.093Z","repository":{"id":332771995,"uuid":"1134771353","full_name":"AJGit/Claude.AgentSdk","owner":"AJGit","description":"A C# SDK for building intelligent agents with Claude Code CLI","archived":false,"fork":false,"pushed_at":"2026-01-18T18:23:34.000Z","size":569,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-19T01:54:13.783Z","etag":null,"topics":["ai","ai-agent","anthropic","claude","csharp","dotnet","mcp","sdk"],"latest_commit_sha":null,"homepage":"https://www.nuget.org/packages/AJGit.Claude.AgentSdk","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AJGit.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-01-15T07:18:07.000Z","updated_at":"2026-01-18T18:19:23.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/AJGit/Claude.AgentSdk","commit_stats":null,"previous_names":["ajgit/claude.agentsdk"],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/AJGit/Claude.AgentSdk","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AJGit%2FClaude.AgentSdk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AJGit%2FClaude.AgentSdk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AJGit%2FClaude.AgentSdk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AJGit%2FClaude.AgentSdk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AJGit","download_url":"https://codeload.github.com/AJGit/Claude.AgentSdk/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AJGit%2FClaude.AgentSdk/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29227378,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-08T09:43:19.170Z","status":"ssl_error","status_checked_at":"2026-02-08T09:42:55.556Z","response_time":57,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","ai-agent","anthropic","claude","csharp","dotnet","mcp","sdk"],"created_at":"2026-01-18T20:10:22.512Z","updated_at":"2026-02-08T10:01:06.084Z","avatar_url":"https://github.com/AJGit.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Claude.AgentSdk\n\nA C# SDK for building agents with the Claude Code CLI. This SDK provides a .NET interface to the same agent capabilities that power Claude Code.\n\n## Requirements\n\n- **.NET 8.0, 9.0, or 10.0**\n- **Claude Code CLI** installed and available in PATH\n\n## Installation\n\n### Install Claude Code CLI\n\n```bash\nnpm install -g @anthropic-ai/claude-code\n```\n\nVerify installation:\n```bash\nclaude --version\n```\n\n### Add SDK to Your Project\n\n```bash\ndotnet add package AJGit.Claude.AgentSdk\n```\n\nFor ASP.NET Core dependency injection support:\n```bash\ndotnet add package AJGit.Claude.AgentSdk.Extensions.DependencyInjection\n```\n\nOr reference the project directly:\n```xml\n\u003cProjectReference Include=\"path/to/Claude.AgentSdk.csproj\" /\u003e\n```\n\n## Quick Start\n\n### Simple Query\n\n```csharp\nusing Claude.AgentSdk;\nusing Claude.AgentSdk.Messages;\n\nvar client = new ClaudeAgentClient();\n\nawait foreach (var message in client.QueryAsync(\"What is the capital of France?\"))\n{\n    if (message is AssistantMessage assistant)\n    {\n        foreach (var block in assistant.MessageContent.Content)\n        {\n            if (block is TextBlock text)\n            {\n                Console.Write(text.Text);\n            }\n        }\n    }\n}\n```\n\n### With Options\n\n```csharp\nvar options = new ClaudeAgentOptions\n{\n    Model = \"sonnet\",                              // Model to use (string)\n    MaxTurns = 10,                                 // Limit conversation turns\n    SystemPrompt = \"You are a helpful assistant.\", // Custom system prompt (string)\n    AllowedTools = [\"Read\", \"Glob\", \"Grep\"],       // Tools Claude can use\n    WorkingDirectory = \"/path/to/project\"          // Working directory\n};\n\nvar client = new ClaudeAgentClient(options);\n```\n\n### Strongly-Typed Model Selection\n\nUse `ModelIdentifier` for type-safe model selection with IntelliSense support:\n\n```csharp\nusing Claude.AgentSdk.Types;\n\nvar options = new ClaudeAgentOptions\n{\n    // New: Strongly-typed model selection\n    ModelId = ModelIdentifier.Sonnet,              // Use predefined model aliases\n    FallbackModelId = ModelIdentifier.Haiku,       // Type-safe fallback\n\n    // Specific versions also available\n    // ModelId = ModelIdentifier.ClaudeOpus45,     // claude-opus-4-5-20251101\n    // ModelId = ModelIdentifier.ClaudeSonnet4,    // claude-sonnet-4-20250514\n\n    // Custom models supported\n    // ModelId = ModelIdentifier.Custom(\"my-fine-tuned-model\"),\n\n    MaxTurns = 10,\n    AllowedTools = [\"Read\", \"Glob\", \"Grep\"]\n};\n\n// Backward compatible: string Model property still works\nvar legacyOptions = new ClaudeAgentOptions { Model = \"sonnet\" };\n```\n\n#### Available Model Identifiers\n\n| Identifier | Value |\n|------------|-------|\n| `ModelIdentifier.Sonnet` | `\"sonnet\"` |\n| `ModelIdentifier.Opus` | `\"opus\"` |\n| `ModelIdentifier.Haiku` | `\"haiku\"` |\n| `ModelIdentifier.ClaudeSonnet4` | `\"claude-sonnet-4-20250514\"` |\n| `ModelIdentifier.ClaudeOpus45` | `\"claude-opus-4-5-20251101\"` |\n| `ModelIdentifier.ClaudeHaiku35` | `\"claude-3-5-haiku-20241022\"` |\n\n### Strongly-Typed Tool Names\n\nUse `ToolName` for type-safe tool references with IntelliSense support:\n\n```csharp\nusing Claude.AgentSdk.Types;\n\nvar options = new ClaudeAgentOptions\n{\n    // Strongly-typed tool names\n    AllowedTools = [ToolName.Read, ToolName.Write, ToolName.Bash, ToolName.Grep],\n    DisallowedTools = [ToolName.WebSearch, ToolName.WebFetch],\n\n    // MCP tool names use factory method\n    // AllowedTools = [ToolName.Mcp(\"email-tools\", \"search_inbox\")]\n};\n\n// Backward compatible: string arrays still work\nvar legacyOptions = new ClaudeAgentOptions\n{\n    AllowedTools = [\"Read\", \"Write\", \"Bash\"]\n};\n```\n\n#### Available Built-in Tools\n\n| Tool Name | Description |\n|-----------|-------------|\n| `ToolName.Read` | Read files from filesystem |\n| `ToolName.Write` | Write files to filesystem |\n| `ToolName.Edit` | Edit existing files |\n| `ToolName.MultiEdit` | Multiple edits in one operation |\n| `ToolName.Bash` | Execute bash commands |\n| `ToolName.Grep` | Search file contents |\n| `ToolName.Glob` | Find files by pattern |\n| `ToolName.Task` | Spawn subagents |\n| `ToolName.WebFetch` | Fetch web content |\n| `ToolName.WebSearch` | Search the web |\n| `ToolName.TodoRead` | Read todo list |\n| `ToolName.TodoWrite` | Update todo list |\n| `ToolName.NotebookEdit` | Edit Jupyter notebooks |\n| `ToolName.AskUserQuestion` | Ask user questions |\n| `ToolName.Skill` | Invoke skills |\n| `ToolName.TaskOutput` | Get background task output |\n| `ToolName.KillShell` | Terminate background shell |\n\n#### MCP Tool Names\n\nCreate MCP tool names using the factory method:\n\n```csharp\n// Format: mcp__\u003cserver\u003e__\u003ctool\u003e\nvar mcpTool = ToolName.Mcp(\"email-tools\", \"search_inbox\");\n// Result: \"mcp__email-tools__search_inbox\"\n\n// Or use McpServerName for even more type safety\nvar server = McpServerName.Sdk(\"email-tools\");\nvar tool = server.Tool(\"search_inbox\");  // Returns ToolName\n```\n\n### Strongly-Typed MCP Server Names\n\nUse `McpServerName` for type-safe MCP server references:\n\n```csharp\nusing Claude.AgentSdk.Types;\n\n// Create server name\nvar server = McpServerName.Sdk(\"my-tools\");\n\n// Get tool names from server\nvar searchTool = server.Tool(\"search\");       // ToolName: \"mcp__my-tools__search\"\nvar readTool = server.Tool(\"read_file\");      // ToolName: \"mcp__my-tools__read_file\"\n\n// Use with AllowedTools\nvar options = new ClaudeAgentOptions\n{\n    AllowedTools = [\n        server.Tool(\"search\"),\n        server.Tool(\"read_file\"),\n        server.Tool(\"write_file\")\n    ]\n};\n```\n\n### Using CLAUDE.md Files\n\nCLAUDE.md files provide project-specific context and instructions. To load them, you must explicitly specify `SettingSources`:\n\n```csharp\nvar options = new ClaudeAgentOptions\n{\n    // Use Claude Code's system prompt (includes tool instructions, code guidelines, etc.)\n    SystemPrompt = SystemPromptConfig.ClaudeCode(),\n\n    // IMPORTANT: You must specify SettingSources to load CLAUDE.md files\n    // The claude_code preset alone does NOT load CLAUDE.md automatically\n    SettingSources = [SettingSource.Project],  // Load project-level CLAUDE.md\n\n    WorkingDirectory = \"/path/to/project\"\n};\n\nvar client = new ClaudeAgentClient(options);\n\nawait foreach (var message in client.QueryAsync(\"Help me refactor this code\"))\n{\n    // Claude now has access to your project guidelines from CLAUDE.md\n}\n```\n\n#### System Prompt Options\n\n```csharp\n// Option 1: Custom string prompt (replaces default entirely)\nSystemPrompt = \"You are a Python specialist.\"\n\n// Option 2: Use Claude Code's preset (includes tools, code guidelines, safety)\nSystemPrompt = SystemPromptConfig.ClaudeCode()\n\n// Option 3: Use preset with appended instructions\nSystemPrompt = SystemPromptConfig.ClaudeCode(append: \"Always use TypeScript strict mode.\")\n\n// Option 4: Explicit preset configuration\nSystemPrompt = new PresetSystemPrompt\n{\n    Preset = \"claude_code\",\n    Append = \"Focus on performance optimization.\"\n}\n```\n\n#### Setting Sources\n\n```csharp\n// Load only project-level CLAUDE.md (./CLAUDE.md or ./.claude/CLAUDE.md)\nSettingSources = [SettingSource.Project]\n\n// Load only user-level CLAUDE.md (~/.claude/CLAUDE.md)\nSettingSources = [SettingSource.User]\n\n// Load both project and user-level CLAUDE.md\nSettingSources = [SettingSource.Project, SettingSource.User]\n\n// Load project, user, and local settings (CLAUDE.local.md - gitignored)\nSettingSources = [SettingSource.Project, SettingSource.User, SettingSource.Local]\n```\n\n**CLAUDE.md locations:**\n- **Project-level:** `CLAUDE.md` or `.claude/CLAUDE.md` in your working directory\n- **User-level:** `~/.claude/CLAUDE.md` for global instructions across all projects\n- **Local-level:** `CLAUDE.local.md` or `.claude/CLAUDE.local.md` (typically gitignored)\n\n### Tool Permission Callback\n\nControl which tools Claude can use:\n\n```csharp\nvar options = new ClaudeAgentOptions\n{\n    AllowedTools = [\"Read\", \"Write\", \"Bash\"],\n    CanUseTool = async (request, ct) =\u003e\n    {\n        Console.WriteLine($\"Claude wants to use: {request.ToolName}\");\n        Console.WriteLine($\"Input: {request.Input}\");\n\n        // Auto-allow read operations\n        if (request.ToolName == \"Read\")\n            return new PermissionResultAllow();\n\n        // Deny dangerous operations\n        if (request.ToolName == \"Bash\")\n            return new PermissionResultDeny { Message = \"Bash not allowed\" };\n\n        // Allow with modifications\n        return new PermissionResultAllow();\n    }\n};\n```\n\n### MCP Servers\n\nModel Context Protocol (MCP) servers extend Claude with custom tools and capabilities. The SDK supports four transport types.\n\n#### Transport Types\n\n| Transport | Config Type            | Description                       |\n| --------- | ---------------------- | --------------------------------- |\n| **stdio** | `McpStdioServerConfig` | External process via stdin/stdout |\n| **SSE**   | `McpSseServerConfig`   | Server-Sent Events over HTTP      |\n| **HTTP**  | `McpHttpServerConfig`  | HTTP request/response             |\n| **SDK**   | `McpSdkServerConfig`   | In-process C# tools               |\n\n#### stdio Server (External Process)\n\n```csharp\nvar options = new ClaudeAgentOptions\n{\n    McpServers = new Dictionary\u003cstring, McpServerConfig\u003e\n    {\n        [\"filesystem\"] = new McpStdioServerConfig\n        {\n            Command = \"npx\",\n            Args = [\"@modelcontextprotocol/server-filesystem\"],\n            Env = new Dictionary\u003cstring, string\u003e\n            {\n                [\"ALLOWED_PATHS\"] = \"/Users/me/projects\"\n            }\n        }\n    },\n    AllowedTools = [\"mcp__filesystem__list_files\", \"mcp__filesystem__read_file\"]\n};\n```\n\n#### SSE Server (Remote)\n\n```csharp\nvar options = new ClaudeAgentOptions\n{\n    McpServers = new Dictionary\u003cstring, McpServerConfig\u003e\n    {\n        [\"remote-api\"] = new McpSseServerConfig\n        {\n            Url = \"https://api.example.com/mcp/sse\",\n            Headers = new Dictionary\u003cstring, string\u003e\n            {\n                [\"Authorization\"] = \"Bearer your-token\"\n            }\n        }\n    }\n};\n```\n\n#### HTTP Server (Remote)\n\n```csharp\nvar options = new ClaudeAgentOptions\n{\n    McpServers = new Dictionary\u003cstring, McpServerConfig\u003e\n    {\n        [\"http-service\"] = new McpHttpServerConfig\n        {\n            Url = \"https://api.example.com/mcp\",\n            Headers = new Dictionary\u003cstring, string\u003e\n            {\n                [\"X-API-Key\"] = \"your-api-key\"\n            }\n        }\n    }\n};\n```\n\n#### SDK Server (In-Process C# Tools)\n\nDefine tools directly in C# that Claude can call:\n\n```csharp\nusing Claude.AgentSdk.Attributes;\nusing Claude.AgentSdk.Tools;\n\n// Create a tool server\nvar toolServer = new McpToolServer(\"my-tools\", \"1.0.0\");\n\n// Register a tool with typed input\ntoolServer.RegisterTool\u003cCalculatorInput\u003e(\n    \"calculate\",\n    \"Perform arithmetic operations\",\n    async (input, ct) =\u003e\n    {\n        var result = input.Operation switch\n        {\n            \"add\" =\u003e input.A + input.B,\n            \"multiply\" =\u003e input.A * input.B,\n            _ =\u003e throw new ArgumentException(\"Unknown operation\")\n        };\n        return ToolResult.Text($\"Result: {result}\");\n    });\n\n// Or use attributes with compile-time registration (recommended)\n[GenerateToolRegistration]  // Generates RegisterToolsCompiled() extension\npublic class MyTools\n{\n    [ClaudeTool(\"get_weather\", \"Get weather for a location\",\n        Categories = [\"weather\"],\n        TimeoutSeconds = 5)]\n    public string GetWeather(\n        [ToolParameter(Description = \"City name\", Example = \"Tokyo\")] string location,\n        [ToolParameter(Description = \"Unit: celsius or fahrenheit\",\n                       AllowedValues = [\"celsius\", \"fahrenheit\"])] string unit = \"celsius\")\n    {\n        return $\"Weather in {location}: 72°F, sunny\";\n    }\n}\n\nvar myTools = new MyTools();\ntoolServer.RegisterToolsCompiled(myTools);  // No reflection!\n\n// Use with client\nvar options = new ClaudeAgentOptions\n{\n    McpServers = new Dictionary\u003cstring, McpServerConfig\u003e\n    {\n        [\"my-tools\"] = new McpSdkServerConfig\n        {\n            Name = \"my-tools\",\n            Instance = toolServer\n        }\n    }\n};\n\nrecord CalculatorInput(double A, double B, string Operation);\n```\n\n#### Compile-Time Tool Registration (Recommended)\n\nUse source generators to register tools without reflection:\n\n```csharp\n// Add generator reference to your project:\n// \u003cProjectReference Include=\"Claude.AgentSdk.Generators.csproj\"\n//                   OutputItemType=\"Analyzer\"\n//                   ReferenceOutputAssembly=\"false\" /\u003e\n\n[GenerateToolRegistration]  // Marker attribute for source generator\npublic class EmailTools\n{\n    [ClaudeTool(\"search_inbox\", \"Search emails with Gmail-like syntax\",\n        Categories = [\"email\"],\n        TimeoutSeconds = 10)]\n    public string SearchInbox(\n        [ToolParameter(Description = \"Gmail-style search query\")] string query,\n        [ToolParameter(Description = \"Max results (1-100)\", MinValue = 1, MaxValue = 100)] int? limit = 20)\n    {\n        // Implementation\n    }\n\n    [ClaudeTool(\"delete_email\", \"Delete an email by ID\",\n        Categories = [\"email\"],\n        Dangerous = true)]  // Mark destructive operations\n    public string DeleteEmail([ToolParameter(Description = \"Email ID\")] string id)\n    {\n        // Implementation\n    }\n}\n\n// Generated extension method (no reflection)\nvar emailTools = new EmailTools();\ntoolServer.RegisterToolsCompiled(emailTools);\n\n// Get tool names for AllowedTools configuration\nvar toolNames = emailTools.GetToolNamesCompiled();\n// Returns: [\"search_inbox\", \"delete_email\", ...]\n\n// Get MCP-prefixed tool names for a server\nvar mcpToolNames = emailTools.GetMcpToolNamesCompiled(\"email-tools\");\n// Returns: [\"mcp__email-tools__search_inbox\", \"mcp__email-tools__delete_email\", ...]\n\n// Get AllowedTools array directly\nvar options = new ClaudeAgentOptions\n{\n    AllowedTools = emailTools.GetAllowedToolsCompiled(\"email-tools\")\n};\n```\n\n**Generated Tool Name Methods:**\n\n| Method | Description |\n|--------|-------------|\n| `GetToolNamesCompiled()` | Returns `IReadOnlyList\u003cstring\u003e` of tool names |\n| `GetMcpToolNamesCompiled(serverName)` | Returns MCP-prefixed tool names |\n| `GetAllowedToolsCompiled(serverName)` | Returns `string[]` for `AllowedTools` |\n\n#### Compile-Time Schema Generation\n\nGenerate JSON schemas at compile-time for input types:\n\n```csharp\n[GenerateSchema]  // Generates static schema string\npublic record SearchInboxInput\n{\n    [ToolParameter(Description = \"Gmail-style search query\")]\n    public required string Query { get; init; }\n\n    [ToolParameter(Description = \"Max results\", MinValue = 1, MaxValue = 100)]\n    public int? Limit { get; init; }\n}\n\n// Access generated schema\nvar schema = SearchInboxInputSchemaExtensions.GetSchema();\n```\n\n#### Combining Multiple MCP Servers\n\n```csharp\nvar options = new ClaudeAgentOptions\n{\n    McpServers = new Dictionary\u003cstring, McpServerConfig\u003e\n    {\n        // External filesystem server\n        [\"filesystem\"] = new McpStdioServerConfig\n        {\n            Command = \"npx\",\n            Args = [\"@modelcontextprotocol/server-filesystem\"]\n        },\n        // Remote API via SSE\n        [\"remote-api\"] = new McpSseServerConfig\n        {\n            Url = \"https://api.example.com/mcp/sse\"\n        },\n        // In-process custom tools\n        [\"custom\"] = new McpSdkServerConfig\n        {\n            Name = \"custom\",\n            Instance = myToolServer\n        }\n    },\n    // Allow specific MCP tools (format: mcp__\u003cserver\u003e__\u003ctool\u003e)\n    AllowedTools = [\n        \"mcp__filesystem__list_files\",\n        \"mcp__remote-api__query\",\n        \"mcp__custom__calculate\"\n    ]\n};\n```\n\n#### Fluent MCP Server Builder\n\nUse `McpServerBuilder` for a more ergonomic configuration experience:\n\n```csharp\nusing Claude.AgentSdk.Builders;\n\nvar servers = new McpServerBuilder()\n    // Add stdio server with environment variables\n    .AddStdio(\"file-tools\", \"python\", \"file_tools.py\")\n        .WithEnvironment(\"DEBUG\", \"true\")\n        .WithEnvironment(\"MAX_FILES\", \"100\")\n\n    // Add SSE server with authentication headers\n    .AddSse(\"remote-api\", \"https://api.example.com/mcp/sse\")\n        .WithHeaders(\"Authorization\", \"Bearer your-token\")\n        .WithHeaders(\"X-API-Version\", \"2\")\n\n    // Add HTTP server\n    .AddHttp(\"http-service\", \"https://api.example.com/mcp\")\n        .WithHeaders(\"X-API-Key\", \"your-api-key\")\n\n    // Add in-process SDK server\n    .AddSdk(\"excel-tools\", excelToolServer)\n\n    .Build();\n\nvar options = new ClaudeAgentOptions\n{\n    McpServers = servers,\n    AllowedTools = [\"mcp__file-tools__read\", \"mcp__remote-api__query\"]\n};\n```\n\nThe builder provides:\n- **Fluent chaining**: Configure multiple servers in a readable flow\n- **Context-aware methods**: `WithEnvironment()` for stdio, `WithHeaders()` for SSE/HTTP\n- **Type safety**: Compile-time checking of configuration\n\n#### Fluent Options Builder\n\nUse `ClaudeAgentOptionsBuilder` for a comprehensive fluent configuration experience:\n\n```csharp\nusing Claude.AgentSdk.Builders;\nusing Claude.AgentSdk.Types;\n\nvar options = new ClaudeAgentOptionsBuilder()\n    // Model configuration\n    .WithModel(ModelIdentifier.Sonnet)\n    .WithFallbackModel(ModelIdentifier.Haiku)\n    .WithMaxTurns(50)\n\n    // System prompt options\n    .WithSystemPrompt(\"You are a helpful assistant.\")\n    // Or: .UseClaudeCodePreset()\n    // Or: .UseClaudeCodePreset(append: \"Focus on C# code.\")\n\n    // Tool configuration with strongly-typed names\n    .AllowTools(ToolName.Read, ToolName.Write, ToolName.Bash, ToolName.Task)\n    .DisallowTools(ToolName.WebSearch)\n    // Or: .AllowAllToolsExcept(ToolName.Bash)\n\n    // MCP servers\n    .AddMcpServer(\"my-tools\", new McpSdkServerConfig\n    {\n        Name = \"my-tools\",\n        Instance = toolServer\n    })\n\n    // Permission handling\n    .WithPermissionMode(PermissionMode.AcceptEdits)\n    .WithToolPermissionHandler(async (request, ct) =\u003e\n    {\n        if (request.ToolName == \"Bash\")\n            return new PermissionResultDeny { Message = \"No shell access\" };\n        return new PermissionResultAllow();\n    })\n\n    // Hooks using builder\n    .WithHooks(new HookConfigurationBuilder()\n        .OnPreToolUse(handler, matcher: \"Write|Edit\")\n        .OnSessionStart(sessionHandler)\n        .Build())\n\n    // Subagents using builder\n    .AddAgent(\"reviewer\", new AgentDefinitionBuilder()\n        .WithDescription(\"Code review specialist\")\n        .WithPrompt(\"You review code for quality and security.\")\n        .WithTools(ToolName.Read, ToolName.Grep, ToolName.Glob)\n        .WithModel(ModelIdentifier.Haiku)\n        .Build())\n\n    // Additional settings\n    .WithWorkingDirectory(\"/path/to/project\")\n    .LoadSettingsFrom(SettingSource.Project, SettingSource.User)\n\n    .Build();\n\nvar client = new ClaudeAgentClient(options);\n```\n\nThe `ClaudeAgentOptionsBuilder` provides:\n- **Full IntelliSense support**: Discover all options via method chaining\n- **Type safety**: Strongly-typed identifiers for models, tools, and settings\n- **Composability**: Combine with other builders (HookConfigurationBuilder, AgentDefinitionBuilder)\n- **Validation**: Catches configuration errors at build time\n\n#### Fluent Hook Configuration Builder\n\nUse `HookConfigurationBuilder` to simplify hook setup:\n\n```csharp\nusing Claude.AgentSdk.Builders;\nusing Claude.AgentSdk.Protocol;\n\nvar hooks = new HookConfigurationBuilder()\n    // Pre-tool hooks with pattern matching\n    .OnPreToolUse(ValidateBashCommand, matcher: \"Bash\")\n    .OnPreToolUse(ValidateFileWrites, matcher: \"Write|Edit|MultiEdit\")\n\n    // Post-tool hooks\n    .OnPostToolUse(LogToolUsage)\n    .OnPostToolUseFailure(HandleToolError)\n\n    // Session lifecycle\n    .OnSessionStart(InitializeTelemetry)\n    .OnSessionEnd(CleanupResources)\n\n    // Subagent tracking\n    .OnSubagentStart(TrackSubagent)\n    .OnSubagentStop(AggregateResults)\n\n    // Other events\n    .OnUserPromptSubmit(InjectContext)\n    .OnNotification(SendToSlack)\n    .OnPermissionRequest(CustomPermissionHandler)\n\n    .Build();\n\nvar options = new ClaudeAgentOptions { Hooks = hooks };\n```\n\n#### Fluent Agent Definition Builder\n\nUse `AgentDefinitionBuilder` for subagent configuration:\n\n```csharp\nusing Claude.AgentSdk.Builders;\nusing Claude.AgentSdk.Types;\n\n// Basic agent definition\nvar codeReviewer = new AgentDefinitionBuilder()\n    .WithDescription(\"Expert code reviewer for security and quality\")\n    .WithPrompt(\"\"\"\n        You are a code review specialist. Focus on:\n        - Security vulnerabilities\n        - Performance issues\n        - Clean code principles\n        \"\"\")\n    .WithTools(ToolName.Read, ToolName.Grep, ToolName.Glob)\n    .WithModel(ModelIdentifier.Haiku)\n    .Build();\n\n// Using convenience presets\nvar readOnlyAgent = new AgentDefinitionBuilder()\n    .WithDescription(\"Read-only code analyzer\")\n    .WithPrompt(\"Analyze code without making changes.\")\n    .AsReadOnlyAnalyzer()  // Sets Read, Grep, Glob tools\n    .Build();\n\nvar testRunner = new AgentDefinitionBuilder()\n    .WithDescription(\"Test execution specialist\")\n    .WithPrompt(\"Run and analyze test suites.\")\n    .AsTestRunner()  // Sets Bash, Read, Grep tools\n    .Build();\n\nvar fullAccessAgent = new AgentDefinitionBuilder()\n    .WithDescription(\"Full-stack developer\")\n    .WithPrompt(\"Implement features with full file access.\")\n    .AsFullAccessDeveloper()  // Sets Read, Write, Edit, Bash, Grep, Glob\n    .Build();\n\n// Use with options\nvar options = new ClaudeAgentOptions\n{\n    AllowedTools = [ToolName.Task, ToolName.Read, ToolName.Write],\n    Agents = new Dictionary\u003cstring, AgentDefinition\u003e\n    {\n        [\"code-reviewer\"] = codeReviewer,\n        [\"test-runner\"] = testRunner\n    }\n};\n```\n\n### Subagents\n\nSubagents are separate agent instances that handle focused subtasks. Use them to isolate context, run tasks in parallel, and apply specialized instructions.\n\n#### Defining Subagents\n\n```csharp\nvar options = new ClaudeAgentOptions\n{\n    // Task tool is required for subagent invocation\n    AllowedTools = [\"Read\", \"Grep\", \"Glob\", \"Task\"],\n\n    Agents = new Dictionary\u003cstring, AgentDefinition\u003e\n    {\n        [\"code-reviewer\"] = new AgentDefinition\n        {\n            // Description tells Claude when to use this subagent\n            Description = \"Expert code review specialist. Use for quality, security, and maintainability reviews.\",\n\n            // Prompt defines the subagent's behavior\n            Prompt = \"\"\"\n                You are a code review specialist with expertise in security and best practices.\n                When reviewing code:\n                - Identify security vulnerabilities\n                - Check for performance issues\n                - Suggest specific improvements\n                Be thorough but concise.\n                \"\"\",\n\n            // Tools restricts what the subagent can do (read-only here)\n            Tools = [\"Read\", \"Grep\", \"Glob\"],\n\n            // Model overrides the default model for this subagent\n            Model = \"sonnet\"\n        },\n\n        [\"test-runner\"] = new AgentDefinition\n        {\n            Description = \"Runs and analyzes test suites. Use for test execution and coverage analysis.\",\n            Prompt = \"You are a test execution specialist. Run tests and analyze results.\",\n            // Bash access lets this subagent run test commands\n            Tools = [\"Bash\", \"Read\", \"Grep\"]\n        }\n    }\n};\n\nvar client = new ClaudeAgentClient(options);\nawait foreach (var msg in client.QueryAsync(\"Review the authentication module for security issues\"))\n{\n    // Claude will automatically delegate to code-reviewer based on the task\n}\n```\n\n#### AgentDefinition Properties\n\n| Property      | Type                     | Required | Description                                              |\n| ------------- | ------------------------ | -------- | -------------------------------------------------------- |\n| `Description` | `string`                 | Yes      | When to use this agent (Claude uses this for delegation) |\n| `Prompt`      | `string`                 | Yes      | System prompt defining the agent's role                  |\n| `Tools`       | `IReadOnlyList\u003cstring\u003e?` | No       | Allowed tools (inherits all if omitted)                  |\n| `Model`       | `string?`                | No       | Model override (\"sonnet\", \"opus\", \"haiku\")               |\n\n#### Common Tool Combinations\n\n| Use Case           | Tools                                       | Description                    |\n| ------------------ | ------------------------------------------- | ------------------------------ |\n| Read-only analysis | `[\"Read\", \"Grep\", \"Glob\"]`                  | Can examine but not modify     |\n| Test execution     | `[\"Bash\", \"Read\", \"Grep\"]`                  | Can run commands               |\n| Code modification  | `[\"Read\", \"Edit\", \"Write\", \"Grep\", \"Glob\"]` | Full read/write                |\n| Full access        | `null` (omit)                               | Inherits all tools from parent |\n\n#### Explicit Invocation\n\nTo guarantee Claude uses a specific subagent, mention it by name:\n\n```csharp\nawait foreach (var msg in client.QueryAsync(\"Use the code-reviewer agent to check the auth module\"))\n{\n    // Directly invokes the named subagent\n}\n```\n\n\u003e **Note:** Subagents cannot spawn their own subagents. Don't include \"Task\" in a subagent's Tools array.\n\n#### Subagent Tool Configuration\n\n**How Tool Permissions Work:**\n\nThe main agent's `Tools` list creates a **base tool pool**. Subagents can use:\n1. Tools from the main agent's pool (shared tools like Read, Write)\n2. Tools in their own `AgentDefinition.Tools` list (even if not in main's pool)\n\n**Working Pattern:**\n\n```csharp\nvar options = new ClaudeAgentOptions\n{\n    SystemPrompt = \"You are a coordinator. Spawn subagents to do research.\",\n\n    // Main agent: Task for spawning + shared tools subagents need\n    Tools = new ToolsList([\"Task\", \"Read\", \"Write\"]),\n\n    Agents = new Dictionary\u003cstring, AgentDefinition\u003e\n    {\n        [\"researcher\"] = new AgentDefinition\n        {\n            Description = \"Research specialist for web searches\",\n            // Subagent gets: WebSearch (own list) + Read, Write (from main's pool)\n            Tools = [\"WebSearch\", \"Write\", \"Read\"],\n            Prompt = \"You research topics and save findings to files.\",\n            Model = \"haiku\"\n        }\n    }\n};\n```\n\n| Tool      | Main Agent | Subagent Config | Subagent Can Use?            |\n| --------- | ---------- | --------------- | ---------------------------- |\n| Task      | ✓          | ✗               | N/A (for spawning)           |\n| Read      | ✓          | ✓               | ✓ (from main's pool)         |\n| Write     | ✓          | ✓               | ✓ (from main's pool)         |\n| WebSearch | ✗          | ✓               | ✓ (from subagent's own list) |\n\n**Key Points:**\n- Include `Task` in main agent's tools for spawning subagents\n- Include shared file tools (`Read`, `Write`) in main agent's tools - subagents need these in the pool\n- Subagent-specific tools (like `WebSearch`) only need to be in the subagent's `Tools` list\n- Use full absolute paths in prompts for file operations (relative paths may resolve incorrectly)\n- The `parent_tool_use_id` field may be null, but you can identify subagent execution by checking the `Model` field (e.g., haiku vs sonnet)\n\n**Common Pitfall:**\n\nIf main agent has `Tools = [\"Task\"]` only (without Read/Write), subagents cannot write files even if Write is in their Tools list. The shared tools must be in the main agent's pool.\n\n#### Declarative Agent Registration\n\nUse attributes to define agents declaratively:\n\n```csharp\nusing Claude.AgentSdk.Attributes;\n\n[GenerateAgentRegistration]  // Generates GetAgentsCompiled() extension method\npublic class MyAgents\n{\n    [ClaudeAgent(\"code-reviewer\",\n        Description = \"Expert code reviewer for quality, security, and maintainability\")]\n    [AgentTools(\"Read\", \"Grep\", \"Glob\")]\n    public static string CodeReviewerPrompt =\u003e \"\"\"\n        You are a code review specialist with expertise in:\n        - Security vulnerability detection\n        - Performance optimization\n        - Clean code principles\n        - SOLID design patterns\n\n        When reviewing code:\n        1. Identify potential security issues\n        2. Check for performance bottlenecks\n        3. Suggest specific improvements with code examples\n        Be thorough but concise.\n        \"\"\";\n\n    [ClaudeAgent(\"test-runner\",\n        Description = \"Test execution specialist for running and analyzing test suites\",\n        Model = \"haiku\")]  // Use faster model for test execution\n    [AgentTools(\"Bash\", \"Read\", \"Grep\")]\n    public static string TestRunnerPrompt =\u003e \"\"\"\n        You are a test execution specialist. Your responsibilities:\n        - Run test suites using appropriate commands\n        - Analyze test results and failures\n        - Provide clear summaries of test coverage\n        \"\"\";\n\n    [ClaudeAgent(\"documentation-writer\",\n        Description = \"Technical writer for API docs, READMEs, and code comments\")]\n    [AgentTools(\"Read\", \"Write\", \"Edit\", \"Glob\")]\n    public static string DocumentationWriterPrompt =\u003e \"\"\"\n        You are a technical documentation specialist. Create clear, accurate documentation\n        that helps developers understand and use the code effectively.\n        \"\"\";\n}\n\n// Usage with generated extension method\nvar agents = new MyAgents();\nvar options = new ClaudeAgentOptions\n{\n    AllowedTools = [\"Task\", \"Read\", \"Write\", \"Grep\", \"Glob\", \"Bash\"],\n    Agents = agents.GetAgentsCompiled()  // Returns IReadOnlyDictionary\u003cstring, AgentDefinition\u003e\n};\n```\n\n**Attribute Reference:**\n\n| Attribute | Target | Description |\n|-----------|--------|-------------|\n| `[GenerateAgentRegistration]` | Class | Enables `GetAgentsCompiled()` extension |\n| `[ClaudeAgent(name)]` | Property | Defines an agent with name and metadata |\n| `[AgentTools(...)]` | Property | Specifies tools available to the agent |\n\n**ClaudeAgent Properties:**\n\n| Property | Type | Description |\n|----------|------|-------------|\n| `Name` | `string` | Required. Unique agent identifier |\n| `Description` | `string?` | When Claude should use this agent |\n| `Model` | `string?` | Model override (e.g., \"haiku\" for speed) |\n\n### Slash Commands\n\nSlash commands control Claude Code sessions with special `/` prefixed commands.\n\n#### Discovering Available Commands\n\n```csharp\nvar client = new ClaudeAgentClient();\n\nawait foreach (var msg in client.QueryAsync(\"Hello\"))\n{\n    if (msg is SystemMessage sys \u0026\u0026 sys.IsInit)\n    {\n        Console.WriteLine(\"Available commands:\");\n        foreach (var cmd in sys.SlashCommands ?? [])\n        {\n            Console.WriteLine($\"  {cmd}\");\n        }\n        // Output: /compact, /clear, /help, /review, etc.\n    }\n}\n```\n\n#### Sending Slash Commands\n\nSend commands as prompt strings:\n\n```csharp\n// Compact conversation history\nawait foreach (var msg in client.QueryAsync(\"/compact\"))\n{\n    if (msg is SystemMessage sys \u0026\u0026 sys.IsCompactBoundary)\n    {\n        Console.WriteLine($\"Compacted: {sys.CompactMetadata?.PreTokens} → {sys.CompactMetadata?.PostTokens} tokens\");\n    }\n}\n\n// Clear conversation and start fresh\nawait foreach (var msg in client.QueryAsync(\"/clear\"))\n{\n    if (msg is SystemMessage sys \u0026\u0026 sys.IsInit)\n    {\n        Console.WriteLine($\"New session: {sys.SessionId}\");\n    }\n}\n```\n\n#### Commands with Arguments\n\nPass arguments after the command:\n\n```csharp\n// Custom command with arguments (e.g., /fix-issue defined in .claude/commands/fix-issue.md)\nawait foreach (var msg in client.QueryAsync(\"/fix-issue 123 high\"))\n{\n    // Arguments are passed as $1=\"123\", $2=\"high\" to the command\n}\n\n// Refactor a specific file\nawait foreach (var msg in client.QueryAsync(\"/refactor src/auth/login.cs\"))\n{\n    // ...\n}\n```\n\n#### Custom Slash Commands\n\nCreate custom commands as markdown files in `.claude/commands/`:\n\n**`.claude/commands/security-check.md`:**\n```markdown\n---\nallowed-tools: Read, Grep, Glob\ndescription: Run security vulnerability scan\nmodel: claude-sonnet-4-5-20250929\n---\n\nAnalyze the codebase for security vulnerabilities including:\n- SQL injection risks\n- XSS vulnerabilities\n- Exposed credentials\n```\n\n**`.claude/commands/fix-issue.md`:**\n```markdown\n---\nargument-hint: [issue-number] [priority]\ndescription: Fix a GitHub issue\n---\n\nFix issue #$1 with priority $2.\nCheck the issue description and implement the necessary changes.\n```\n\n#### File References in Commands\n\nReference files using `@` prefix in command definitions:\n\n```markdown\nReview the following configuration:\n- Package config: @package.json\n- TypeScript config: @tsconfig.json\n```\n\n#### Bash Output in Commands\n\nInclude bash command output using `!`:\n\n```markdown\n## Context\n- Current status: !`git status`\n- Recent changes: !`git diff HEAD~1`\n```\n\n#### SystemMessage Properties\n\n| Property            | Type                              | Description                                        |\n| ------------------- | --------------------------------- | -------------------------------------------------- |\n| `Subtype`           | `string`                          | Message subtype (\"init\", \"compact_boundary\", etc.) |\n| `SessionId`         | `string?`                         | Current session ID                                 |\n| `SlashCommands`     | `IReadOnlyList\u003cstring\u003e?`          | Available slash commands                           |\n| `Tools`             | `IReadOnlyList\u003cstring\u003e?`          | Available tools                                    |\n| `McpServers`        | `IReadOnlyList\u003cMcpServerStatus\u003e?` | MCP server connection status                       |\n| `Model`             | `string?`                         | Current model                                      |\n| `CompactMetadata`   | `CompactMetadata?`                | Compaction details (for compact_boundary)          |\n| `IsInit`            | `bool`                            | True if subtype == \"init\"                          |\n| `IsCompactBoundary` | `bool`                            | True if subtype == \"compact_boundary\"              |\n| `SubtypeEnum`       | `SystemMessageSubtype`            | Strongly-typed enum accessor for subtype           |\n\n### Strongly-Typed Enum Accessors\n\nThe SDK provides strongly-typed enum accessors for type-safe message handling:\n\n```csharp\nusing Claude.AgentSdk.Types;\n\nawait foreach (var message in client.QueryAsync(prompt))\n{\n    switch (message)\n    {\n        case SystemMessage system:\n            // Use SubtypeEnum instead of string comparison\n            if (system.SubtypeEnum == SystemMessageSubtype.Init)\n            {\n                Console.WriteLine($\"Session initialized: {system.SessionId}\");\n\n                // Check MCP server status with StatusEnum\n                foreach (var server in system.McpServers ?? [])\n                {\n                    if (server.StatusEnum == McpServerStatusType.Connected)\n                        Console.WriteLine($\"  {server.Name}: Connected\");\n                    else if (server.StatusEnum == McpServerStatusType.Failed)\n                        Console.WriteLine($\"  {server.Name}: Failed - {server.Error}\");\n                }\n            }\n            break;\n\n        case ResultMessage result:\n            // Use SubtypeEnum for type-safe result checking\n            var status = result.SubtypeEnum switch\n            {\n                ResultMessageSubtype.Success =\u003e \"Completed\",\n                ResultMessageSubtype.Error =\u003e \"Failed\",\n                ResultMessageSubtype.Partial =\u003e \"Partial\",\n                _ =\u003e \"Unknown\"\n            };\n            var ctx = result.Usage is not null ? $\"{result.Usage.TotalContextTokens / 1000.0:F0}k\" : \"?\";\n            Console.WriteLine($\"[{result.DurationMs / 1000.0:F1}s | ${result.TotalCostUsd:F4} | {ctx}]\");\n            break;\n    }\n}\n```\n\n#### Available Enum Types\n\n| Type                    | Values                                                             |\n| ----------------------- | ------------------------------------------------------------------ |\n| `MessageType`           | `User`, `Assistant`, `System`, `Result`, `StreamEvent`             |\n| `ContentBlockType`      | `Text`, `Thinking`, `ToolUse`, `ToolResult`                        |\n| `SystemMessageSubtype`  | `Init`, `CompactBoundary`                                          |\n| `ResultMessageSubtype`  | `Success`, `Error`, `Partial`                                      |\n| `McpServerStatusType`   | `Connected`, `Failed`, `NeedsAuth`, `Pending`                      |\n| `SessionStartSource`    | `Startup`, `Resume`, `Clear`, `Compact`                            |\n| `SessionEndReason`      | `Clear`, `Logout`, `PromptInputExit`, `BypassPermissionsDisabled`  |\n| `NotificationType`      | `PermissionPrompt`, `IdlePrompt`, `AuthSuccess`, `ElicitationDialog` |\n\n#### Generated Enum String Mappings\n\nEnums with `[GenerateEnumStrings]` have compile-time generated conversion methods:\n\n```csharp\nusing Claude.AgentSdk.Types;\n\n// Convert enum to JSON string\nvar jsonValue = MessageType.StreamEvent.ToJsonString();  // \"stream_event\"\nvar status = McpServerStatusType.NeedsAuth.ToJsonString();  // \"needs-auth\"\n\n// Parse string to enum\nvar messageType = EnumStringMappings.ParseMessageType(\"assistant\");  // MessageType.Assistant\nvar serverStatus = EnumStringMappings.ParseMcpServerStatusType(\"connected\");  // McpServerStatusType.Connected\n\n// Safe parsing with TryParse\nif (EnumStringMappings.TryParseResultMessageSubtype(\"success\", out var subtype))\n{\n    Console.WriteLine($\"Parsed: {subtype}\");  // ResultMessageSubtype.Success\n}\n```\n\n**Benefits over `Enum.Parse`:**\n- **Compile-time generated**: No reflection, better performance\n- **Type-safe**: Each enum has dedicated Parse/TryParse methods\n- **JSON-compatible**: Handles snake_case and kebab-case naming conventions\n\n#### Functional Match Patterns\n\nThe SDK generates functional `Match` extension methods for discriminated union types like `Message` and `ContentBlock`. Use them for exhaustive, type-safe pattern matching:\n\n```csharp\nusing Claude.AgentSdk.Messages;\n\n// Match with all cases (exhaustive)\nvar description = message.Match(\n    userMessage: u =\u003e $\"User: {u.MessageContent.Content}\",\n    assistantMessage: a =\u003e $\"Assistant response with {a.MessageContent.Content.Count} blocks\",\n    systemMessage: s =\u003e $\"System: {s.Subtype}\",\n    resultMessage: r =\u003e {\n        var ctx = r.Usage is not null ? $\"{r.Usage.TotalContextTokens / 1000.0:F0}k\" : \"?\";\n        return $\"[{r.DurationMs/1000.0:F1}s | ${r.TotalCostUsd:F4} | {ctx}]\";\n    },\n    streamEvent: e =\u003e $\"Stream event: {e.Uuid}\"\n);\n\n// Match with default for partial handling\nvar isFromClaude = message.Match(\n    assistantMessage: _ =\u003e true,\n    defaultCase: () =\u003e false\n);\n\n// Match on content blocks\nforeach (var block in assistant.MessageContent.Content)\n{\n    var text = block.Match(\n        textBlock: t =\u003e t.Text,\n        thinkingBlock: t =\u003e $\"[thinking: {t.Thinking.Length} chars]\",\n        toolUseBlock: t =\u003e $\"[tool: {t.Name}]\",\n        toolResultBlock: t =\u003e t.Content?.ToString() ?? \"\"\n    );\n    Console.WriteLine(text);\n}\n\n// Action-based matching (void return)\nmessage.Match(\n    userMessage: u =\u003e Console.WriteLine($\"User said: {u.MessageContent.Content}\"),\n    assistantMessage: a =\u003e ProcessAssistantResponse(a),\n    systemMessage: s =\u003e LogSystemEvent(s),\n    resultMessage: r =\u003e RecordCost(r),\n    streamEvent: _ =\u003e { }  // Ignore stream events\n);\n```\n\n**Benefits:**\n- **Exhaustive checking**: Compiler ensures all cases are handled\n- **Type inference**: Each handler receives the correct derived type\n- **Default support**: Handle subset of cases with `defaultCase`\n- **Generated at compile-time**: No runtime reflection\n\n#### Message Processing Extensions\n\nThe SDK provides extension methods to simplify common message processing tasks:\n\n```csharp\nusing Claude.AgentSdk.Extensions;\nusing Claude.AgentSdk.Messages;\n\nawait foreach (var message in client.QueryAsync(prompt))\n{\n    if (message is AssistantMessage assistant)\n    {\n        // Get all text content combined\n        var fullText = assistant.GetText();\n        Console.WriteLine(fullText);\n\n        // Get all tool uses\n        foreach (var toolUse in assistant.GetToolUses())\n        {\n            Console.WriteLine($\"Tool: {toolUse.Name}\");\n\n            // Get typed input\n            var input = toolUse.GetInput\u003cSearchInput\u003e();\n            if (input != null)\n                Console.WriteLine($\"Query: {input.Query}\");\n        }\n\n        // Check if specific tool was used\n        if (assistant.HasToolUse(ToolName.Bash))\n            Console.WriteLine(\"Bash command executed\");\n\n        // Get thinking blocks (for extended thinking)\n        foreach (var thinking in assistant.GetThinking())\n        {\n            Console.WriteLine($\"[Thinking: {thinking.Thinking.Length} chars]\");\n        }\n    }\n}\n\nrecord SearchInput(string Query, int? Limit);\n```\n\n#### Content Block Extensions\n\nExtension methods for type-safe content block handling:\n\n```csharp\nusing Claude.AgentSdk.Extensions;\nusing Claude.AgentSdk.Messages;\n\nforeach (var block in assistant.MessageContent.Content)\n{\n    // Type checking\n    if (block.IsText())\n        Console.Write(block.AsText());\n\n    if (block.IsToolUse())\n    {\n        var toolUse = block.AsToolUse()!;\n        Console.WriteLine($\"[{toolUse.Name}]\");\n    }\n\n    if (block.IsThinking())\n        Console.Write(\"[thinking...]\");\n\n    if (block.IsToolResult())\n    {\n        var result = block.AsToolResult()!;\n        Console.WriteLine($\"Result: {result.Content}\");\n    }\n}\n```\n\n**Available Extension Methods:**\n\n| Method | Description |\n|--------|-------------|\n| `GetText()` | Concatenates all text blocks |\n| `GetToolUses()` | Returns all tool use blocks |\n| `GetThinking()` | Returns all thinking blocks |\n| `HasToolUse(ToolName)` | Checks if specific tool was used |\n| `GetInput\u003cT\u003e()` | Deserializes tool input to type |\n| `IsText()` / `AsText()` | Type check and conversion for text |\n| `IsToolUse()` / `AsToolUse()` | Type check and conversion for tool use |\n| `IsThinking()` / `AsThinking()` | Type check and conversion for thinking |\n| `IsToolResult()` / `AsToolResult()` | Type check and conversion for tool result |\n\n#### Hook Input Enum Accessors\n\n```csharp\n[HookEvent.SessionStart] = new[]\n{\n    new HookMatcher\n    {\n        Hooks = new HookCallback[]\n        {\n            async (input, toolUseId, context, ct) =\u003e\n            {\n                if (input is SessionStartHookInput start)\n                {\n                    // Use SourceEnum for type-safe source checking\n                    if (start.SourceEnum == SessionStartSource.Resume)\n                        Console.WriteLine(\"Resumed previous session\");\n                }\n                return new SyncHookOutput { Continue = true };\n            }\n        }\n    }\n},\n[HookEvent.Notification] = new[]\n{\n    new HookMatcher\n    {\n        Hooks = new HookCallback[]\n        {\n            async (input, toolUseId, context, ct) =\u003e\n            {\n                if (input is NotificationHookInput notification)\n                {\n                    // Use NotificationTypeEnum for type-safe handling\n                    if (notification.NotificationTypeEnum == NotificationType.PermissionPrompt)\n                        await SendSlackNotification(notification.Message);\n                }\n                return new SyncHookOutput { Continue = true };\n            }\n        }\n    }\n}\n```\n\n### Skills\n\nSkills extend Claude with specialized capabilities that Claude autonomously invokes when relevant. Skills are defined as `SKILL.md` files (not programmatically).\n\n#### Enabling Skills\n\n```csharp\nvar options = new ClaudeAgentOptions\n{\n    WorkingDirectory = \"/path/to/project\",  // Project with .claude/skills/\n\n    // REQUIRED: Load skills from filesystem\n    SettingSources = [SettingSource.Project, SettingSource.User],\n\n    // REQUIRED: Enable the Skill tool\n    AllowedTools = [\"Skill\", \"Read\", \"Write\", \"Bash\"]\n};\n\nvar client = new ClaudeAgentClient(options);\n\n// Claude automatically invokes relevant skills based on your request\nawait foreach (var msg in client.QueryAsync(\"Help me process this PDF document\"))\n{\n    // If a PDF processing skill exists, Claude will use it\n}\n```\n\n#### Skill Locations\n\n| Location       | Path                          | Loaded When             |\n| -------------- | ----------------------------- | ----------------------- |\n| Project Skills | `.claude/skills/*/SKILL.md`   | `SettingSource.Project` |\n| User Skills    | `~/.claude/skills/*/SKILL.md` | `SettingSource.User`    |\n\n#### Creating Skills\n\nSkills are directories containing a `SKILL.md` file:\n\n**`.claude/skills/pdf-processor/SKILL.md`:**\n```markdown\n---\ndescription: Extract and process text from PDF documents\n---\n\n# PDF Processing Skill\n\nWhen the user needs to extract text from PDFs:\n\n1. Use `pdftotext` or similar tools to extract content\n2. Clean and format the extracted text\n3. Return structured results\n\n## Example Usage\n- \"Extract text from invoice.pdf\"\n- \"Process all PDFs in the documents folder\"\n```\n\n#### Discovering Available Skills\n\n```csharp\n// Ask Claude what skills are available\nawait foreach (var msg in client.QueryAsync(\"What Skills are available?\"))\n{\n    if (msg is AssistantMessage assistant)\n    {\n        // Claude lists available skills based on current directory\n    }\n}\n```\n\n#### Key Points\n\n- **Filesystem-only**: Skills cannot be defined programmatically (unlike Subagents)\n- **`SettingSources` required**: Skills won't load without explicit `SettingSources` configuration\n- **Auto-invoked**: Claude decides when to use skills based on their `description` field\n- **Tool restrictions**: Control available tools via `AllowedTools` in your options\n\n### Plugins\n\nPlugins are packages of Claude Code extensions that can include commands, agents, skills, hooks, and MCP servers.\n\n#### Loading Plugins\n\n```csharp\nvar options = new ClaudeAgentOptions\n{\n    Plugins = [\n        new PluginConfig { Path = \"./my-plugin\" },\n        new PluginConfig { Path = \"/absolute/path/to/another-plugin\" }\n    ]\n};\n\nvar client = new ClaudeAgentClient(options);\n\nawait foreach (var msg in client.QueryAsync(\"Hello\"))\n{\n    if (msg is SystemMessage sys \u0026\u0026 sys.IsInit)\n    {\n        // Plugin commands, agents, and features are now available\n        Console.WriteLine($\"Commands: {string.Join(\", \", sys.SlashCommands ?? [])}\");\n        // Example: /help, /compact, my-plugin:custom-command\n    }\n}\n```\n\n#### Using Plugin Commands\n\nPlugin commands are namespaced as `plugin-name:command-name`:\n\n```csharp\n// Use a plugin command\nawait foreach (var msg in client.QueryAsync(\"/my-plugin:greet\"))\n{\n    // Claude executes the custom greeting command from the plugin\n}\n```\n\n#### Plugin Structure\n\nPlugins are directories with a `.claude-plugin/plugin.json` manifest:\n\n```\nmy-plugin/\n├── .claude-plugin/\n│   └── plugin.json          # Required: plugin manifest\n├── commands/                 # Custom slash commands\n│   └── custom-cmd.md\n├── agents/                   # Custom agents\n│   └── specialist.md\n├── skills/                   # Agent Skills\n│   └── my-skill/\n│       └── SKILL.md\n├── hooks/                    # Event handlers\n│   └── hooks.json\n└── .mcp.json                # MCP server definitions\n```\n\n#### Multiple Plugins\n\n```csharp\nvar options = new ClaudeAgentOptions\n{\n    Plugins = [\n        new PluginConfig { Path = \"./local-plugin\" },\n        new PluginConfig { Path = \"./project-plugins/team-workflows\" },\n        new PluginConfig { Path = \"~/.claude/custom-plugins/shared-plugin\" }\n    ]\n};\n```\n\n#### PluginConfig Properties\n\n| Property | Type     | Description                                     |\n| -------- | -------- | ----------------------------------------------- |\n| `Type`   | `string` | Plugin type (default: \"local\")                  |\n| `Path`   | `string` | Path to plugin directory (relative or absolute) |\n\n### Structured Outputs\n\nGet responses in a specific JSON schema:\n\n```csharp\nvar options = new ClaudeAgentOptions\n{\n    OutputFormat = JsonDocument.Parse(\"\"\"\n    {\n        \"type\": \"json_schema\",\n        \"json_schema\": {\n            \"name\": \"analysis\",\n            \"strict\": true,\n            \"schema\": {\n                \"type\": \"object\",\n                \"properties\": {\n                    \"summary\": { \"type\": \"string\" },\n                    \"sentiment\": {\n                        \"type\": \"string\",\n                        \"enum\": [\"positive\", \"negative\", \"neutral\"]\n                    },\n                    \"score\": { \"type\": \"number\" }\n                },\n                \"required\": [\"summary\", \"sentiment\", \"score\"],\n                \"additionalProperties\": false\n            }\n        }\n    }\n    \"\"\").RootElement\n};\n\nvar client = new ClaudeAgentClient(options);\n\nawait foreach (var msg in client.QueryAsync(\"Analyze: I love this product!\"))\n{\n    if (msg is AssistantMessage assistant)\n    {\n        var text = assistant.MessageContent.Content.OfType\u003cTextBlock\u003e().First();\n        var result = JsonSerializer.Deserialize\u003cAnalysisResult\u003e(text.Text);\n        Console.WriteLine($\"Sentiment: {result.Sentiment}, Score: {result.Score}\");\n    }\n}\n\nrecord AnalysisResult(string Summary, string Sentiment, double Score);\n```\n\n### Type-Safe Structured Outputs (Recommended)\n\nUse the `SchemaGenerator` to auto-generate JSON schemas from C# types:\n\n```csharp\nusing Claude.AgentSdk.Schema;\n\n// Define your output type with descriptions\n[Description(\"Analysis of text sentiment\")]\npublic record SentimentAnalysis\n{\n    [SchemaDescription(\"Brief summary of the text\")]\n    public required string Summary { get; init; }\n\n    [SchemaDescription(\"Overall sentiment of the text\")]\n    public required Sentiment Sentiment { get; init; }\n\n    [SchemaDescription(\"Confidence score from 0-1\")]\n    public required double Confidence { get; init; }\n}\n\npublic enum Sentiment { Positive, Negative, Neutral }\n\n// Generate schema automatically\nvar schema = SchemaGenerator.Generate\u003cSentimentAnalysis\u003e(\"sentiment_analysis\");\n\n// Or use the fluent extension method\nvar options = new ClaudeAgentOptions { Model = \"sonnet\" }\n    .WithStructuredOutput\u003cSentimentAnalysis\u003e();\n\nvar client = new ClaudeAgentClient(options);\n\nawait foreach (var msg in client.QueryAsync(\"Analyze: I love this product!\"))\n{\n    if (msg is AssistantMessage assistant)\n    {\n        // Type-safe parsing\n        var result = assistant.ParseStructuredOutput\u003cSentimentAnalysis\u003e();\n        Console.WriteLine($\"Sentiment: {result?.Sentiment}, Confidence: {result?.Confidence}\");\n    }\n}\n```\n\n### Hooks\n\nHooks let you intercept agent execution at key points to add validation, logging, security controls, or custom logic.\n\n#### Available Hook Events\n\n| Hook Event           | Description                             | Use Case                   |\n| -------------------- | --------------------------------------- | -------------------------- |\n| `PreToolUse`         | Before tool executes (can block/modify) | Block dangerous commands   |\n| `PostToolUse`        | After tool executes successfully        | Log file changes           |\n| `PostToolUseFailure` | When tool execution fails               | Handle errors              |\n| `UserPromptSubmit`   | When user prompt is submitted           | Inject context             |\n| `Stop`               | When agent execution stops              | Save session state         |\n| `SubagentStart`      | When subagent initializes               | Track parallel tasks       |\n| `SubagentStop`       | When subagent completes                 | Aggregate results          |\n| `PreCompact`         | Before conversation compaction          | Archive transcript         |\n| `PermissionRequest`  | When permission dialog would show       | Custom permission handling |\n| `SessionStart`       | When session initializes                | Initialize telemetry       |\n| `SessionEnd`         | When session terminates                 | Clean up resources         |\n| `Notification`       | For agent status messages               | Send to Slack/PagerDuty    |\n\n#### Basic Hook Example\n\n```csharp\nvar options = new ClaudeAgentOptions\n{\n    Hooks = new Dictionary\u003cHookEvent, IReadOnlyList\u003cHookMatcher\u003e\u003e\n    {\n        [HookEvent.PreToolUse] = new[]\n        {\n            new HookMatcher\n            {\n                Matcher = \"Bash\",  // Only for Bash tool (regex pattern)\n                Hooks = new HookCallback[]\n                {\n                    async (input, toolUseId, context, ct) =\u003e\n                    {\n                        if (input is PreToolUseHookInput pre)\n                        {\n                            Console.WriteLine($\"About to run: {pre.ToolInput}\");\n                        }\n                        return new SyncHookOutput { Continue = true };\n                    }\n                }\n            }\n        }\n    }\n};\n```\n\n#### Block Dangerous Operations\n\n```csharp\nvar options = new ClaudeAgentOptions\n{\n    Hooks = new Dictionary\u003cHookEvent, IReadOnlyList\u003cHookMatcher\u003e\u003e\n    {\n        [HookEvent.PreToolUse] = new[]\n        {\n            new HookMatcher\n            {\n                Matcher = \"Write|Edit\",  // Match file modification tools\n                Hooks = new HookCallback[]\n                {\n                    async (input, toolUseId, context, ct) =\u003e\n                    {\n                        if (input is PreToolUseHookInput pre)\n                        {\n                            var filePath = pre.ToolInput.GetProperty(\"file_path\").GetString();\n                            if (filePath?.EndsWith(\".env\") == true)\n                            {\n                                return new SyncHookOutput\n                                {\n                                    HookSpecificOutput = JsonSerializer.SerializeToElement(new\n                                    {\n                                        hookEventName = pre.HookEventName,\n                                        permissionDecision = \"deny\",\n                                        permissionDecisionReason = \"Cannot modify .env files\"\n                                    })\n                                };\n                            }\n                        }\n                        return new SyncHookOutput { Continue = true };\n                    }\n                }\n            }\n        }\n    }\n};\n```\n\n#### Session Lifecycle Hooks\n\n```csharp\nvar options = new ClaudeAgentOptions\n{\n    Hooks = new Dictionary\u003cHookEvent, IReadOnlyList\u003cHookMatcher\u003e\u003e\n    {\n        [HookEvent.SessionStart] = new[]\n        {\n            new HookMatcher\n            {\n                Hooks = new HookCallback[]\n                {\n                    async (input, toolUseId, context, ct) =\u003e\n                    {\n                        if (input is SessionStartHookInput start)\n                        {\n                            Console.WriteLine($\"Session started: {start.Source}\");\n                        }\n                        return new SyncHookOutput { Continue = true };\n                    }\n                }\n            }\n        },\n        [HookEvent.SessionEnd] = new[]\n        {\n            new HookMatcher\n            {\n                Hooks = new HookCallback[]\n                {\n                    async (input, toolUseId, context, ct) =\u003e\n                    {\n                        if (input is SessionEndHookInput end)\n                        {\n                            Console.WriteLine($\"Session ended: {end.Reason}\");\n                        }\n                        return new SyncHookOutput { Continue = true };\n                    }\n                }\n            }\n        },\n        [HookEvent.Notification] = new[]\n        {\n            new HookMatcher\n            {\n                Hooks = new HookCallback[]\n                {\n                    async (input, toolUseId, context, ct) =\u003e\n                    {\n                        if (input is NotificationHookInput notification)\n                        {\n                            Console.WriteLine($\"[{notification.NotificationType}] {notification.Message}\");\n                        }\n                        return new SyncHookOutput { Continue = true };\n                    }\n                }\n            }\n        }\n    }\n};\n```\n\n#### Hook Input Types\n\n| Input Type                    | Properties                                         |\n| ----------------------------- | -------------------------------------------------- |\n| `PreToolUseHookInput`         | `ToolName`, `ToolInput`                            |\n| `PostToolUseHookInput`        | `ToolName`, `ToolInput`, `ToolResponse`            |\n| `PostToolUseFailureHookInput` | `ToolName`, `ToolInput`, `Error`, `IsInterrupt`    |\n| `UserPromptSubmitHookInput`   | `Prompt`                                           |\n| `StopHookInput`               | `StopHookActive`                                   |\n| `SubagentStartHookInput`      | `AgentId`, `AgentType`                             |\n| `SubagentStopHookInput`       | `StopHookActive`, `AgentId`, `AgentTranscriptPath` |\n| `PreCompactHookInput`         | `Trigger`, `CustomInstructions`                    |\n| `PermissionRequestHookInput`  | `ToolName`, `ToolInput`, `PermissionSuggestions`   |\n| `SessionStartHookInput`       | `Source`                                           |\n| `SessionEndHookInput`         | `Reason`                                           |\n| `NotificationHookInput`       | `Message`, `NotificationType`, `Title`             |\n\nAll input types also include common fields: `SessionId`, `TranscriptPath`, `Cwd`, `PermissionMode`.\n\n#### Declarative Hook Registration\n\nUse attributes to define hooks declaratively instead of building dictionaries manually:\n\n```csharp\nusing Claude.AgentSdk.Attributes;\nusing Claude.AgentSdk.Protocol;\n\n[GenerateHookRegistration]  // Generates GetHooksCompiled() extension method\npublic class SecurityHooks\n{\n    [HookHandler(HookEvent.PreToolUse, Matcher = \"Bash\")]\n    public Task\u003cHookOutput\u003e ValidateBashCommand(HookInput input, string? toolUseId,\n        HookContext ctx, CancellationToken ct)\n    {\n        if (input is PreToolUseHookInput pre)\n        {\n            var command = pre.ToolInput.GetProperty(\"command\").GetString();\n            if (command?.Contains(\"rm -rf\") == true)\n            {\n                return Task.FromResult\u003cHookOutput\u003e(new SyncHookOutput\n                {\n                    Continue = false,\n                    Decision = \"block\",\n                    StopReason = \"Dangerous command blocked\"\n                });\n            }\n        }\n        return Task.FromResult\u003cHookOutput\u003e(new SyncHookOutput { Continue = true });\n    }\n\n    [HookHandler(HookEvent.PreToolUse, Matcher = \"Write|Edit\")]\n    public Task\u003cHookOutput\u003e ValidateFileWrites(HookInput input, string? toolUseId,\n        HookContext ctx, CancellationToken ct)\n    {\n        if (input is PreToolUseHookInput pre)\n        {\n            var path = pre.ToolInput.GetProperty(\"file_path\").GetString();\n            if (path?.EndsWith(\".env\") == true)\n            {\n                return Task.FromResult\u003cHookOutput\u003e(new SyncHookOutput\n                {\n                    Continue = false,\n                    Decision = \"block\",\n                    StopReason = \"Cannot modify .env files\"\n                });\n            }\n        }\n        return Task.FromResult\u003cHookOutput\u003e(new SyncHookOutput { Continue = true });\n    }\n\n    [HookHandler(HookEvent.SessionStart)]\n    public Task\u003cHookOutput\u003e OnSessionStart(HookInput input, string? toolUseId,\n        HookContext ctx, CancellationToken ct)\n    {\n        Console.WriteLine($\"Session started: {ctx.SessionId}\");\n        return Task.FromResult\u003cHookOutput\u003e(new SyncHookOutput { Continue = true });\n    }\n}\n\n// Usage with generated extension method\nvar hooks = new SecurityHooks();\nvar options = new ClaudeAgentOptions\n{\n    Hooks = hooks.GetHooksCompiled(),  // No manual dictionary building!\n    AllowedTools = [\"Bash\", \"Write\", \"Edit\", \"Read\"]\n};\n```\n\n**HookHandler Attribute Properties:**\n\n| Property | Type | Description |\n|----------|------|-------------|\n| `HookEvent` | `HookEvent` | Required. The event type (constructor parameter) |\n| `Matcher` | `string?` | Regex pattern to match (e.g., tool names) |\n| `Timeout` | `double` | Timeout in seconds for this hook |\n\n#### Parameter Validation in Tools\n\nThe `[ToolParameter]` attribute constraints are now enforced at runtime:\n\n```csharp\n[GenerateToolRegistration]\npublic class ValidatedTools\n{\n    [ClaudeTool(\"search\", \"Search for items\")]\n    public string Search(\n        [ToolParameter(Description = \"Search query\", MinLength = 1, MaxLength = 100)]\n        string query,\n\n        [ToolParameter(Description = \"Results limit\", MinValue = 1, MaxValue = 50)]\n        int limit = 10,\n\n        [ToolParameter(Description = \"Filter pattern\", Pattern = @\"^[a-zA-Z0-9_-]+$\")]\n        string? filter = null)\n    {\n        // Implementation - validation happens before this code runs\n        return $\"Searching for: {query}\";\n    }\n}\n```\n\n**Generated Validation:**\n- String length checks (`MinLength`, `MaxLength`)\n- Numeric range checks (`MinValue`, `MaxValue`)\n- Pattern matching via regex (`Pattern`)\n- Array length checks for collection parameters\n\nInvalid inputs return `ToolResult.Error()` with descriptive messages before the method executes.\n\n### Dependency Injection (ASP.NET Core)\n\nThe `AJGit.Claude.AgentSdk.Extensions.DependencyInjection` package provides integration with Microsoft.Extensions.DependencyInjection.\n\n#### Installation\n\n```bash\ndotnet add package AJGit.Claude.AgentSdk.Extensions.DependencyInjection\n```\n\n#### Basic Registration\n\n```csharp\nusing Claude.AgentSdk.Extensions.DependencyInjection;\n\nservices.AddClaudeAgent(options =\u003e\n{\n    options.Model = \"sonnet\";\n    options.MaxTurns = 10;\n    options.AllowedTools = [\"Read\", \"Write\", \"Bash\"];\n});\n```\n\n#### Configuration from appsettings.json\n\n```csharp\nservices.AddClaudeAgent(configuration.GetSection(\"Claude\"));\n```\n\n```json\n{\n  \"Claude\": {\n    \"Model\": \"sonnet\",\n    \"MaxTurns\": 10,\n    \"MaxBudgetUsd\": 1.0,\n    \"AllowedTools\": [\"Read\", \"Write\", \"Bash\"],\n    \"PermissionMode\": \"AcceptEdits\"\n  }\n}\n```\n\n#### Named Instances for Multi-Agent Scenarios\n\n```csharp\n// Register multiple agents with different configurations\nservices.AddClaudeAgent(\"analyzer\", options =\u003e\n{\n    options.Model = \"sonnet\";\n    options.SystemPrompt = \"You analyze code for issues.\";\n});\n\nservices.AddClaudeAgent(\"generator\", options =\u003e\n{\n    options.Model = \"opus\";\n    options.SystemPrompt = \"You generate high-quality code.\";\n});\n\n// Resolve via factory\npublic class MyService\n{\n    private readonly IClaudeAgentClientFactory _factory;\n\n    public MyService(IClaudeAgentClientFactory factory) =\u003e _factory = factory;\n\n    public async Task AnalyzeAsync()\n    {\n        var analyzer = _factory.CreateClient(\"analyzer\");\n        // ...\n    }\n}\n```\n\n#### MCP Tool Server Registration\n\n```csharp\nservices.AddClaudeAgent(options =\u003e options.Model = \"sonnet\")\n    .AddMcpServer(\"tools\", myToolServer)\n    .AddMcpServer\u003cMyToolServer\u003e(\"custom\");\n```\n\n#### Health Checks\n\n```csharp\nservices.AddHealthChecks()\n    .AddClaudeAgentCheck();\n```\n\n### Functional Programming\n\nThe SDK includes functional types for safer, more composable code.\n\n#### Option\u0026lt;T\u0026gt; for Null Safety\n\n```csharp\nusing Claude.AgentSdk.Functional;\n\n// Create options\nOption\u003cstring\u003e some = Option.Some(\"hello\");\nOption\u003cstring\u003e none = Option.NoneOf\u003cstring\u003e();\nOption\u003cstring\u003e fromNullable = Option.FromNullable(possiblyNull);\n\n// Chain operations safely\nvar result = GetUserInput()\n    .Map(s =\u003e s.Trim())\n    .Where(s =\u003e !string.IsNullOrEmpty(s))\n    .Bind(ParseCommand);\n\n// Pattern match\nresult.Match(\n    some: cmd =\u003e ProcessCommand(cmd),\n    none: () =\u003e ShowHelp()\n);\n\n// Get value with defaults\nvar value = option.GetValueOrDefault(\"fallback\");\nvar lazyValue = option.GetValueOrElse(() =\u003e ExpensiveComputation());\n```\n\n#### Result\u0026lt;T\u0026gt; for Error Handling\n\n```csharp\nusing Claude.AgentSdk.Functional;\n\n// Create results\nResult\u003cint\u003e success = Result.Success(42);\nResult\u003cint\u003e failure = Result.Failure\u003cint\u003e(\"Something went wrong\");\n\n// Wrap operations that can throw\nvar result = await Result.TryAsync(async () =\u003e\n{\n    await using var client = new ClaudeAgentClient(options);\n    await using var session = await client.CreateSessionAsync();\n    return await ProcessAsync(session);\n});\n\n// Chain operations with automatic error propagation\nvar processed = result\n    .Map(data =\u003e Transform(data))\n    .Bind(data =\u003e Validate(data))\n    .Ensure(data =\u003e data.IsValid, \"Validation failed\");\n\n// Handle both cases\nprocessed.Match(\n    success: data =\u003e Console.WriteLine($\"Success: {data}\"),\n    failure: error =\u003e Console.WriteLine($\"Error: {error}\")\n);\n```\n\n#### Pipeline\u0026lt;TIn, TOut\u0026gt; for Composable Processing\n\n```csharp\nusing Claude.AgentSdk.Functional;\n\n// Build a processing pipeline\nvar pipeline = Pipeline\n    .StartWith\u003cMessage, ProcessingResult\u003e(ProcessMessage);\n\n// Or chain multiple steps\nvar pipeline = Pipeline\n    .Start\u003cstring\u003e()\n    .Then(ValidateInput)\n    .ThenBind(ParseJson)\n    .Then(TransformData)\n    .ThenTap(LogSuccess);\n\n// Run the pipeline\nResult\u003cProcessingResult\u003e result = pipeline.Run(input);\n```\n\n#### Validation\u0026lt;T\u0026gt; for Accumulating Errors\n\n```csharp\nusing Claude.AgentSdk.Functional;\n\n// Validate multiple fields, accumulating all errors\nvar validation = Validation.Success\u003cUser, string\u003e(new User())\n    .Ensure(u =\u003e !string.IsNullOrEmpty(u.Email), \"Email is required\")\n    .Ensure(u =\u003e u.Email.Contains('@'), \"Email must be valid\")\n    .Ensure(u =\u003e u.Age \u003e= 18, \"Must be 18 or older\");\n\n// Check all errors at once\nif (validation.IsFailure)\n{\n    foreach (var error in validation.Errors)\n        Console.WriteLine($\"- {error}\");\n}\n```\n\n#### Functional Collection Extensions\n\n```csharp\nusing Claude.AgentSdk.Functional;\n\n// Choose: Filter and transform in one operation\nvar actions = blocks.Choose(block =\u003e block switch\n{\n    TextBlock text =\u003e Option.Some\u003cAction\u003e(() =\u003e Console.Write(text.Text)),\n    ToolUseBlock tool =\u003e Option.Some\u003cAction\u003e(() =\u003e PrintTool(tool)),\n    _ =\u003e Option.NoneOf\u003cAction\u003e()\n});\n\n// Sequence: Convert IEnumerable\u003cOption\u003cT\u003e\u003e to Option\u003cIEnumerable\u003cT\u003e\u003e\nvar allValues = options.Sequence();  // None if any is None\n\n// Traverse: Map and sequence in one operation\nvar results = items.Traverse(item =\u003e TryParse(item));\n```\n\n## v1 Behavioral Contract\n\nThis section describes the expected runtime behavior of the SDK in v1.\n\n### Lifetimes\n\n- `ClaudeAgentClient` is **stateless**. It does not own long-lived resources.\n- `ClaudeAgentSession` **owns the connection** to the Claude CLI and must be disposed when finished.\n\n### Cancellation \u0026 disposal\n\n- Disposing a `ClaudeAgentSession` cancels the session's internal cancellation token and initiates shutdown of the underlying transport.\n- Any active message enumeration from `ReceiveAsync()` / `ReceiveResponseAsync()` is expected to stop when the session is disposed.\n\n### Streaming \u0026 backpressure\n\n- Bidirectional sessions use a **bounded internal buffer** for messages.\n- If you do **not** enumerate the receive stream, the SDK may apply backpressure and message processing can appear to stall.\n  For interactive scenarios, always run a receive loop (even if you ignore messages).\n\n### Errors\n\n- If the underlying transport/protocol fails, the message stream will typically **fault** (throw) during `await foreach`.\n- `OperationCanceledException` is expected when you cancel/dispose a session.\n- For diagnostics, `ClaudeAgentSession.TerminalException` may be set after the stream ends.\n\n## API Reference\n\n### ClaudeAgentClient\n\n| Method                                         | Description                                                   |\n| ---------------------------------------------- | ------------------------------------------------------------- |\n| `QueryAsync(prompt, options?, ct)`             | Execute a one-shot query, streaming responses                 |\n| `QueryToCompletionAsync(prompt, options?, ct)` | Execute and wait for final result                             |\n| `CreateSessionAsync(ct)`                       | Create a bidirectional session (returns `ClaudeAgentSession`) |\n\n### ClaudeAgentSession\n\n| Method                             | Description                           |\n| ---------------------------------- | ------------------------------------- |\n| `SendAsync(content, sessionId?)`   | Send message in bidirectional mode    |\n| `ReceiveAsync(ct)`                 | Receive all messages (continuous)     |\n| `ReceiveResponseAsync(ct)`         | Receive until ResultMessage (typical) |\n| `InterruptAsync(ct)`               | Send interrupt signal                 |\n| `CancelAsync(ct)`                  | Cancel the session                    |\n| `SetPermissionModeAsync(mode, ct)` | Change permission mode                |\n| `SetModelAsync(model, ct)`         | Change model                          |\n\n### ClaudeAgentOptions\n\n| Property                 | Type                            | Description                                           |\n| ------------------------ | ------------------------------- | ----------------------------------------------------- |\n| `Model`                  | `string?`                       | Model to use (sonnet, opus, haiku)                    |\n| `MaxTurns`               | `int?`                          | Maximum conversation turns                            |\n| `SystemPrompt`           | `SystemPromptConfig?`           | System prompt (string, preset, or preset with append) |\n| `SettingSources`         | `IReadOnlyList\u003cSettingSource\u003e?` | Sources for loading CLAUDE.md files                   |\n| `Tools`                  | `IReadOnlyList\u003cstring\u003e?`        | Tools to enable                                       |\n| `AllowedTools`           | `IReadOnlyList\u003cstring\u003e`         | Additional allowed tools                              |\n| `DisallowedTools`        | `IReadOnlyList\u003cstring\u003e`         | Tools to disable                                      |\n| `WorkingDirectory`       | `string?`                       | Working directory for agent                           |\n| `CliPath`                | `string?`                       | Path to Claude CLI (default: search PATH)             |\n| `CanUseTool`             | `Func\u003c...\u003e?`                    | Permission callback                                   |\n| `Hooks`                  | `IReadOnlyDictionary\u003c...\u003e?`     | Hook configurations                                   |\n| `McpServers`             | `IReadOnlyDictionary\u003c...\u003e?`     | MCP server configurations                             |\n| `OutputFormat`           | `JsonElement?`                  | Structured output schema                              |\n| `PermissionMode`         | `PermissionMode?`               | Permission mode                                       |\n| `MaxThinkingTokens`      | `int?`                          | Max tokens for thinking                               |\n| `IncludePartialMessages` | `bool`                          | Include streaming partial messages                    |\n\n### SystemPromptConfig Types\n\n| Type                 | Description                                      |\n| -------------------- | ------------------------------------------------ |\n| `CustomSystemPrompt` | Custom string prompt (replaces default entirely) |\n| `PresetSystemPrompt` | Preset configuration with optional append text   |\n\n### SettingSource Values\n\n| Value     | Description                                               |\n| --------- | --------------------------------------------------------- |\n| `Project` | Load CLAUDE.md from project directory                     |\n| `User`    | Load ~/.claude/CLAUDE.md (user-level)                     |\n| `Local`   | Load CLAUDE.local.md from project (gitignored local file) |\n\n### Message Types\n\n| Type               | Description                           |\n| ------------------ | ------------------------------------- |\n| `UserMessage`      | User input message                    |\n| `AssistantMessage` | Claude's response with content blocks |\n| `SystemMessage`    | System metadata message               |\n| `ResultMessage`    | Final result with cost/usage info     |\n| `StreamEvent`      | Partial streaming update              |\n\n### Content Blocks\n\n| Type              | Description               |\n| ----------------- | ------------------------- |\n| `TextBlock`       | Text content              |\n| `ThinkingBlock`   | Extended thinking content |\n| `ToolUseBlock`    | Tool invocation request   |\n| `ToolResultBlock` | Tool execution result     |\n\n## Architecture\n\n```\n┌─────────────────────────────────────────┐\n│         ClaudeAgentClient               │\n│  - QueryAsync() / CreateSessionAsync()  │\n├─────────────────────────────────────────┤\n│          ClaudeAgentSession             │\n│  - SendAsync() / ReceiveAsync()         │\n│  - Bidirectional communication          │\n├─────────────────────────────────────────┤\n│           QueryHandler                  │\n│  - Control protocol routing             │\n│  - Permission/hook handling             │\n│  - MCP tool dispatch                    │\n├─────────────────────────────────────────┤\n│        SubprocessTransport              │\n│  - CLI process management               │\n│  - JSONL stdin/stdout I/O               │\n├─────────────────────────────────────────┤\n│         Claude Code CLI                 │\n│  (external binary - handles API calls)  │\n└─────────────────────────────────────────┘\n```\n\n## Examples\n\nThe SDK includes several example projects demonstrating different features and use cases.\n\n### Quick Start Examples\n\n**Claude.AgentSdk.Examples** - Interactive menu with 13 SDK feature demonstrations:\n\n```bash\ncd examples/Claude.AgentSdk.Examples\ndotnet run              # Shows interactive menu\ndotnet run -- 1         # Run specific example by number\n```\n\nExamples included:\n1. Basic Query - Simple one-shot query\n2. Streaming - Stream responses as they arrive\n3. Interactive Session - Bidirectional conversation\n4. Custom Tools - MCP SDK tools in C#\n5. Hooks - PreToolUse/PostToolUse hooks\n6. Subagents - Spawning specialized subagents\n7. Structured Output - JSON schema responses\n8. Permission Handler - Tool permission callbacks\n9. System Prompt - Custom and preset prompts\n10. Settings Sources - Loading CLAUDE.md files\n11. MCP Servers - External MCP server configuration\n12. Sandbox - Secure execution configuration\n13. Functional Patterns - Result, Option, Pipeline usage\n\n### Standalone Examples\n\n**HelloWorld** - Basic query with file restriction hooks:\n```bash\ncd examples/Claude.AgentSdk.HelloWorld\ndotnet run                          # Default greeting\ndotnet run -- \"Your prompt here\"    # Custom prompt\n```\n\n**SimpleChatApp** - Multi-turn interactive chat:\n```bash\ncd examples/Claude.AgentSdk.SimpleChatApp\ndotnet run    # Interactive REPL with /clear and /exit commands\n```\n\n**FunctionalChatApp** - Chat app using functional programming patterns:\n```bash\ncd examples/Claude.AgentSdk.FunctionalChatApp\ndotnet run    # Demonstrates Result, Option, Pipeline, and immutable state\n```\n\n**ResearchAgent** - Multi-agent orchestration with researcher and report-writer subagents:\n```bash\ncd examples/Claude.AgentSdk.ResearchAgent\ndotnet run                    # Interactive mode\ndotnet run -- --auto          # Auto-run with default prompt\ndotnet run -- \"Your topic\"    # Research specific topic\n```\n\n**ResumeGenerator** - Web search and document generation:\n```bash\ncd examples/Claude.AgentSdk.ResumeGenerator\ndotnet run -- \"Person Name\"   # Generate resume for a person\n```\n\n**EmailAgent** - Custom MCP tools for email management (mock inbox):\n```bash\ncd examples/Claude.AgentSdk.EmailAgent\ndotnet run    # Interactive email assistant\n```\n\n**ExcelAgent** - Custom MCP tools for Excel spreadsheet creation:\n```bash\ncd examples/Claude.AgentSdk.ExcelAgent\ndotnet run    # Interactive spreadsheet builder\n```\n\n**SignalR** - ASP.NET Core web app with real-time Claude integration:\n```bash\ncd examples/Claude.AgentSdk.SignalR\ndotnet run    # Starts server at http://localhost:5000\n```\n\n**SubagentTest** - Diagnostic tool for testing subagent configurations:\n```bash\ncd examples/Claude.AgentSdk.SubagentTest\ndotnet run                    # Standard test\ndotnet run -- --diagnostic    # Full diagnostic with hooks\ndotnet run -- --cli-args      # Show CLI arguments\n```\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fajgit%2Fclaude.agentsdk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fajgit%2Fclaude.agentsdk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fajgit%2Fclaude.agentsdk/lists"}