[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6G9GM1V63PP4R36PRB4TTHS":3,"skill-same:01M6G9GM1V63PP4R36PRB4TTHS":74},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":22,"publishedAt":43,"linkOnly":44,"markdownContent":45,"markdownBody":46,"frontMatter":47,"refName":48,"commitSha":49,"skillDirectory":50,"forksCount":13,"repositoryHtmlUrl":51,"repositoryHomepageUrl":6,"ownerHtmlUrl":52,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":53,"install":54,"resources":67},"01M6G9GM1V63PP4R36PRB4TTHS","copilot-sdk",null,"Build applications powered by GitHub Copilot using the Copilot SDK. Use when creating programmatic integrations with Copilot across Node.js\u002FTypeScript, Python, Go, or .NET. Covers session management, custom tools, streaming, hooks, MCP servers, BYOK providers, session persistence, custom agents, skills, and deployment patterns. Requires GitHub Copilot CLI installed and a GitHub Copilot subscription (unless using BYOK).","ricardoaevt\u002Fnexus-roms","ricardoaevt","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F164531880?v=4","01M6DGFGSV6CF9AKPHABBREC79","01M6DGFGYNNPJVDFQA05TDPSBN",0,"AGPL-3.0","https:\u002F\u002Fgithub.com\u002Fricardoaevt\u002Fnexus-roms\u002Fblob\u002Fmain\u002F.agent\u002Fskills\u002Fmicrosoft_skills\u002F.github\u002Fskills\u002Fcopilot-sdk\u002FSKILL.md",[17],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42],"sdk","copilot","copilot sdk","Tools","programmatic","github copilot cli","session management","across","patterns","hooks","byok","node","Providers","MCP","custom agents","streaming","github copilot","go","typescript","cli","2026-11-10 10:12:30",false,"---\nname: copilot-sdk\ndescription: Build applications powered by GitHub Copilot using the Copilot SDK. Use when creating programmatic integrations with Copilot across Node.js\u002FTypeScript, Python, Go, or .NET. Covers session management, custom tools, streaming, hooks, MCP servers, BYOK providers, session persistence, custom agents, skills, and deployment patterns. Requires GitHub Copilot CLI installed and a GitHub Copilot subscription (unless using BYOK).\n---\n\n# GitHub Copilot SDK\n\nBuild applications that programmatically interact with GitHub Copilot. The SDK wraps the Copilot CLI via JSON-RPC, providing session management, custom tools, hooks, MCP server integration, and streaming across Node.js, Python, Go, and .NET.\n\n## Prerequisites\n\n- **GitHub Copilot CLI** installed and authenticated (`copilot --version`)\n- **GitHub Copilot subscription** (Individual, Business, or Enterprise) — not required for BYOK\n- **Runtime:** Node.js 18+ \u002F Python 3.8+ \u002F Go 1.21+ \u002F .NET 8.0+\n\n## Installation\n\n| Language | Package | Install |\n|----------|---------|---------|\n| Node.js | `@github\u002Fcopilot-sdk` | `npm install @github\u002Fcopilot-sdk` |\n| Python | `github-copilot-sdk` | `pip install github-copilot-sdk` |\n| Go | `github.com\u002Fgithub\u002Fcopilot-sdk\u002Fgo` | `go get github.com\u002Fgithub\u002Fcopilot-sdk\u002Fgo` |\n| .NET | `GitHub.Copilot.SDK` | `dotnet add package GitHub.Copilot.SDK` |\n\n## Architecture\n\nThe SDK communicates with the Copilot CLI via JSON-RPC over stdio (default) or TCP. The CLI manages model calls, tool execution, session state, and MCP server lifecycle.\n\n```\nYour App → SDK Client → [stdio\u002FTCP] → Copilot CLI → Model Provider\n                                          ↕\n                                     MCP Servers\n```\n\n**Transport modes:**\n\n| Mode | Description | Use Case |\n|------|-------------|----------|\n| **Stdio** (default) | CLI as subprocess via pipes | Local dev, single process |\n| **TCP** | CLI as network server | Multi-client, backend services |\n\n---\n\n## Core Pattern: Client → Session → Message\n\nAll SDK usage follows: create a client, create a session, send messages.\n\n### Node.js \u002F TypeScript\n\n```typescript\nimport { CopilotClient } from \"@github\u002Fcopilot-sdk\";\n\nconst client = new CopilotClient();\nconst session = await client.createSession({ model: \"gpt-4.1\" });\n\nconst response = await session.sendAndWait({ prompt: \"What is 2 + 2?\" });\nconsole.log(response?.data.content);\n\nawait client.stop();\n```\n\n### Python\n\n```python\nimport asyncio\nfrom copilot import CopilotClient\n\nasync def main():\n    client = CopilotClient()\n    await client.start()\n    session = await client.create_session({\"model\": \"gpt-4.1\"})\n    response = await session.send_and_wait({\"prompt\": \"What is 2 + 2?\"})\n    print(response.data.content)\n    await client.stop()\n\nasyncio.run(main())\n```\n\n### Go\n\n```go\nclient := copilot.NewClient(nil)\nif err := client.Start(ctx); err != nil { log.Fatal(err) }\ndefer client.Stop()\n\nsession, _ := client.CreateSession(ctx, &copilot.SessionConfig{Model: \"gpt-4.1\"})\nresponse, _ := session.SendAndWait(ctx, copilot.MessageOptions{Prompt: \"What is 2 + 2?\"})\nfmt.Println(*response.Data.Content)\n```\n\n### .NET\n\n```csharp\nawait using var client = new CopilotClient();\nawait using var session = await client.CreateSessionAsync(new SessionConfig { Model = \"gpt-4.1\" });\nvar response = await session.SendAndWaitAsync(new MessageOptions { Prompt = \"What is 2 + 2?\" });\nConsole.WriteLine(response?.Data.Content);\n```\n\n---\n\n## Streaming Responses\n\nEnable real-time output by setting `streaming: true` and subscribing to delta events.\n\n### Node.js\n\n```typescript\nconst session = await client.createSession({ model: \"gpt-4.1\", streaming: true });\n\nsession.on(\"assistant.message_delta\", (event) => {\n    process.stdout.write(event.data.deltaContent);\n});\nsession.on(\"session.idle\", () => console.log());\n\nawait session.sendAndWait({ prompt: \"Tell me a joke\" });\n```\n\n### Python\n\n```python\nfrom copilot.generated.session_events import SessionEventType\n\nsession = await client.create_session({\"model\": \"gpt-4.1\", \"streaming\": True})\n\ndef handle_event(event):\n    if event.type == SessionEventType.ASSISTANT_MESSAGE_DELTA:\n        sys.stdout.write(event.data.delta_content)\n        sys.stdout.flush()\n    if event.type == SessionEventType.SESSION_IDLE:\n        print()\n\nsession.on(handle_event)\nawait session.send_and_wait({\"prompt\": \"Tell me a joke\"})\n```\n\n### Event Subscription\n\n| Method | Description |\n|--------|-------------|\n| `on(handler)` | Subscribe to all events; returns unsubscribe function |\n| `on(eventType, handler)` | Subscribe to specific event type (Node.js only) |\n\nCall the returned function to unsubscribe. In .NET, call `.Dispose()` on the returned disposable.\n\n---\n\n## Custom Tools\n\nDefine tools that Copilot can call to extend its capabilities.\n\n### Node.js\n\n```typescript\nimport { CopilotClient, defineTool } from \"@github\u002Fcopilot-sdk\";\n\nconst getWeather = defineTool(\"get_weather\", {\n    description: \"Get the current weather for a city\",\n    parameters: {\n        type: \"object\",\n        properties: { city: { type: \"string\", description: \"The city name\" } },\n        required: [\"city\"],\n    },\n    handler: async ({ city }) => ({ city, temperature: \"72°F\", condition: \"sunny\" }),\n});\n\nconst session = await client.createSession({\n    model: \"gpt-4.1\",\n    tools: [getWeather],\n});\n```\n\n### Python\n\n```python\nfrom copilot.tools import define_tool\nfrom pydantic import BaseModel, Field\n\nclass GetWeatherParams(BaseModel):\n    city: str = Field(description=\"The city name\")\n\n@define_tool(description=\"Get the current weather for a city\")\nasync def get_weather(params: GetWeatherParams) -> dict:\n    return {\"city\": params.city, \"temperature\": \"72°F\", \"condition\": \"sunny\"}\n\nsession = await client.create_session({\"model\": \"gpt-4.1\", \"tools\": [get_weather]})\n```\n\n### Go\n\n```go\ntype WeatherParams struct {\n    City string `json:\"city\" jsonschema:\"The city name\"`\n}\n\ngetWeather := copilot.DefineTool(\"get_weather\", \"Get weather for a city\",\n    func(params WeatherParams, inv copilot.ToolInvocation) (WeatherResult, error) {\n        return WeatherResult{City: params.City, Temperature: \"72°F\"}, nil\n    },\n)\n\nsession, _ := client.CreateSession(ctx, &copilot.SessionConfig{\n    Model: \"gpt-4.1\",\n    Tools: []copilot.Tool{getWeather},\n})\n```\n\n### .NET\n\n```csharp\nusing Microsoft.Extensions.AI;\nusing System.ComponentModel;\n\nvar getWeather = AIFunctionFactory.Create(\n    ([Description(\"The city name\")] string city) => new { city, temperature = \"72°F\" },\n    \"get_weather\", \"Get the current weather for a city\");\n\nawait using var session = await client.CreateSessionAsync(new SessionConfig {\n    Model = \"gpt-4.1\", Tools = [getWeather],\n});\n```\n\n### Tool Requirements\n\n- Handler must return JSON-serializable data (not `undefined`)\n- Parameters must follow JSON Schema format\n- Tool description should clearly state when the tool should be used\n\n---\n\n## Hooks\n\nIntercept and customize session behavior at key lifecycle points.\n\n| Hook | Trigger | Use Case |\n|------|---------|----------|\n| `onPreToolUse` | Before tool executes | Permission control, argument modification |\n| `onPostToolUse` | After tool executes | Result transformation, logging, redaction |\n| `onUserPromptSubmitted` | User sends message | Prompt modification, filtering, context injection |\n| `onSessionStart` | Session begins (new or resumed) | Add context, configure session |\n| `onSessionEnd` | Session ends | Cleanup, analytics, metrics |\n| `onErrorOccurred` | Error happens | Custom error handling, retry logic, monitoring |\n\n### Pre-Tool Use Hook\n\nControl tool permissions, modify arguments, or inject context before tool execution.\n\n```typescript\nconst session = await client.createSession({\n    hooks: {\n        onPreToolUse: async (input) => {\n            if ([\"shell\", \"bash\"].includes(input.toolName)) {\n                return { permissionDecision: \"deny\", permissionDecisionReason: \"Shell access not permitted\" };\n            }\n            return { permissionDecision: \"allow\" };\n        },\n    },\n});\n```\n\n**Input fields:** `timestamp`, `cwd`, `toolName`, `toolArgs`\n\n**Output fields:**\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `permissionDecision` | `\"allow\"` \\| `\"deny\"` \\| `\"ask\"` | Whether to allow the tool call |\n| `permissionDecisionReason` | string | Explanation for deny\u002Fask |\n| `modifiedArgs` | object | Modified arguments to pass |\n| `additionalContext` | string | Extra context for conversation |\n| `suppressOutput` | boolean | Hide tool output from conversation |\n\n### Post-Tool Use Hook\n\nTransform results, redact sensitive data, or log tool activity after execution.\n\n```typescript\nhooks: {\n    onPostToolUse: async (input) => {\n        \u002F\u002F Redact sensitive data from results\n        if (typeof input.toolResult === \"string\") {\n            let redacted = input.toolResult;\n            for (const pattern of SENSITIVE_PATTERNS) {\n                redacted = redacted.replace(pattern, \"[REDACTED]\");\n            }\n            if (redacted !== input.toolResult) {\n                return { modifiedResult: redacted };\n            }\n        }\n        return null; \u002F\u002F Pass through unchanged\n    },\n}\n```\n\n**Output fields:** `modifiedResult`, `additionalContext`, `suppressOutput`\n\n### User Prompt Submitted Hook\n\nModify or enhance user prompts before processing. Useful for prompt templates, context injection, and input validation.\n\n```typescript\nhooks: {\n    onUserPromptSubmitted: async (input) => {\n        return {\n            modifiedPrompt: `[User from engineering team] ${input.prompt}`,\n            additionalContext: \"Follow company coding standards.\",\n        };\n    },\n}\n```\n\n**Output fields:** `modifiedPrompt`, `additionalContext`, `suppressOutput`\n\n### Session Lifecycle Hooks\n\n```typescript\nhooks: {\n    onSessionStart: async (input, invocation) => {\n        \u002F\u002F input.source: \"startup\" | \"resume\" | \"new\"\n        console.log(`Session ${invocation.sessionId} started (${input.source})`);\n        return { additionalContext: \"Project uses TypeScript and React.\" };\n    },\n    onSessionEnd: async (input, invocation) => {\n        \u002F\u002F input.reason: \"complete\" | \"error\" | \"abort\" | \"timeout\" | \"user_exit\"\n        await recordMetrics({ sessionId: invocation.sessionId, reason: input.reason });\n        return null;\n    },\n}\n```\n\n### Error Handling Hook\n\n```typescript\nhooks: {\n    onErrorOccurred: async (input) => {\n        \u002F\u002F input.errorContext: \"model_call\" | \"tool_execution\" | \"system\" | \"user_input\"\n        \u002F\u002F input.recoverable: boolean\n        if (input.errorContext === \"model_call\" && input.error.includes(\"rate\")) {\n            return { errorHandling: \"retry\", retryCount: 3, userNotification: \"Rate limited. Retrying...\" };\n        }\n        return null; \u002F\u002F Default error handling\n    },\n}\n```\n\n**Output fields:** `suppressOutput`, `errorHandling` (`\"retry\"` | `\"skip\"` | `\"abort\"`), `retryCount`, `userNotification`\n\n### Python Hook Example\n\n```python\nasync def on_pre_tool_use(input_data, invocation):\n    if input_data[\"toolName\"] in [\"shell\", \"bash\"]:\n        return {\"permissionDecision\": \"deny\", \"permissionDecisionReason\": \"Not permitted\"}\n    return {\"permissionDecision\": \"allow\"}\n\nsession = await client.create_session({\n    \"hooks\": {\"on_pre_tool_use\": on_pre_tool_use}\n})\n```\n\n### Go Hook Example\n\n```go\nsession, _ := client.CreateSession(ctx, &copilot.SessionConfig{\n    Hooks: &copilot.SessionHooks{\n        OnPreToolUse: func(input copilot.PreToolUseHookInput, inv copilot.HookInvocation) (*copilot.PreToolUseHookOutput, error) {\n            return &copilot.PreToolUseHookOutput{PermissionDecision: \"allow\"}, nil\n        },\n    },\n})\n```\n\n---\n\n## MCP Server Integration\n\nConnect to MCP (Model Context Protocol) servers for pre-built tool capabilities.\n\n### Local Stdio Server\n\n```typescript\nconst session = await client.createSession({\n    mcpServers: {\n        filesystem: {\n            type: \"local\",\n            command: \"npx\",\n            args: [\"-y\", \"@modelcontextprotocol\u002Fserver-filesystem\", \"\u002Fallowed\u002Fpath\"],\n            tools: [\"*\"],\n            env: { DEBUG: \"true\" },\n            cwd: \".\u002Fservers\",\n            timeout: 30000,\n        },\n    },\n});\n```\n\n### Remote HTTP Server\n\n```typescript\nconst session = await client.createSession({\n    mcpServers: {\n        github: {\n            type: \"http\",\n            url: \"https:\u002F\u002Fapi.githubcopilot.com\u002Fmcp\u002F\",\n            headers: { Authorization: \"Bearer ${TOKEN}\" },\n            tools: [\"*\"],\n        },\n    },\n});\n```\n\n### MCP Config Fields\n\n**Local\u002FStdio:**\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| `type` | `\"local\"` | No | Defaults to local |\n| `command` | string | Yes | Executable path |\n| `args` | string[] | Yes | Command arguments |\n| `env` | object | No | Environment variables |\n| `cwd` | string | No | Working directory |\n| `tools` | string[] | No | `[\"*\"]` for all, `[]` for none |\n| `timeout` | number | No | Timeout in milliseconds |\n\n**Remote HTTP:**\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| `type` | `\"http\"` | Yes | Server type |\n| `url` | string | Yes | Server URL |\n| `headers` | object | No | HTTP headers |\n| `tools` | string[] | No | Tool filter |\n| `timeout` | number | No | Timeout in ms |\n\n### MCP Debugging\n\nTest MCP servers independently before integrating:\n\n```bash\necho '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"initialize\",\"params\":{\"protocolVersion\":\"2024-11-05\",\"capabilities\":{},\"clientInfo\":{\"name\":\"test\",\"version\":\"1.0\"}}}' | \u002Fpath\u002Fto\u002Fyour\u002Fmcp-server\n```\n\nUse the MCP Inspector for interactive debugging:\n\n```bash\nnpx @modelcontextprotocol\u002Finspector \u002Fpath\u002Fto\u002Fyour\u002Fmcp-server\n```\n\n**Common MCP issues:**\n- Tools not appearing → Set `tools: [\"*\"]` and verify server responds to `tools\u002Flist`\n- Server not starting → Use absolute command paths, check `cwd`\n- Stdout pollution → Debug output must go to stderr, not stdout\n\n---\n\n## Authentication\n\n### Methods (Priority Order)\n\n1. **Explicit token** — `githubToken` in constructor\n2. **HMAC key** — `CAPI_HMAC_KEY` or `COPILOT_HMAC_KEY` env vars\n3. **Direct API token** — `GITHUB_COPILOT_API_TOKEN` with `COPILOT_API_URL`\n4. **Environment variables** — `COPILOT_GITHUB_TOKEN` → `GH_TOKEN` → `GITHUB_TOKEN`\n5. **Stored OAuth** — From `copilot auth login`\n6. **GitHub CLI** — `gh auth` credentials\n\n### Programmatic Token\n\n```typescript\nconst client = new CopilotClient({ githubToken: process.env.GITHUB_TOKEN });\n```\n\n### OAuth GitHub App\n\nFor multi-user apps where users sign in with GitHub:\n\n```typescript\nconst client = new CopilotClient({\n    githubToken: userAccessToken,    \u002F\u002F gho_ or ghu_ token from OAuth flow\n    useLoggedInUser: false,          \u002F\u002F Don't use stored CLI credentials\n});\n```\n\n**Supported token types:** `gho_` (OAuth), `ghu_` (GitHub App), `github_pat_` (fine-grained PAT).\n**Not supported:** `ghp_` (classic PAT — deprecated).\n\n### Disable Auto-Login\n\nPrevent the SDK from using stored credentials:\n\n```typescript\nconst client = new CopilotClient({ useLoggedInUser: false });\n```\n\n---\n\n## BYOK (Bring Your Own Key)\n\nUse your own API keys — no Copilot subscription required. The CLI acts as agent runtime only.\n\n### Provider Configurations\n\n**OpenAI:**\n```typescript\nprovider: { type: \"openai\", baseUrl: \"https:\u002F\u002Fapi.openai.com\u002Fv1\", apiKey: process.env.OPENAI_API_KEY }\n```\n\n**Azure AI Foundry (OpenAI-compatible):**\n```typescript\nprovider: {\n    type: \"openai\",\n    baseUrl: \"https:\u002F\u002Fyour-resource.openai.azure.com\u002Fopenai\u002Fv1\u002F\",\n    apiKey: process.env.FOUNDRY_API_KEY,\n    wireApi: \"responses\",  \u002F\u002F Use \"responses\" for GPT-5 series, \"completions\" for others\n}\n```\n\n**Azure OpenAI (native endpoint):**\n```typescript\nprovider: {\n    type: \"azure\",\n    baseUrl: \"https:\u002F\u002Fmy-resource.openai.azure.com\",  \u002F\u002F Just the host — no \u002Fopenai\u002Fv1\n    apiKey: process.env.AZURE_OPENAI_KEY,\n    azure: { apiVersion: \"2024-10-21\" },\n}\n```\n\n**Anthropic:**\n```typescript\nprovider: { type: \"anthropic\", baseUrl: \"https:\u002F\u002Fapi.anthropic.com\", apiKey: process.env.ANTHROPIC_API_KEY }\n```\n\n**Ollama (local):**\n```typescript\nprovider: { type: \"openai\", baseUrl: \"http:\u002F\u002Flocalhost:11434\u002Fv1\" }\n```\n\n### Provider Config Reference\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `type` | `\"openai\"` \\| `\"azure\"` \\| `\"anthropic\"` | Provider type |\n| `baseUrl` | string | **Required.** API endpoint URL |\n| `apiKey` | string | API key (optional for local providers) |\n| `bearerToken` | string | Bearer token auth (takes precedence over apiKey) |\n| `wireApi` | `\"completions\"` \\| `\"responses\"` | API format (default: `\"completions\"`) |\n| `azure.apiVersion` | string | Azure API version (default: `\"2024-10-21\"`) |\n\n### Azure Managed Identity with BYOK\n\nUse `DefaultAzureCredential` to get short-lived bearer tokens for Azure deployments:\n\n```python\nfrom azure.identity import DefaultAzureCredential\nfrom copilot import CopilotClient, ProviderConfig, SessionConfig\n\ncredential = DefaultAzureCredential()\ntoken = credential.get_token(\"https:\u002F\u002Fcognitiveservices.azure.com\u002F.default\").token\n\nsession = await client.create_session(SessionConfig(\n    model=\"gpt-4.1\",\n    provider=ProviderConfig(\n        type=\"openai\",\n        base_url=f\"{foundry_url}\u002Fopenai\u002Fv1\u002F\",\n        bearer_token=token,\n        wire_api=\"responses\",\n    ),\n))\n```\n\n> **Note:** Bearer tokens expire (~1 hour). For long-running apps, refresh the token before each new session. The SDK does not auto-refresh tokens.\n\n### BYOK Limitations\n\n- **Static credentials only** — no native Entra ID, OIDC, or managed identity support\n- **No auto-refresh** — expired tokens require creating a new session\n- **Keys not persisted** — must re-provide `provider` config on session resume\n- **Model availability** — limited to what your provider offers\n\n---\n\n## Session Persistence\n\nResume sessions across restarts by providing your own session ID.\n\n```typescript\n\u002F\u002F Create with explicit ID\nconst session = await client.createSession({\n    sessionId: \"user-123-task-456\",\n    model: \"gpt-4.1\",\n});\n\n\u002F\u002F Resume later (even from a different client instance)\nconst resumed = await client.resumeSession(\"user-123-task-456\");\nawait resumed.sendAndWait({ prompt: \"What did we discuss?\" });\n```\n\n### Session Management\n\n```typescript\nconst sessions = await client.listSessions();           \u002F\u002F List all\nconst lastId = await client.getLastSessionId();          \u002F\u002F Get most recent\nawait client.deleteSession(\"user-123-task-456\");         \u002F\u002F Delete from storage\nawait session.destroy();                                 \u002F\u002F Destroy active session\n```\n\n### Resume Options\n\nWhen resuming, you can reconfigure: `model`, `systemMessage`, `availableTools`, `excludedTools`, `provider` (required for BYOK), `reasoningEffort`, `streaming`, `mcpServers`, `customAgents`, `skillDirectories`, `infiniteSessions`.\n\n### Session ID Best Practices\n\n| Pattern | Example | Use Case |\n|---------|---------|----------|\n| `user-{userId}-{taskId}` | `user-alice-pr-review-42` | Multi-user apps |\n| `tenant-{tenantId}-{workflow}` | `tenant-acme-onboarding` | Multi-tenant SaaS |\n| `{userId}-{taskType}-{timestamp}` | `alice-deploy-1706932800` | Time-based cleanup |\n\n### What Gets Persisted\n\nSession state is saved to `~\u002F.copilot\u002Fsession-state\u002F{sessionId}\u002F`:\n\n| Data | Persisted? | Notes |\n|------|------------|-------|\n| Conversation history | ✅ Yes | Full message thread |\n| Tool call results | ✅ Yes | Cached for context |\n| Agent planning state | ✅ Yes | `plan.md` file |\n| Session artifacts | ✅ Yes | In `files\u002F` directory |\n| Provider\u002FAPI keys | ❌ No | Must re-provide on resume |\n| In-memory tool state | ❌ No | Design tools to be stateless |\n\n### Infinite Sessions\n\nFor long-running workflows that may exceed context limits, enable auto-compaction:\n\n```typescript\nconst session = await client.createSession({\n    infiniteSessions: {\n        enabled: true,\n        backgroundCompactionThreshold: 0.80,  \u002F\u002F Start background compaction at 80%\n        bufferExhaustionThreshold: 0.95,       \u002F\u002F Block and compact at 95%\n    },\n});\n```\n\n> Thresholds are context utilization ratios (0.0–1.0), not absolute token counts.\n\n---\n\n## Custom Agents\n\nDefine specialized AI personas:\n\n```typescript\nconst session = await client.createSession({\n    customAgents: [{\n        name: \"pr-reviewer\",\n        displayName: \"PR Reviewer\",\n        description: \"Reviews pull requests for best practices\",\n        prompt: \"You are an expert code reviewer. Focus on security, performance, and maintainability.\",\n    }],\n});\n```\n\n---\n\n## System Message\n\nControl AI behavior and personality:\n\n```typescript\nconst session = await client.createSession({\n    systemMessage: { content: \"You are a helpful assistant. Always be concise.\" },\n});\n```\n\n---\n\n## Skills Integration\n\nLoad skill directories to extend Copilot's capabilities:\n\n```typescript\nconst session = await client.createSession({\n    skillDirectories: [\".\u002Fskills\u002Fcode-review\", \".\u002Fskills\u002Fdocumentation\"],\n    disabledSkills: [\"experimental-feature\"],\n});\n```\n\nSkills can be combined with custom agents and MCP servers:\n\n```typescript\nconst session = await client.createSession({\n    skillDirectories: [\".\u002Fskills\u002Fsecurity\"],\n    customAgents: [{ name: \"auditor\", prompt: \"Focus on OWASP Top 10.\" }],\n    mcpServers: { postgres: { type: \"local\", command: \"npx\", args: [\"-y\", \"@modelcontextprotocol\u002Fserver-postgres\"], tools: [\"*\"] } },\n});\n```\n\n---\n\n## Permission & Input Handlers\n\nHandle tool permissions and user input requests programmatically. The SDK uses a **deny-by-default** permission model — all permission requests are denied unless you provide a handler.\n\n```typescript\nconst session = await client.createSession({\n    onPermissionRequest: async (request) => {\n        if (request.kind === \"shell\") {\n            return { approved: request.command.startsWith(\"git\") };\n        }\n        return { approved: true };\n    },\n    onUserInputRequest: async (request) => {\n        return { response: \"yes\" };\n    },\n});\n```\n\n### Token Usage Tracking\n\nSubscribe to usage events instead of using CLI `\u002Fusage`:\n\n```typescript\nsession.on(\"assistant.usage\", (event) => {\n    console.log(\"Tokens:\", { input: event.data.inputTokens, output: event.data.outputTokens });\n});\n```\n\n---\n\n## Deployment Patterns\n\n### Local CLI (Default)\n\nSDK auto-spawns CLI as subprocess. Simplest setup — zero configuration.\n\n```typescript\nconst client = new CopilotClient(); \u002F\u002F Auto-manages CLI process\n```\n\n### External CLI Server (Backend Services)\n\nRun CLI in headless mode, connect SDK over TCP:\n\n```bash\ncopilot --headless --port 4321\n```\n\n```typescript\nconst client = new CopilotClient({ cliUrl: \"localhost:4321\" });\n```\n\n**Multi-client support:** Multiple SDK clients can share one CLI server.\n\n### Bundled CLI (Desktop Apps)\n\nShip CLI binary with your app:\n\n```typescript\nconst client = new CopilotClient({ cliPath: path.join(__dirname, \"vendor\", \"copilot\") });\n```\n\n### Docker Compose\n\n```yaml\nservices:\n  copilot-cli:\n    image: ghcr.io\u002Fgithub\u002Fcopilot-cli:latest\n    command: [\"--headless\", \"--port\", \"4321\"]\n    environment:\n      - COPILOT_GITHUB_TOKEN=${COPILOT_GITHUB_TOKEN}\n    volumes:\n      - session-data:\u002Froot\u002F.copilot\u002Fsession-state\n  api:\n    build: .\n    environment:\n      - CLI_URL=copilot-cli:4321\n    depends_on: [copilot-cli]\nvolumes:\n  session-data:\n```\n\n### Session Isolation Patterns\n\n| Pattern | Isolation | Resources | Best For |\n|---------|-----------|-----------|----------|\n| **CLI per user** | Complete | High | Multi-tenant SaaS, compliance |\n| **Shared CLI + session IDs** | Logical | Low | Internal tools |\n| **Shared sessions** | None | Low | Team collaboration (requires locking) |\n\n### Production Checklist\n\n- Session cleanup: periodic deletion of expired sessions\n- Health checks: ping CLI server, restart if unresponsive\n- Persistent storage: mount `~\u002F.copilot\u002Fsession-state\u002F` for containers\n- Secret management: use Vault\u002FK8s Secrets for tokens\n- Session locking: Redis or similar for shared session access\n- Graceful shutdown: drain active sessions before stopping CLI\n\n---\n\n## Client Configuration\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `cliPath` | string | Auto-detected | Path to Copilot CLI executable |\n| `cliUrl` | string | — | URL of external CLI server |\n| `githubToken` | string | — | GitHub token for auth |\n| `useLoggedInUser` | boolean | `true` | Use stored CLI credentials |\n| `logLevel` | string | `\"none\"` | `\"none\"` \\| `\"error\"` \\| `\"warning\"` \\| `\"info\"` \\| `\"debug\"` |\n| `autoRestart` | boolean | `true` | Auto-restart CLI on crash |\n| `useStdio` | boolean | `true` | Use stdio transport |\n\n## Session Configuration\n\n| Option | Type | Description |\n|--------|------|-------------|\n| `model` | string | Model to use (e.g., `\"gpt-4.1\"`, `\"claude-sonnet-4\"`) |\n| `sessionId` | string | Custom ID for resumable sessions |\n| `streaming` | boolean | Enable streaming responses |\n| `tools` | Tool[] | Custom tools |\n| `mcpServers` | object | MCP server configurations |\n| `hooks` | object | Session hooks |\n| `provider` | object | BYOK provider config |\n| `customAgents` | object[] | Custom agent definitions |\n| `systemMessage` | object | System message override |\n| `skillDirectories` | string[] | Directories to load skills from |\n| `disabledSkills` | string[] | Skills to disable |\n| `reasoningEffort` | string | Reasoning effort level |\n| `availableTools` | string[] | Restrict available tools |\n| `excludedTools` | string[] | Exclude specific tools |\n| `infiniteSessions` | object | Auto-compaction config |\n| `workingDirectory` | string | Working directory |\n\n---\n\n## SDK vs CLI Feature Comparison\n\n### ✅ Available in SDK\n\nSession management, messaging (`send`\u002F`sendAndWait`\u002F`abort`), message history (`getMessages`), custom tools, tool permission hooks, MCP servers (local + HTTP), streaming, model selection, BYOK providers, custom agents, system message, skills, infinite sessions, permission handlers, 40+ event types.\n\n### ❌ CLI-Only Features\n\nSession export (`--share`), slash commands, interactive UI, terminal rendering, YOLO mode, login\u002Flogout flows, `\u002Fcompact` (use `infiniteSessions` instead), `\u002Fusage` (use usage events), `\u002Freview`, `\u002Fdelegate`.\n\n**Workarounds:**\n- Session export → Collect events manually with `session.on()` + `session.getMessages()`\n- Permission control → Use `onPermissionRequest` handler instead of `--allow-all-paths`\n- Context compaction → Use `infiniteSessions` config instead of `\u002Fcompact`\n\n---\n\n## Debugging\n\nEnable debug logging:\n\n```typescript\nconst client = new CopilotClient({ logLevel: \"debug\" });\n```\n\nCustom log directory:\n\n```typescript\nconst client = new CopilotClient({ cliArgs: [\"--log-dir\", \"\u002Fpath\u002Fto\u002Flogs\"] });\n```\n\n### Common Issues\n\n| Issue | Cause | Solution |\n|-------|-------|----------|\n| `CLI not found` | CLI not installed or not in PATH | Install CLI or set `cliPath` |\n| `Not authenticated` | No valid credentials | Run `copilot auth login` or provide `githubToken` |\n| `Session not found` | Using session after `destroy()` | Check `listSessions()` for valid IDs |\n| `Connection refused` | CLI process crashed | Enable `autoRestart: true`, check port conflicts |\n| MCP tools missing | Server init failure or tools not enabled | Set `tools: [\"*\"]`, test server independently |\n\n### Connection State\n\n```typescript\nconsole.log(\"State:\", client.getState());  \u002F\u002F \"connected\" after start()\nclient.on(\"stateChange\", (state) => console.log(\"Changed to:\", state));\n```\n\n---\n\n## Key API Summary\n\n| Language | Client | Session Create | Send | Resume | Stop |\n|----------|--------|---------------|------|--------|------|\n| Node.js | `new CopilotClient()` | `client.createSession()` | `session.sendAndWait()` | `client.resumeSession()` | `client.stop()` |\n| Python | `CopilotClient()` | `client.create_session()` | `session.send_and_wait()` | `client.resume_session()` | `client.stop()` |\n| Go | `copilot.NewClient(nil)` | `client.CreateSession()` | `session.SendAndWait()` | `client.ResumeSession()` | `client.Stop()` |\n| .NET | `new CopilotClient()` | `client.CreateSessionAsync()` | `session.SendAndWaitAsync()` | `client.ResumeSessionAsync()` | `client.DisposeAsync()` |\n\n## References\n\n- [GitHub Copilot SDK](https:\u002F\u002Fgithub.com\u002Fgithub\u002Fcopilot-sdk)\n- [Copilot CLI Installation](https:\u002F\u002Fdocs.github.com\u002Fen\u002Fcopilot\u002Fhow-tos\u002Fset-up\u002Finstall-copilot-cli)\n- [MCP Protocol Specification](https:\u002F\u002Fmodelcontextprotocol.io)\n- [MCP Servers Directory](https:\u002F\u002Fgithub.com\u002Fmodelcontextprotocol\u002Fservers)\n- [GitHub MCP Server](https:\u002F\u002Fgithub.com\u002Fgithub\u002Fgithub-mcp-server)\n","# GitHub Copilot SDK\n\nBuild applications that programmatically interact with GitHub Copilot. The SDK wraps the Copilot CLI via JSON-RPC, providing session management, custom tools, hooks, MCP server integration, and streaming across Node.js, Python, Go, and .NET.\n\n## Prerequisites\n\n- **GitHub Copilot CLI** installed and authenticated (`copilot --version`)\n- **GitHub Copilot subscription** (Individual, Business, or Enterprise) — not required for BYOK\n- **Runtime:** Node.js 18+ \u002F Python 3.8+ \u002F Go 1.21+ \u002F .NET 8.0+\n\n## Installation\n\n| Language | Package | Install |\n|----------|---------|---------|\n| Node.js | `@github\u002Fcopilot-sdk` | `npm install @github\u002Fcopilot-sdk` |\n| Python | `github-copilot-sdk` | `pip install github-copilot-sdk` |\n| Go | `github.com\u002Fgithub\u002Fcopilot-sdk\u002Fgo` | `go get github.com\u002Fgithub\u002Fcopilot-sdk\u002Fgo` |\n| .NET | `GitHub.Copilot.SDK` | `dotnet add package GitHub.Copilot.SDK` |\n\n## Architecture\n\nThe SDK communicates with the Copilot CLI via JSON-RPC over stdio (default) or TCP. The CLI manages model calls, tool execution, session state, and MCP server lifecycle.\n\n```\nYour App → SDK Client → [stdio\u002FTCP] → Copilot CLI → Model Provider\n                                          ↕\n                                     MCP Servers\n```\n\n**Transport modes:**\n\n| Mode | Description | Use Case |\n|------|-------------|----------|\n| **Stdio** (default) | CLI as subprocess via pipes | Local dev, single process |\n| **TCP** | CLI as network server | Multi-client, backend services |\n\n---\n\n## Core Pattern: Client → Session → Message\n\nAll SDK usage follows: create a client, create a session, send messages.\n\n### Node.js \u002F TypeScript\n\n```typescript\nimport { CopilotClient } from \"@github\u002Fcopilot-sdk\";\n\nconst client = new CopilotClient();\nconst session = await client.createSession({ model: \"gpt-4.1\" });\n\nconst response = await session.sendAndWait({ prompt: \"What is 2 + 2?\" });\nconsole.log(response?.data.content);\n\nawait client.stop();\n```\n\n### Python\n\n```python\nimport asyncio\nfrom copilot import CopilotClient\n\nasync def main():\n    client = CopilotClient()\n    await client.start()\n    session = await client.create_session({\"model\": \"gpt-4.1\"})\n    response = await session.send_and_wait({\"prompt\": \"What is 2 + 2?\"})\n    print(response.data.content)\n    await client.stop()\n\nasyncio.run(main())\n```\n\n### Go\n\n```go\nclient := copilot.NewClient(nil)\nif err := client.Start(ctx); err != nil { log.Fatal(err) }\ndefer client.Stop()\n\nsession, _ := client.CreateSession(ctx, &copilot.SessionConfig{Model: \"gpt-4.1\"})\nresponse, _ := session.SendAndWait(ctx, copilot.MessageOptions{Prompt: \"What is 2 + 2?\"})\nfmt.Println(*response.Data.Content)\n```\n\n### .NET\n\n```csharp\nawait using var client = new CopilotClient();\nawait using var session = await client.CreateSessionAsync(new SessionConfig { Model = \"gpt-4.1\" });\nvar response = await session.SendAndWaitAsync(new MessageOptions { Prompt = \"What is 2 + 2?\" });\nConsole.WriteLine(response?.Data.Content);\n```\n\n---\n\n## Streaming Responses\n\nEnable real-time output by setting `streaming: true` and subscribing to delta events.\n\n### Node.js\n\n```typescript\nconst session = await client.createSession({ model: \"gpt-4.1\", streaming: true });\n\nsession.on(\"assistant.message_delta\", (event) => {\n    process.stdout.write(event.data.deltaContent);\n});\nsession.on(\"session.idle\", () => console.log());\n\nawait session.sendAndWait({ prompt: \"Tell me a joke\" });\n```\n\n### Python\n\n```python\nfrom copilot.generated.session_events import SessionEventType\n\nsession = await client.create_session({\"model\": \"gpt-4.1\", \"streaming\": True})\n\ndef handle_event(event):\n    if event.type == SessionEventType.ASSISTANT_MESSAGE_DELTA:\n        sys.stdout.write(event.data.delta_content)\n        sys.stdout.flush()\n    if event.type == SessionEventType.SESSION_IDLE:\n        print()\n\nsession.on(handle_event)\nawait session.send_and_wait({\"prompt\": \"Tell me a joke\"})\n```\n\n### Event Subscription\n\n| Method | Description |\n|--------|-------------|\n| `on(handler)` | Subscribe to all events; returns unsubscribe function |\n| `on(eventType, handler)` | Subscribe to specific event type (Node.js only) |\n\nCall the returned function to unsubscribe. In .NET, call `.Dispose()` on the returned disposable.\n\n---\n\n## Custom Tools\n\nDefine tools that Copilot can call to extend its capabilities.\n\n### Node.js\n\n```typescript\nimport { CopilotClient, defineTool } from \"@github\u002Fcopilot-sdk\";\n\nconst getWeather = defineTool(\"get_weather\", {\n    description: \"Get the current weather for a city\",\n    parameters: {\n        type: \"object\",\n        properties: { city: { type: \"string\", description: \"The city name\" } },\n        required: [\"city\"],\n    },\n    handler: async ({ city }) => ({ city, temperature: \"72°F\", condition: \"sunny\" }),\n});\n\nconst session = await client.createSession({\n    model: \"gpt-4.1\",\n    tools: [getWeather],\n});\n```\n\n### Python\n\n```python\nfrom copilot.tools import define_tool\nfrom pydantic import BaseModel, Field\n\nclass GetWeatherParams(BaseModel):\n    city: str = Field(description=\"The city name\")\n\n@define_tool(description=\"Get the current weather for a city\")\nasync def get_weather(params: GetWeatherParams) -> dict:\n    return {\"city\": params.city, \"temperature\": \"72°F\", \"condition\": \"sunny\"}\n\nsession = await client.create_session({\"model\": \"gpt-4.1\", \"tools\": [get_weather]})\n```\n\n### Go\n\n```go\ntype WeatherParams struct {\n    City string `json:\"city\" jsonschema:\"The city name\"`\n}\n\ngetWeather := copilot.DefineTool(\"get_weather\", \"Get weather for a city\",\n    func(params WeatherParams, inv copilot.ToolInvocation) (WeatherResult, error) {\n        return WeatherResult{City: params.City, Temperature: \"72°F\"}, nil\n    },\n)\n\nsession, _ := client.CreateSession(ctx, &copilot.SessionConfig{\n    Model: \"gpt-4.1\",\n    Tools: []copilot.Tool{getWeather},\n})\n```\n\n### .NET\n\n```csharp\nusing Microsoft.Extensions.AI;\nusing System.ComponentModel;\n\nvar getWeather = AIFunctionFactory.Create(\n    ([Description(\"The city name\")] string city) => new { city, temperature = \"72°F\" },\n    \"get_weather\", \"Get the current weather for a city\");\n\nawait using var session = await client.CreateSessionAsync(new SessionConfig {\n    Model = \"gpt-4.1\", Tools = [getWeather],\n});\n```\n\n### Tool Requirements\n\n- Handler must return JSON-serializable data (not `undefined`)\n- Parameters must follow JSON Schema format\n- Tool description should clearly state when the tool should be used\n\n---\n\n## Hooks\n\nIntercept and customize session behavior at key lifecycle points.\n\n| Hook | Trigger | Use Case |\n|------|---------|----------|\n| `onPreToolUse` | Before tool executes | Permission control, argument modification |\n| `onPostToolUse` | After tool executes | Result transformation, logging, redaction |\n| `onUserPromptSubmitted` | User sends message | Prompt modification, filtering, context injection |\n| `onSessionStart` | Session begins (new or resumed) | Add context, configure session |\n| `onSessionEnd` | Session ends | Cleanup, analytics, metrics |\n| `onErrorOccurred` | Error happens | Custom error handling, retry logic, monitoring |\n\n### Pre-Tool Use Hook\n\nControl tool permissions, modify arguments, or inject context before tool execution.\n\n```typescript\nconst session = await client.createSession({\n    hooks: {\n        onPreToolUse: async (input) => {\n            if ([\"shell\", \"bash\"].includes(input.toolName)) {\n                return { permissionDecision: \"deny\", permissionDecisionReason: \"Shell access not permitted\" };\n            }\n            return { permissionDecision: \"allow\" };\n        },\n    },\n});\n```\n\n**Input fields:** `timestamp`, `cwd`, `toolName`, `toolArgs`\n\n**Output fields:**\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `permissionDecision` | `\"allow\"` \\| `\"deny\"` \\| `\"ask\"` | Whether to allow the tool call |\n| `permissionDecisionReason` | string | Explanation for deny\u002Fask |\n| `modifiedArgs` | object | Modified arguments to pass |\n| `additionalContext` | string | Extra context for conversation |\n| `suppressOutput` | boolean | Hide tool output from conversation |\n\n### Post-Tool Use Hook\n\nTransform results, redact sensitive data, or log tool activity after execution.\n\n```typescript\nhooks: {\n    onPostToolUse: async (input) => {\n        \u002F\u002F Redact sensitive data from results\n        if (typeof input.toolResult === \"string\") {\n            let redacted = input.toolResult;\n            for (const pattern of SENSITIVE_PATTERNS) {\n                redacted = redacted.replace(pattern, \"[REDACTED]\");\n            }\n            if (redacted !== input.toolResult) {\n                return { modifiedResult: redacted };\n            }\n        }\n        return null; \u002F\u002F Pass through unchanged\n    },\n}\n```\n\n**Output fields:** `modifiedResult`, `additionalContext`, `suppressOutput`\n\n### User Prompt Submitted Hook\n\nModify or enhance user prompts before processing. Useful for prompt templates, context injection, and input validation.\n\n```typescript\nhooks: {\n    onUserPromptSubmitted: async (input) => {\n        return {\n            modifiedPrompt: `[User from engineering team] ${input.prompt}`,\n            additionalContext: \"Follow company coding standards.\",\n        };\n    },\n}\n```\n\n**Output fields:** `modifiedPrompt`, `additionalContext`, `suppressOutput`\n\n### Session Lifecycle Hooks\n\n```typescript\nhooks: {\n    onSessionStart: async (input, invocation) => {\n        \u002F\u002F input.source: \"startup\" | \"resume\" | \"new\"\n        console.log(`Session ${invocation.sessionId} started (${input.source})`);\n        return { additionalContext: \"Project uses TypeScript and React.\" };\n    },\n    onSessionEnd: async (input, invocation) => {\n        \u002F\u002F input.reason: \"complete\" | \"error\" | \"abort\" | \"timeout\" | \"user_exit\"\n        await recordMetrics({ sessionId: invocation.sessionId, reason: input.reason });\n        return null;\n    },\n}\n```\n\n### Error Handling Hook\n\n```typescript\nhooks: {\n    onErrorOccurred: async (input) => {\n        \u002F\u002F input.errorContext: \"model_call\" | \"tool_execution\" | \"system\" | \"user_input\"\n        \u002F\u002F input.recoverable: boolean\n        if (input.errorContext === \"model_call\" && input.error.includes(\"rate\")) {\n            return { errorHandling: \"retry\", retryCount: 3, userNotification: \"Rate limited. Retrying...\" };\n        }\n        return null; \u002F\u002F Default error handling\n    },\n}\n```\n\n**Output fields:** `suppressOutput`, `errorHandling` (`\"retry\"` | `\"skip\"` | `\"abort\"`), `retryCount`, `userNotification`\n\n### Python Hook Example\n\n```python\nasync def on_pre_tool_use(input_data, invocation):\n    if input_data[\"toolName\"] in [\"shell\", \"bash\"]:\n        return {\"permissionDecision\": \"deny\", \"permissionDecisionReason\": \"Not permitted\"}\n    return {\"permissionDecision\": \"allow\"}\n\nsession = await client.create_session({\n    \"hooks\": {\"on_pre_tool_use\": on_pre_tool_use}\n})\n```\n\n### Go Hook Example\n\n```go\nsession, _ := client.CreateSession(ctx, &copilot.SessionConfig{\n    Hooks: &copilot.SessionHooks{\n        OnPreToolUse: func(input copilot.PreToolUseHookInput, inv copilot.HookInvocation) (*copilot.PreToolUseHookOutput, error) {\n            return &copilot.PreToolUseHookOutput{PermissionDecision: \"allow\"}, nil\n        },\n    },\n})\n```\n\n---\n\n## MCP Server Integration\n\nConnect to MCP (Model Context Protocol) servers for pre-built tool capabilities.\n\n### Local Stdio Server\n\n```typescript\nconst session = await client.createSession({\n    mcpServers: {\n        filesystem: {\n            type: \"local\",\n            command: \"npx\",\n            args: [\"-y\", \"@modelcontextprotocol\u002Fserver-filesystem\", \"\u002Fallowed\u002Fpath\"],\n            tools: [\"*\"],\n            env: { DEBUG: \"true\" },\n            cwd: \".\u002Fservers\",\n            timeout: 30000,\n        },\n    },\n});\n```\n\n### Remote HTTP Server\n\n```typescript\nconst session = await client.createSession({\n    mcpServers: {\n        github: {\n            type: \"http\",\n            url: \"https:\u002F\u002Fapi.githubcopilot.com\u002Fmcp\u002F\",\n            headers: { Authorization: \"Bearer ${TOKEN}\" },\n            tools: [\"*\"],\n        },\n    },\n});\n```\n\n### MCP Config Fields\n\n**Local\u002FStdio:**\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| `type` | `\"local\"` | No | Defaults to local |\n| `command` | string | Yes | Executable path |\n| `args` | string[] | Yes | Command arguments |\n| `env` | object | No | Environment variables |\n| `cwd` | string | No | Working directory |\n| `tools` | string[] | No | `[\"*\"]` for all, `[]` for none |\n| `timeout` | number | No | Timeout in milliseconds |\n\n**Remote HTTP:**\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| `type` | `\"http\"` | Yes | Server type |\n| `url` | string | Yes | Server URL |\n| `headers` | object | No | HTTP headers |\n| `tools` | string[] | No | Tool filter |\n| `timeout` | number | No | Timeout in ms |\n\n### MCP Debugging\n\nTest MCP servers independently before integrating:\n\n```bash\necho '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"initialize\",\"params\":{\"protocolVersion\":\"2024-11-05\",\"capabilities\":{},\"clientInfo\":{\"name\":\"test\",\"version\":\"1.0\"}}}' | \u002Fpath\u002Fto\u002Fyour\u002Fmcp-server\n```\n\nUse the MCP Inspector for interactive debugging:\n\n```bash\nnpx @modelcontextprotocol\u002Finspector \u002Fpath\u002Fto\u002Fyour\u002Fmcp-server\n```\n\n**Common MCP issues:**\n- Tools not appearing → Set `tools: [\"*\"]` and verify server responds to `tools\u002Flist`\n- Server not starting → Use absolute command paths, check `cwd`\n- Stdout pollution → Debug output must go to stderr, not stdout\n\n---\n\n## Authentication\n\n### Methods (Priority Order)\n\n1. **Explicit token** — `githubToken` in constructor\n2. **HMAC key** — `CAPI_HMAC_KEY` or `COPILOT_HMAC_KEY` env vars\n3. **Direct API token** — `GITHUB_COPILOT_API_TOKEN` with `COPILOT_API_URL`\n4. **Environment variables** — `COPILOT_GITHUB_TOKEN` → `GH_TOKEN` → `GITHUB_TOKEN`\n5. **Stored OAuth** — From `copilot auth login`\n6. **GitHub CLI** — `gh auth` credentials\n\n### Programmatic Token\n\n```typescript\nconst client = new CopilotClient({ githubToken: process.env.GITHUB_TOKEN });\n```\n\n### OAuth GitHub App\n\nFor multi-user apps where users sign in with GitHub:\n\n```typescript\nconst client = new CopilotClient({\n    githubToken: userAccessToken,    \u002F\u002F gho_ or ghu_ token from OAuth flow\n    useLoggedInUser: false,          \u002F\u002F Don't use stored CLI credentials\n});\n```\n\n**Supported token types:** `gho_` (OAuth), `ghu_` (GitHub App), `github_pat_` (fine-grained PAT).\n**Not supported:** `ghp_` (classic PAT — deprecated).\n\n### Disable Auto-Login\n\nPrevent the SDK from using stored credentials:\n\n```typescript\nconst client = new CopilotClient({ useLoggedInUser: false });\n```\n\n---\n\n## BYOK (Bring Your Own Key)\n\nUse your own API keys — no Copilot subscription required. The CLI acts as agent runtime only.\n\n### Provider Configurations\n\n**OpenAI:**\n```typescript\nprovider: { type: \"openai\", baseUrl: \"https:\u002F\u002Fapi.openai.com\u002Fv1\", apiKey: process.env.OPENAI_API_KEY }\n```\n\n**Azure AI Foundry (OpenAI-compatible):**\n```typescript\nprovider: {\n    type: \"openai\",\n    baseUrl: \"https:\u002F\u002Fyour-resource.openai.azure.com\u002Fopenai\u002Fv1\u002F\",\n    apiKey: process.env.FOUNDRY_API_KEY,\n    wireApi: \"responses\",  \u002F\u002F Use \"responses\" for GPT-5 series, \"completions\" for others\n}\n```\n\n**Azure OpenAI (native endpoint):**\n```typescript\nprovider: {\n    type: \"azure\",\n    baseUrl: \"https:\u002F\u002Fmy-resource.openai.azure.com\",  \u002F\u002F Just the host — no \u002Fopenai\u002Fv1\n    apiKey: process.env.AZURE_OPENAI_KEY,\n    azure: { apiVersion: \"2024-10-21\" },\n}\n```\n\n**Anthropic:**\n```typescript\nprovider: { type: \"anthropic\", baseUrl: \"https:\u002F\u002Fapi.anthropic.com\", apiKey: process.env.ANTHROPIC_API_KEY }\n```\n\n**Ollama (local):**\n```typescript\nprovider: { type: \"openai\", baseUrl: \"http:\u002F\u002Flocalhost:11434\u002Fv1\" }\n```\n\n### Provider Config Reference\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `type` | `\"openai\"` \\| `\"azure\"` \\| `\"anthropic\"` | Provider type |\n| `baseUrl` | string | **Required.** API endpoint URL |\n| `apiKey` | string | API key (optional for local providers) |\n| `bearerToken` | string | Bearer token auth (takes precedence over apiKey) |\n| `wireApi` | `\"completions\"` \\| `\"responses\"` | API format (default: `\"completions\"`) |\n| `azure.apiVersion` | string | Azure API version (default: `\"2024-10-21\"`) |\n\n### Azure Managed Identity with BYOK\n\nUse `DefaultAzureCredential` to get short-lived bearer tokens for Azure deployments:\n\n```python\nfrom azure.identity import DefaultAzureCredential\nfrom copilot import CopilotClient, ProviderConfig, SessionConfig\n\ncredential = DefaultAzureCredential()\ntoken = credential.get_token(\"https:\u002F\u002Fcognitiveservices.azure.com\u002F.default\").token\n\nsession = await client.create_session(SessionConfig(\n    model=\"gpt-4.1\",\n    provider=ProviderConfig(\n        type=\"openai\",\n        base_url=f\"{foundry_url}\u002Fopenai\u002Fv1\u002F\",\n        bearer_token=token,\n        wire_api=\"responses\",\n    ),\n))\n```\n\n> **Note:** Bearer tokens expire (~1 hour). For long-running apps, refresh the token before each new session. The SDK does not auto-refresh tokens.\n\n### BYOK Limitations\n\n- **Static credentials only** — no native Entra ID, OIDC, or managed identity support\n- **No auto-refresh** — expired tokens require creating a new session\n- **Keys not persisted** — must re-provide `provider` config on session resume\n- **Model availability** — limited to what your provider offers\n\n---\n\n## Session Persistence\n\nResume sessions across restarts by providing your own session ID.\n\n```typescript\n\u002F\u002F Create with explicit ID\nconst session = await client.createSession({\n    sessionId: \"user-123-task-456\",\n    model: \"gpt-4.1\",\n});\n\n\u002F\u002F Resume later (even from a different client instance)\nconst resumed = await client.resumeSession(\"user-123-task-456\");\nawait resumed.sendAndWait({ prompt: \"What did we discuss?\" });\n```\n\n### Session Management\n\n```typescript\nconst sessions = await client.listSessions();           \u002F\u002F List all\nconst lastId = await client.getLastSessionId();          \u002F\u002F Get most recent\nawait client.deleteSession(\"user-123-task-456\");         \u002F\u002F Delete from storage\nawait session.destroy();                                 \u002F\u002F Destroy active session\n```\n\n### Resume Options\n\nWhen resuming, you can reconfigure: `model`, `systemMessage`, `availableTools`, `excludedTools`, `provider` (required for BYOK), `reasoningEffort`, `streaming`, `mcpServers`, `customAgents`, `skillDirectories`, `infiniteSessions`.\n\n### Session ID Best Practices\n\n| Pattern | Example | Use Case |\n|---------|---------|----------|\n| `user-{userId}-{taskId}` | `user-alice-pr-review-42` | Multi-user apps |\n| `tenant-{tenantId}-{workflow}` | `tenant-acme-onboarding` | Multi-tenant SaaS |\n| `{userId}-{taskType}-{timestamp}` | `alice-deploy-1706932800` | Time-based cleanup |\n\n### What Gets Persisted\n\nSession state is saved to `~\u002F.copilot\u002Fsession-state\u002F{sessionId}\u002F`:\n\n| Data | Persisted? | Notes |\n|------|------------|-------|\n| Conversation history | ✅ Yes | Full message thread |\n| Tool call results | ✅ Yes | Cached for context |\n| Agent planning state | ✅ Yes | `plan.md` file |\n| Session artifacts | ✅ Yes | In `files\u002F` directory |\n| Provider\u002FAPI keys | ❌ No | Must re-provide on resume |\n| In-memory tool state | ❌ No | Design tools to be stateless |\n\n### Infinite Sessions\n\nFor long-running workflows that may exceed context limits, enable auto-compaction:\n\n```typescript\nconst session = await client.createSession({\n    infiniteSessions: {\n        enabled: true,\n        backgroundCompactionThreshold: 0.80,  \u002F\u002F Start background compaction at 80%\n        bufferExhaustionThreshold: 0.95,       \u002F\u002F Block and compact at 95%\n    },\n});\n```\n\n> Thresholds are context utilization ratios (0.0–1.0), not absolute token counts.\n\n---\n\n## Custom Agents\n\nDefine specialized AI personas:\n\n```typescript\nconst session = await client.createSession({\n    customAgents: [{\n        name: \"pr-reviewer\",\n        displayName: \"PR Reviewer\",\n        description: \"Reviews pull requests for best practices\",\n        prompt: \"You are an expert code reviewer. Focus on security, performance, and maintainability.\",\n    }],\n});\n```\n\n---\n\n## System Message\n\nControl AI behavior and personality:\n\n```typescript\nconst session = await client.createSession({\n    systemMessage: { content: \"You are a helpful assistant. Always be concise.\" },\n});\n```\n\n---\n\n## Skills Integration\n\nLoad skill directories to extend Copilot's capabilities:\n\n```typescript\nconst session = await client.createSession({\n    skillDirectories: [\".\u002Fskills\u002Fcode-review\", \".\u002Fskills\u002Fdocumentation\"],\n    disabledSkills: [\"experimental-feature\"],\n});\n```\n\nSkills can be combined with custom agents and MCP servers:\n\n```typescript\nconst session = await client.createSession({\n    skillDirectories: [\".\u002Fskills\u002Fsecurity\"],\n    customAgents: [{ name: \"auditor\", prompt: \"Focus on OWASP Top 10.\" }],\n    mcpServers: { postgres: { type: \"local\", command: \"npx\", args: [\"-y\", \"@modelcontextprotocol\u002Fserver-postgres\"], tools: [\"*\"] } },\n});\n```\n\n---\n\n## Permission & Input Handlers\n\nHandle tool permissions and user input requests programmatically. The SDK uses a **deny-by-default** permission model — all permission requests are denied unless you provide a handler.\n\n```typescript\nconst session = await client.createSession({\n    onPermissionRequest: async (request) => {\n        if (request.kind === \"shell\") {\n            return { approved: request.command.startsWith(\"git\") };\n        }\n        return { approved: true };\n    },\n    onUserInputRequest: async (request) => {\n        return { response: \"yes\" };\n    },\n});\n```\n\n### Token Usage Tracking\n\nSubscribe to usage events instead of using CLI `\u002Fusage`:\n\n```typescript\nsession.on(\"assistant.usage\", (event) => {\n    console.log(\"Tokens:\", { input: event.data.inputTokens, output: event.data.outputTokens });\n});\n```\n\n---\n\n## Deployment Patterns\n\n### Local CLI (Default)\n\nSDK auto-spawns CLI as subprocess. Simplest setup — zero configuration.\n\n```typescript\nconst client = new CopilotClient(); \u002F\u002F Auto-manages CLI process\n```\n\n### External CLI Server (Backend Services)\n\nRun CLI in headless mode, connect SDK over TCP:\n\n```bash\ncopilot --headless --port 4321\n```\n\n```typescript\nconst client = new CopilotClient({ cliUrl: \"localhost:4321\" });\n```\n\n**Multi-client support:** Multiple SDK clients can share one CLI server.\n\n### Bundled CLI (Desktop Apps)\n\nShip CLI binary with your app:\n\n```typescript\nconst client = new CopilotClient({ cliPath: path.join(__dirname, \"vendor\", \"copilot\") });\n```\n\n### Docker Compose\n\n```yaml\nservices:\n  copilot-cli:\n    image: ghcr.io\u002Fgithub\u002Fcopilot-cli:latest\n    command: [\"--headless\", \"--port\", \"4321\"]\n    environment:\n      - COPILOT_GITHUB_TOKEN=${COPILOT_GITHUB_TOKEN}\n    volumes:\n      - session-data:\u002Froot\u002F.copilot\u002Fsession-state\n  api:\n    build: .\n    environment:\n      - CLI_URL=copilot-cli:4321\n    depends_on: [copilot-cli]\nvolumes:\n  session-data:\n```\n\n### Session Isolation Patterns\n\n| Pattern | Isolation | Resources | Best For |\n|---------|-----------|-----------|----------|\n| **CLI per user** | Complete | High | Multi-tenant SaaS, compliance |\n| **Shared CLI + session IDs** | Logical | Low | Internal tools |\n| **Shared sessions** | None | Low | Team collaboration (requires locking) |\n\n### Production Checklist\n\n- Session cleanup: periodic deletion of expired sessions\n- Health checks: ping CLI server, restart if unresponsive\n- Persistent storage: mount `~\u002F.copilot\u002Fsession-state\u002F` for containers\n- Secret management: use Vault\u002FK8s Secrets for tokens\n- Session locking: Redis or similar for shared session access\n- Graceful shutdown: drain active sessions before stopping CLI\n\n---\n\n## Client Configuration\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `cliPath` | string | Auto-detected | Path to Copilot CLI executable |\n| `cliUrl` | string | — | URL of external CLI server |\n| `githubToken` | string | — | GitHub token for auth |\n| `useLoggedInUser` | boolean | `true` | Use stored CLI credentials |\n| `logLevel` | string | `\"none\"` | `\"none\"` \\| `\"error\"` \\| `\"warning\"` \\| `\"info\"` \\| `\"debug\"` |\n| `autoRestart` | boolean | `true` | Auto-restart CLI on crash |\n| `useStdio` | boolean | `true` | Use stdio transport |\n\n## Session Configuration\n\n| Option | Type | Description |\n|--------|------|-------------|\n| `model` | string | Model to use (e.g., `\"gpt-4.1\"`, `\"claude-sonnet-4\"`) |\n| `sessionId` | string | Custom ID for resumable sessions |\n| `streaming` | boolean | Enable streaming responses |\n| `tools` | Tool[] | Custom tools |\n| `mcpServers` | object | MCP server configurations |\n| `hooks` | object | Session hooks |\n| `provider` | object | BYOK provider config |\n| `customAgents` | object[] | Custom agent definitions |\n| `systemMessage` | object | System message override |\n| `skillDirectories` | string[] | Directories to load skills from |\n| `disabledSkills` | string[] | Skills to disable |\n| `reasoningEffort` | string | Reasoning effort level |\n| `availableTools` | string[] | Restrict available tools |\n| `excludedTools` | string[] | Exclude specific tools |\n| `infiniteSessions` | object | Auto-compaction config |\n| `workingDirectory` | string | Working directory |\n\n---\n\n## SDK vs CLI Feature Comparison\n\n### ✅ Available in SDK\n\nSession management, messaging (`send`\u002F`sendAndWait`\u002F`abort`), message history (`getMessages`), custom tools, tool permission hooks, MCP servers (local + HTTP), streaming, model selection, BYOK providers, custom agents, system message, skills, infinite sessions, permission handlers, 40+ event types.\n\n### ❌ CLI-Only Features\n\nSession export (`--share`), slash commands, interactive UI, terminal rendering, YOLO mode, login\u002Flogout flows, `\u002Fcompact` (use `infiniteSessions` instead), `\u002Fusage` (use usage events), `\u002Freview`, `\u002Fdelegate`.\n\n**Workarounds:**\n- Session export → Collect events manually with `session.on()` + `session.getMessages()`\n- Permission control → Use `onPermissionRequest` handler instead of `--allow-all-paths`\n- Context compaction → Use `infiniteSessions` config instead of `\u002Fcompact`\n\n---\n\n## Debugging\n\nEnable debug logging:\n\n```typescript\nconst client = new CopilotClient({ logLevel: \"debug\" });\n```\n\nCustom log directory:\n\n```typescript\nconst client = new CopilotClient({ cliArgs: [\"--log-dir\", \"\u002Fpath\u002Fto\u002Flogs\"] });\n```\n\n### Common Issues\n\n| Issue | Cause | Solution |\n|-------|-------|----------|\n| `CLI not found` | CLI not installed or not in PATH | Install CLI or set `cliPath` |\n| `Not authenticated` | No valid credentials | Run `copilot auth login` or provide `githubToken` |\n| `Session not found` | Using session after `destroy()` | Check `listSessions()` for valid IDs |\n| `Connection refused` | CLI process crashed | Enable `autoRestart: true`, check port conflicts |\n| MCP tools missing | Server init failure or tools not enabled | Set `tools: [\"*\"]`, test server independently |\n\n### Connection State\n\n```typescript\nconsole.log(\"State:\", client.getState());  \u002F\u002F \"connected\" after start()\nclient.on(\"stateChange\", (state) => console.log(\"Changed to:\", state));\n```\n\n---\n\n## Key API Summary\n\n| Language | Client | Session Create | Send | Resume | Stop |\n|----------|--------|---------------|------|--------|------|\n| Node.js | `new CopilotClient()` | `client.createSession()` | `session.sendAndWait()` | `client.resumeSession()` | `client.stop()` |\n| Python | `CopilotClient()` | `client.create_session()` | `session.send_and_wait()` | `client.resume_session()` | `client.stop()` |\n| Go | `copilot.NewClient(nil)` | `client.CreateSession()` | `session.SendAndWait()` | `client.ResumeSession()` | `client.Stop()` |\n| .NET | `new CopilotClient()` | `client.CreateSessionAsync()` | `session.SendAndWaitAsync()` | `client.ResumeSessionAsync()` | `client.DisposeAsync()` |\n\n## References\n\n- [GitHub Copilot SDK](https:\u002F\u002Fgithub.com\u002Fgithub\u002Fcopilot-sdk)\n- [Copilot CLI Installation](https:\u002F\u002Fdocs.github.com\u002Fen\u002Fcopilot\u002Fhow-tos\u002Fset-up\u002Finstall-copilot-cli)\n- [MCP Protocol Specification](https:\u002F\u002Fmodelcontextprotocol.io)\n- [MCP Servers Directory](https:\u002F\u002Fgithub.com\u002Fmodelcontextprotocol\u002Fservers)\n- [GitHub MCP Server](https:\u002F\u002Fgithub.com\u002Fgithub\u002Fgithub-mcp-server)\n",{"name":5,"description":7},"main","d41309588593cee5c2fb44062474efc3a99fbcb6",".agent\u002Fskills\u002Fmicrosoft_skills\u002F.github\u002Fskills\u002Fcopilot-sdk","https:\u002F\u002Fgithub.com\u002Fricardoaevt\u002Fnexus-roms","https:\u002F\u002Fgithub.com\u002Fricardoaevt","2026-03-23 00:05:03",{"source":8,"skillName":5,"commands":55,"prompt":65,"zipAvailable":66},[56,59,62],{"tool":57,"command":58},"npx","npx skills add ricardoaevt\u002Fnexus-roms --skill copilot-sdk",{"tool":60,"command":61},"bunx","bunx skills add ricardoaevt\u002Fnexus-roms --skill copilot-sdk",{"tool":63,"command":64},"pnpm","pnpm dlx skills add ricardoaevt\u002Fnexus-roms --skill copilot-sdk","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fricardoaevt\u002Fnexus-roms\u002Fblob\u002Fmain\u002F.agent\u002Fskills\u002Fmicrosoft_skills\u002F.github\u002Fskills\u002Fcopilot-sdk\u002FSKILL.md",true,[68],{"path":69,"resourceType":70,"resourceTypeDesc":71,"sizeBytes":72,"sourceHtmlUrl":73},"references\u002Facceptance-criteria.md","REFERENCE","参考文档",5077,"https:\u002F\u002Fgithub.com\u002Fricardoaevt\u002Fnexus-roms\u002Fblob\u002Fmain\u002F.agent\u002Fskills\u002Fmicrosoft_skills\u002F.github\u002Fskills\u002Fcopilot-sdk\u002Freferences\u002Facceptance-criteria.md",[75,99,115,130,141,150],{"skillNo":76,"name":77,"nameZh":6,"description":78,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":79,"licenseFileUrl":6,"sourceHtmlUrl":80,"categories":81,"keywords":82,"publishedAt":43},"01M6G9HYKQRK6HBKVTZM3258M3","openspec-propose","Propose a new change with all artifacts generated in one step. Use when the user wants to quickly describe what they want to build and get a complete proposal with design, specs, and tasks ready for implementation.","MIT","https:\u002F\u002Fgithub.com\u002Fricardoaevt\u002Fnexus-roms\u002Fblob\u002Fmain\u002F.agent\u002Fskills\u002Fopenspec-propose\u002FSKILL.md",[],[83,84,42,85,86,87,88,89,90,91,92,93,94,95,96,97,98],"openspec propose","openspec","generated","with","proposal","complete","get","build","implementation","ready","use","user","artifacts","tasks","change","design",{"skillNo":100,"name":101,"nameZh":6,"description":102,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":79,"licenseFileUrl":6,"sourceHtmlUrl":103,"categories":104,"keywords":105,"publishedAt":43},"01M6G9HV9V20WFCHYVSDNQMJVK","openspec-new-change","Start a new OpenSpec change using the experimental artifact workflow. Use when the user wants to create a new feature, fix, or modification with a structured step-by-step approach.","https:\u002F\u002Fgithub.com\u002Fricardoaevt\u002Fnexus-roms\u002Fblob\u002Fmain\u002F.agent\u002Fskills\u002Fopenspec-new-change\u002FSKILL.md",[],[84,106,97,107,42,108,109,110,93,94,111,112,113,114,86],"openspec new change","new feature","structured","artifact","workflow","create","start","fix","feature",{"skillNo":116,"name":117,"nameZh":6,"description":118,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":79,"licenseFileUrl":6,"sourceHtmlUrl":119,"categories":120,"keywords":121,"publishedAt":43},"01M6G9HRF6R89QZXGSFC9DRQW3","openspec-explore","Enter explore mode - a thinking partner for exploring ideas, investigating problems, and clarifying requirements. Use when the user wants to think through something before or during a change.","https:\u002F\u002Fgithub.com\u002Fricardoaevt\u002Fnexus-roms\u002Fblob\u002Fmain\u002F.agent\u002Fskills\u002Fopenspec-explore\u002FSKILL.md",[],[122,123,84,93,124,42,97,94,125,126,127,128,129],"openspec explore","explore","partner","think","thinking partner","thinking","ideas","requirements",{"skillNo":131,"name":132,"nameZh":6,"description":133,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":79,"licenseFileUrl":6,"sourceHtmlUrl":134,"categories":135,"keywords":136,"publishedAt":43},"01M6G9HP3APFCXZG7XRWBMM524","openspec-continue-change","Continue working on an OpenSpec change by creating the next artifact. Use when the user wants to progress their change, create the next artifact, or continue their workflow.","https:\u002F\u002Fgithub.com\u002Fricardoaevt\u002Fnexus-roms\u002Fblob\u002Fmain\u002F.agent\u002Fskills\u002Fopenspec-continue-change\u002FSKILL.md",[],[84,137,138,97,110,42,111,94,93,139,109,140],"continue","openspec continue change","next","progress",{"skillNo":142,"name":143,"nameZh":6,"description":144,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":79,"licenseFileUrl":6,"sourceHtmlUrl":145,"categories":146,"keywords":147,"publishedAt":43},"01M6G9HKT3WMSDBSKA7YM4MSSQ","openspec-archive-change","Archive a completed change in the experimental workflow. Use when the user wants to finalize and archive a change after implementation is complete.","https:\u002F\u002Fgithub.com\u002Fricardoaevt\u002Fnexus-roms\u002Fblob\u002Fmain\u002F.agent\u002Fskills\u002Fopenspec-archive-change\u002FSKILL.md",[],[148,84,149,97,42,110,94,93,91,88],"openspec archive change","archive",{"skillNo":151,"name":152,"nameZh":6,"description":153,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":79,"licenseFileUrl":6,"sourceHtmlUrl":154,"categories":155,"keywords":156,"publishedAt":43},"01M6G9HHEG0RJK4E0YTVZZ6A8T","openspec-apply-change","Implement tasks from an OpenSpec change. Use when the user wants to start implementing, continue implementation, or work through tasks.","https:\u002F\u002Fgithub.com\u002Fricardoaevt\u002Fnexus-roms\u002Fblob\u002Fmain\u002F.agent\u002Fskills\u002Fopenspec-apply-change\u002FSKILL.md",[],[84,97,157,158,96,112,137,159,94,93,91,42],"openspec apply change","implement","work"]