Conversation
- Add docs/debugging.md with general SDK debugging guide - Create docs/mcp/ directory for MCP-specific documentation - Move docs/mcp.md to docs/mcp/overview.md - Add docs/mcp/debugging.md with detailed MCP troubleshooting - Update cross-references between docs
- Add docs/hooks/overview.md with hook types summary and quick start - Add docs/hooks/pre-tool-use.md for permission control - Add docs/hooks/post-tool-use.md for result transformation - Add docs/hooks/user-prompt-submitted.md for prompt modification - Add docs/hooks/session-lifecycle.md for session start/end hooks - Add docs/hooks/error-handling.md for custom error handling All docs include examples for Node.js, Python, Go, and .NET SDKs
- Document features available via SDK vs CLI-only - Include workarounds for common CLI-only features - Add protocol limitations explanation - Cross-reference to other docs
Custom agent for auditing and maintaining SDK documentation: - Checks feature coverage across all 4 SDKs - Validates link integrity - Ensures multi-language examples - Enforces documentation standards - Provides audit checklist and process - Generates improvement reports Can be deployed from github.com to keep docs current.
There was a problem hiding this comment.
Pull request overview
This PR introduces a substantial documentation expansion for the Copilot SDK, focusing on debugging, MCP server troubleshooting, session hooks, and a feature compatibility matrix between the SDKs and the Copilot CLI.
Changes:
- Adds a general SDK-wide debugging guide plus a dedicated MCP debugging guide, including platform-specific troubleshooting and protocol testing steps.
- Introduces comprehensive hook documentation (pre/post tool use, user prompt, session lifecycle, error handling) with multi-language examples (Node.js, Python, Go, .NET).
- Documents SDK vs CLI feature compatibility, including which interactive CLI features are not exposed via JSON-RPC and suggested SDK-level workarounds.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
docs/mcp/overview.md |
Refactors the MCP overview to point to the new dedicated MCP debugging guide, and updates cross-links to the general getting-started/debugging docs. |
docs/mcp/debugging.md |
New MCP-specific debugging guide covering manual protocol tests, common failure modes, and platform-specific configuration tips, including .NET and NPX examples. |
docs/hooks/overview.md |
Provides a high-level overview of all available session hooks, with quick-start examples for each SDK and links to the individual hook guides. |
docs/hooks/pre-tool-use.md |
Documents the onPreToolUse hook’s input/output contract and shows patterns for permission gating, argument rewriting, path restriction, and output suppression across languages. |
docs/hooks/post-tool-use.md |
Documents onPostToolUse semantics and illustrates logging, redaction, truncation, summarization, and auditing patterns for tool results. |
docs/hooks/user-prompt-submitted.md |
Describes the user-prompt-submitted hook and demonstrates logging, prompt templating, shortcuts, content filtering, rate limiting, and preference injection, but currently mis-documents the hook output shape and uses unsupported fields. |
docs/hooks/session-lifecycle.md |
Explains session start/end hooks with examples for adding project/user context, cleaning up resources, tracking metrics, and saving state; includes one example with inconsistent in-memory state (startTime) and misaligned input/output field descriptions. |
docs/hooks/error-handling.md |
Introduces the error hook with examples for logging, monitoring, user-friendly messaging, suppression, pattern tracking, and alerting, but the documented input/output fields and example payloads don’t match the actual ErrorOccurredHook* types. |
docs/debugging.md |
Adds a general debugging guide (log levels, CLI path/auth issues, connection modes, tool issues, platform quirks, MCP debugging pointer) but some environment-variable and Python log-directory examples do not reflect the current SDK APIs. |
docs/compatibility.md |
New SDK/CLI feature compatibility matrix plus workarounds (permission handling, export, usage, compaction), though the token-usage and infinite-session examples are partially out of sync with the actual event and config types. |
Comments suppressed due to low confidence (4)
docs/debugging.md:50
- Similarly to the Node section, this Python example implies that
COPILOT_LOG_LEVELcontrols SDK logging, butCopilotClientnever reads that environment variable and instead uses thelog_leveloption to compute the--log-levelCLI flag. To avoid surprising behavior, this should either be removed or rewritten to demonstrate readingCOPILOT_LOG_LEVELin user code and threading it intoCopilotClient(log_level=...).
Or via environment variable:
```bash
COPILOT_LOG_LEVEL=debug python your_app.py
**docs/debugging.md:68**
* The Go section also suggests that `COPILOT_LOG_LEVEL` can be used to control logging, but `ClientOptions` and `NewClient` in `go/client.go` never consult this environment variable and always pass the `LogLevel` option directly to `--log-level`. Like the Node/Python notes above, this should be clarified or removed so users don’t expect the env var alone to change the SDK’s log level.
Or via environment variable:
COPILOT_LOG_LEVEL=debug go run main.go**docs/hooks/user-prompt-submitted.md:213**
* The examples that use `reject` / `rejectReason` in the hook output (e.g., this content filtering snippet) are inconsistent with the actual `UserPromptSubmittedHookOutput` types, which do not define these fields. To avoid compile-time errors in TypeScript and no-op behavior in other SDKs, these examples should be rewritten to use the supported fields (e.g., `modifiedPrompt`, `additionalContext`, or `suppressOutput`) or another documented mechanism for rejecting prompts.
const BLOCKED_PATTERNS = [
/password\s*[:=]/i,
/api[_-]?key\s*[:=]/i,
/secret\s*[:=]/i,
];
const session = await client.createSession({
hooks: {
onUserPromptSubmitted: async (input) => {
for (const pattern of BLOCKED_PATTERNS) {
if (pattern.test(input.prompt)) {
return {
reject: true,
rejectReason: "Please don't include sensitive credentials in your prompts. Use environment variables instead.",
};
}
**docs/hooks/error-handling.md:96**
* This example (and the similar one in the Python section) logs `input.errorType` and `input.stack`, but `ErrorOccurredHookInput` in all SDKs exposes `errorContext` and `recoverable` instead, and does not have `stack` or `errorType` properties. To avoid confusing users and causing type errors, please update the examples to use the actual fields (`errorContext`, `recoverable`) or adjust the type definitions and implementation if you intend to support the documented shape.
const session = await client.createSession({
hooks: {
onErrorOccurred: async (input, invocation) => {
console.error([${invocation.sessionId}] Error: ${input.error});
console.error( Type: ${input.errorType});
if (input.stack) {
console.error( Stack: ${input.stack});
}
return null;
</details>
docs/debugging.md
Outdated
| You can also set the environment variable: | ||
| ```bash | ||
| COPILOT_LOG_LEVEL=debug node your-app.js | ||
| ``` |
There was a problem hiding this comment.
The COPILOT_LOG_LEVEL example suggests that setting this environment variable will control SDK logging, but none of the language clients read COPILOT_LOG_LEVEL—Node, Python, Go, and .NET all drive the CLI log level from the explicit logLevel/log_level option and --log-level CLI flag. As written, COPILOT_LOG_LEVEL=debug node your-app.js will not change the SDK client’s log level; consider either removing this snippet or showing how to read COPILOT_LOG_LEVEL in your app and pass it into the CopilotClient options.
This issue also appears in the following locations of the same file:
- line 47
- line 65
docs/hooks/error-handling.md
Outdated
| | Field | Type | Description | | ||
| |-------|------|-------------| | ||
| | `timestamp` | number | Unix timestamp when the error occurred | | ||
| | `cwd` | string | Current working directory | | ||
| | `error` | string | Error message | | ||
| | `errorType` | string | Type/category of error | | ||
| | `stack` | string | Stack trace (if available) | | ||
| | `context` | object | Additional error context | | ||
|
|
||
| ## Output | ||
|
|
||
| Return `null` or `undefined` to use default error handling. Otherwise, return an object with: | ||
|
|
||
| | Field | Type | Description | | ||
| |-------|------|-------------| | ||
| | `additionalContext` | string | Context to add to help recover | | ||
| | `suppressError` | boolean | If true, don't show error to user | | ||
| | `modifiedMessage` | string | Custom error message to display | |
There was a problem hiding this comment.
The input/output schema described for ErrorOccurredHookInput/ErrorOccurredHookOutput doesn't match the implemented hook types: the SDKs expose errorContext and recoverable on the input (not errorType, stack, or context) and suppressOutput, errorHandling, retryCount, and userNotification on the output (not additionalContext, suppressError, or modifiedMessage). This table should be brought in line with the concrete types in nodejs/src/types.ts, python/copilot/types.py, go/types.go, and dotnet/src/Types.cs, and the property names in the examples below (e.g., input.errorType, input.stack) should be updated accordingly.
docs/compatibility.md
Outdated
| session.on("assistant.turn_end", (event) => { | ||
| console.log("Tokens used:", event.data.usage); |
There was a problem hiding this comment.
The Node.js example for token usage tracking listens on "assistant.turn_end" and reads event.data.usage, but the generated session events only attach usage information on the separate "assistant.usage" event with fields like inputTokens/outputTokens. This snippet should instead subscribe to "assistant.usage" and read the documented usage fields from event.data so it matches the actual event model.
| session.on("assistant.turn_end", (event) => { | |
| console.log("Tokens used:", event.data.usage); | |
| session.on("assistant.usage", (event) => { | |
| console.log("Tokens used:", { | |
| input: event.data.inputTokens, | |
| output: event.data.outputTokens, | |
| }); |
docs/hooks/user-prompt-submitted.md
Outdated
| | `reject` | boolean | If true, reject the prompt entirely | | ||
| | `rejectReason` | string | Explanation shown when prompt is rejected | |
There was a problem hiding this comment.
The documented UserPromptSubmittedHookOutput shape here doesn't match the actual SDK types: in all 4 SDKs the output only supports modifiedPrompt, additionalContext, and suppressOutput (see UserPromptSubmittedHookOutput in nodejs/src/types.ts, python/copilot/types.py, go/types.go, and dotnet/src/Types.cs). There are no reject or rejectReason fields, so returning them will either fail type-checking (TypeScript) or be ignored by the CLI; this table should drop reject/rejectReason and mention suppressOutput instead.
| | `reject` | boolean | If true, reject the prompt entirely | | |
| | `rejectReason` | string | Explanation shown when prompt is rejected | | |
| | `suppressOutput` | boolean | If true, do not send any assistant message back to the user | |
| ```typescript | ||
| const sessionData: Record<string, { prompts: number; tools: number }> = {}; | ||
|
|
||
| const session = await client.createSession({ | ||
| hooks: { | ||
| onSessionStart: async (_, invocation) => { | ||
| sessionData[invocation.sessionId] = { prompts: 0, tools: 0 }; | ||
| return null; | ||
| }, | ||
| onUserPromptSubmitted: async (_, invocation) => { | ||
| sessionData[invocation.sessionId].prompts++; | ||
| return null; | ||
| }, | ||
| onPreToolUse: async (_, invocation) => { | ||
| sessionData[invocation.sessionId].tools++; | ||
| return { permissionDecision: "allow" }; | ||
| }, | ||
| onSessionEnd: async (input, invocation) => { | ||
| const data = sessionData[invocation.sessionId]; | ||
| console.log(` | ||
| Session Summary: | ||
| ID: ${invocation.sessionId} | ||
| Duration: ${(input.timestamp - data.startTime) / 1000}s | ||
| Prompts: ${data.prompts} | ||
| Tool calls: ${data.tools} |
There was a problem hiding this comment.
In this "Log Session Summary" example, sessionData is declared as { prompts: number; tools: number }, but onSessionEnd later reads data.startTime, which is never stored. Either the map type and onSessionStart handler should be extended to record a startTime (e.g., from input.timestamp), or the duration computation should be removed/rewritten so it only uses fields that are actually tracked.
- Agent now audits and creates IMPROVEMENT_PLAN.md - Does NOT make changes directly - Creates PR with findings for human review - Includes code sample validation against SDK interface - Plan is prioritized and actionable - Human can then ask Copilot to implement specific items
- Create docs/auth/index.md with overview of all auth methods - Create docs/auth/byok.md with Azure AI Foundry example and limitations - Document Entra ID/managed identity limitations for BYOK - Add auth links to README and getting-started.md
- Use backgroundCompactionThreshold instead of compactionThreshold.background - Use bufferExhaustionThreshold instead of compactionThreshold.blocking - Values are 0.0-1.0 utilization ratios, not absolute token counts - Add note clarifying the value range
Comprehensive guide covering: - Session lifecycle and persistence model - Creating and resuming sessions across all 4 SDKs - BYOK re-authentication requirements - Session ID best practices and patterns - Session cleanup and lifecycle management - Idle timeout behavior - Deployment patterns (one CLI per user vs shared) - Azure Dynamic Sessions with persistent storage - Infinite sessions configuration - Concurrent access handling - ASCII diagrams for visual learners
- Session lifecycle flowchart - Resume flow diagram - Session ID patterns - Idle timeout timeline - Deployment patterns (isolated vs shared) - Azure persistent storage diagram
- Use horizontal (LR) flowcharts instead of vertical (TB) - Remove custom colors that may have legibility issues - Use emoji for visual clarity instead of colors - Replace Session ID diagram with a table (cleaner) - Simplify timeline diagram to horizontal flow - Reduce overall vertical height of all diagrams
- Remove non-existent COPILOT_LOG_LEVEL env var references (SDK doesn't read it) - Fix Python log directory example (cli_args doesn't exist in Python SDK) - Add note about Python/Go limitation for log directory config - Add initialPrompt field to SessionStartHookInput docs - Add finalMessage and error fields to SessionEndHookInput docs - Fix SessionEndHookOutput fields (suppressOutput, cleanupActions, sessionSummary)
- error-handling.md: Fix input fields (errorContext, recoverable instead of errorType, stack, context) - error-handling.md: Fix output fields (suppressOutput, errorHandling, retryCount, userNotification) - error-handling.md: Update examples to use correct field names - user-prompt-submitted.md: Remove non-existent reject/rejectReason, add suppressOutput - compatibility.md: Fix token usage event (assistant.usage not assistant.turn_end) - compatibility.md: Fix usage fields (inputTokens/outputTokens not usage object) - session-lifecycle.md: Fix Log Session Summary example to track startTime
- Remove bash tool (not needed for file creation) - Add create/edit tools for file operations - Remove branch creation and PR steps - Note that github.com handles PR creation automatically
Summary
This PR adds comprehensive documentation for the Copilot SDK covering debugging, hooks, MCP servers, and SDK/CLI compatibility.
Changes
New Documentation Structure
Details
Debugging Guide (
docs/debugging.md)MCP Documentation (
docs/mcp/)mcp/overview.mdmcp/debugging.mdfor MCP-specific troubleshootingHooks Documentation (
docs/hooks/)Compatibility Guide (
docs/compatibility.md)--share, slash commands)Testing
Documentation only - no code changes.
Related Issues
Addresses common questions about: