Back to skills
SkillHub ClubShip Full StackFull StackIntegration

copilot-sdk

This skill provides guidance for creating agents and applications with the GitHub Copilot SDK. IMPORTANT - When using the SDK with TypeScript/Node.js, the project MUST use ESM (ECMAScript Modules). CommonJS (require/module.exports) is NOT supported. It should be used when the user wants to create, modify, or work on software that uses the GitHub Copilot SDK in TypeScript (ESM only), Python, Go, or .NET. The skill covers SDK usage patterns, ESM-based project configuration, CLI configuration, custom tools, MCP servers, and custom agents.

Packaged view

This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.

Stars
10
Hot score
84
Updated
March 20, 2026
Overall rating
C2.2
Composite score
2.2
Best-practice grade
C64.8

Install command

npx @skill-hub/cli install doggy8088-agent-skills-copilot-sdk

Repository

doggy8088/agent-skills

Skill path: skills/copilot-sdk

This skill provides guidance for creating agents and applications with the GitHub Copilot SDK. IMPORTANT - When using the SDK with TypeScript/Node.js, the project MUST use ESM (ECMAScript Modules). CommonJS (require/module.exports) is NOT supported. It should be used when the user wants to create, modify, or work on software that uses the GitHub Copilot SDK in TypeScript (ESM only), Python, Go, or .NET. The skill covers SDK usage patterns, ESM-based project configuration, CLI configuration, custom tools, MCP servers, and custom agents.

Open repository

Best for

Primary workflow: Ship Full Stack.

Technical facets: Full Stack, Integration.

Target audience: everyone.

License: Unknown.

Original source

Catalog source: SkillHub Club.

Repository owner: doggy8088.

This is still a mirrored public skill entry. Review the repository before installing into production workflows.

What it helps with

  • Install copilot-sdk into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
  • Review https://github.com/doggy8088/agent-skills before adding copilot-sdk to shared team environments
  • Use copilot-sdk for development workflows

Works across

Claude CodeCodex CLIGemini CLIOpenCode

Favorites: 0.

Sub-skills: 0.

Aggregator: No.

Original source / Raw SKILL.md

---
name: copilot-sdk
description: This skill provides guidance for creating agents and applications with the GitHub Copilot SDK. IMPORTANT - When using the SDK with TypeScript/Node.js, the project MUST use ESM (ECMAScript Modules). CommonJS (require/module.exports) is NOT supported. It should be used when the user wants to create, modify, or work on software that uses the GitHub Copilot SDK in TypeScript (ESM only), Python, Go, or .NET. The skill covers SDK usage patterns, ESM-based project configuration, CLI configuration, custom tools, MCP servers, and custom agents.
---

# GitHub Copilot SDK

## Overview

The GitHub Copilot SDK is a multi-platform agent runtime that embeds Copilot's agentic workflows into applications. It exposes the same engine behind Copilot CLI, enabling programmatic invocation without requiring custom orchestration development.

**Critical Constraint (TypeScript / Node.js):**
- The Copilot SDK for Node.js is **ESM-only**
- Projects **MUST** use ECMAScript Modules
- CommonJS (`require`, `module.exports`) is **not supported**

**Status:** Technical Preview (suitable for development and testing)

**Supported Languages:** TypeScript/Node.js (ESM only), Python, Go, .NET

## Primary Documentation

- [GitHub Copilot SDK Repository](https://github.com/github/copilot-sdk)
- [Getting Started Guide](https://github.com/github/copilot-sdk/blob/main/docs/getting-started.md)
- [Cookbook with Recipes](https://github.com/github/copilot-sdk/blob/main/cookbook/README.md)

### Language-Specific SDK Docs

- [Node.js/TypeScript SDK](https://github.com/github/copilot-sdk/blob/main/nodejs/README.md)
- [Python SDK](https://github.com/github/copilot-sdk/blob/main/python/README.md)
- [Go SDK](https://github.com/github/copilot-sdk/tree/main/go)
- [.NET SDK](https://github.com/github/copilot-sdk/tree/main/dotnet)

### CLI and Configuration Docs

- [About GitHub Copilot CLI](https://docs.github.com/en/copilot/concepts/agents/about-copilot-cli)
- [Using GitHub Copilot CLI](https://docs.github.com/en/copilot/how-tos/use-copilot-agents/use-copilot-cli)
- [Creating Custom Agents](https://docs.github.com/en/copilot/how-tos/use-copilot-agents/coding-agent/create-custom-agents)
- [Custom Agents Configuration Reference](https://docs.github.com/en/copilot/reference/custom-agents-configuration)
- [Enhancing Agent Mode with MCP](https://docs.github.com/en/copilot/tutorials/enhance-agent-mode-with-mcp)
- [Supported AI Models](https://docs.github.com/en/copilot/reference/ai-models/supported-models)

---

## Prerequisites

1. **GitHub Copilot Subscription** - Pro, Pro+, Business, or Enterprise
2. **GitHub Copilot CLI** - Installed and authenticated (`copilot --version`)
3. **Runtime:**
   - **Node.js 18+ (ESM required)**
   - Python 3.8+
   - Go 1.21+
   - .NET 8.0+

4. **TypeScript / Node.js Project Requirements**
   - `package.json` MUST include:
     ```json
     {
       "type": "module"
     }
     ```
   - Use `import` / `export`
   - Do NOT use `require()` or `module.exports`

## Installation

| Language | Command |
|----------|---------|
| TypeScript/Node.js (ESM) | `npm install @github/copilot-sdk` |
| Python | `pip install github-copilot-sdk` |
| Go | `go get github.com/github/copilot-sdk/go` |
| .NET | `dotnet add package GitHub.Copilot.SDK` |

## Architecture

```
Application (ESM) → SDK Client → JSON-RPC → Copilot CLI (server mode)
```

The SDK manages CLI lifecycle automatically. External server connections supported via `cliUrl` / `cli_url`.

---

## Quick Start (TypeScript – ESM REQUIRED)

```typescript
// package.json MUST include: { "type": "module" }

import { CopilotClient } from "@github/copilot-sdk";

const client = new CopilotClient();
await client.start();

const session = await client.createSession({ model: "gpt-5" });

// Register handler BEFORE send()
session.on((event) => {
  if (event.type === "assistant.message") {
    console.log(event.data.content);
  }
});

await session.send({ prompt: "What is 2 + 2?" });

await session.destroy();
await client.stop();
```

**Critical:**
- ESM only (`import`)
- No CommonJS
- Register event handlers **before** calling `send()`

For complete examples in all languages, see `references/working-examples.md`.

---

## Core Concepts

### Client

Main entry point. Manages CLI server lifecycle and session creation.

**Operations:** `start()`, `stop()`, `createSession()`, `resumeSession()`

**Config:** `cliPath`, `cliUrl`, `port`, `useStdio`, `autoStart`, `autoRestart`

### Session

Individual conversation context with message history.

**Operations:** `send()`, `sendAndWait()`, `on()`, `abort()`, `getMessages()`, `destroy()`

**Config:** `model`, `streaming`, `tools`, `systemMessage`

### Events

Key events during processing:

| Event | Purpose |
|-------|---------|
| `assistant.message` | Complete response |
| `assistant.message_delta` | Streaming chunk |
| `session.idle` | Ready for next prompt |
| `tool.execution_start/end` | Tool invocations |

For full event lifecycle and SessionEvent structure, see `references/event-system.md`.

### Streaming

- `streaming: false` (default) - Content arrives all at once
- `streaming: true` - Content arrives incrementally via `assistant.message_delta`

Final `assistant.message` **always fires** regardless of streaming setting.

---

## Available Models

See [Supported AI Models](https://docs.github.com/en/copilot/reference/ai-models/supported-models) for full list.

| Provider | Model ID | Notes |
|----------|----------|-------|
| OpenAI | `gpt-4.1`, `gpt-5`, `gpt-5-mini` | Included |
| OpenAI | `gpt-5.1`, `gpt-5.1-codex`, `gpt-5.2` | Premium |
| Anthropic | `claude-sonnet-4.5` | Premium (CLI default) |
| Anthropic | `claude-opus-4.5` | Premium (3× multiplier) |
| Google | `gemini-3-pro-preview` | Premium |

---

## Custom Tools

**TypeScript (ESM + Zod):**
```typescript
const tool = defineTool("lookup_issue", {
  description: "Fetch issue details",
  parameters: z.object({ id: z.string() }),
  handler: async ({ id }) => fetchIssue(id),
});
```

**Python (Pydantic):**
```python
@define_tool(description="Fetch issue details")
async def lookup_issue(params: IssueParams) -> dict:
    return fetch_issue(params.id)
```

For complete tool examples in all languages, see `references/working-examples.md`.

---

## Language Conventions

| Concept | TypeScript (ESM) | Python | Go | .NET |
|---------|------------------|--------|----|----|
| Create session | `createSession()` | `create_session()` | `CreateSession()` | `CreateSessionAsync()` |
| Delta content | `deltaContent` | `delta_content` | `DeltaContent` | `DeltaContent` |

For full conventions table, see `references/event-system.md`.

---

## CLI Configuration

Config stored in `~/.copilot/`:
- `config.json` - General configuration
- `mcp-config.json` - MCP server definitions

For custom agents and MCP setup, see `references/cli-agents-mcp.md`.

---

## Troubleshooting

| Problem | Solution |
|---------|----------|
| Import errors | Ensure ESM (`"type": "module"`) |
| Events fire but content empty | Use `event.data.content`, not `event.content` |
| Handler never fires | Register **before** `send()` |
| Python enum issues | Use `event.type.value` |
| Go nil pointer | Check `!= nil` before dereferencing |

For debugging techniques, see `references/troubleshooting.md`.

---

## Skill References

Detailed documentation in this skill:

- `references/working-examples.md` - Complete examples for all languages, custom tools
- `references/event-system.md` - Event lifecycle, SessionEvent structure, language conventions
- `references/troubleshooting.md` - Common issues, debugging techniques
- `references/cli-agents-mcp.md` - CLI configuration, custom agents, MCP server setup

---

## Additional Resources

- [SDK Samples](https://github.com/github/copilot-sdk/blob/main/samples/README.md)
- [SDK Releases](https://github.com/github/copilot-sdk/releases)
- [Cookbook](https://github.com/github/copilot-sdk/blob/main/cookbook/README.md)
- [awesome-copilot](https://github.com/github/awesome-copilot)


---

## Referenced Files

> The following files are referenced in this skill and included for context.

### references/working-examples.md

```markdown
# Complete Working Examples

**Critical:** Register event handlers **before** calling `send()` to capture all events.

## TypeScript/Node.js

```typescript
import { CopilotClient, SessionEvent } from "@github/copilot-sdk";

async function main() {
  const client = new CopilotClient();
  await client.start();

  const session = await client.createSession({
    model: "gpt-5",
    streaming: true,
  });

  const done = new Promise<string>((resolve) => {
    let content = "";

    // Register handler BEFORE send()
    session.on((event: SessionEvent) => {
      if (event.type === "assistant.message_delta") {
        process.stdout.write(event.data.deltaContent ?? "");
      }
      if (event.type === "assistant.message") {
        content = event.data.content ?? "";
      }
      if (event.type === "session.idle") {
        resolve(content);
      }
    });
  });

  await session.send({ prompt: "What is 2 + 2?" });
  const response = await done;

  console.log("\n\nFinal response:", response);

  await session.destroy();
  await client.stop();
}

main();
```

## Python

```python
import asyncio
from copilot import CopilotClient

async def main():
    client = CopilotClient()
    await client.start()

    session = await client.create_session({
        "model": "gpt-5",
        "streaming": True,
    })

    done = asyncio.Event()
    final_content = ""

    def on_event(event):
        nonlocal final_content
        # Access type via .value for the string
        event_type = event.type.value

        if event_type == "assistant.message_delta":
            print(event.data.delta_content, end="", flush=True)
        elif event_type == "assistant.message":
            final_content = event.data.content
        elif event_type == "session.idle":
            done.set()

    # Register handler BEFORE send()
    session.on(on_event)

    await session.send({"prompt": "What is 2 + 2?"})
    await done.wait()

    print(f"\n\nFinal response: {final_content}")

    await session.destroy()
    await client.stop()

asyncio.run(main())
```

## Go

```go
package main

import (
    "fmt"
    copilot "github.com/github/copilot-sdk/go"
)

func main() {
    client := copilot.NewClient(nil)
    if err := client.Start(); err != nil {
        panic(err)
    }
    defer client.Stop()

    session, err := client.CreateSession(&copilot.SessionConfig{
        Model:     "gpt-5",
        Streaming: true,
    })
    if err != nil {
        panic(err)
    }
    defer session.Destroy()

    done := make(chan string)
    var finalContent string

    // Register handler BEFORE Send()
    session.On(func(event copilot.SessionEvent) {
        switch event.Type {
        case "assistant.message_delta":
            if event.Data.DeltaContent != nil {
                fmt.Print(*event.Data.DeltaContent)
            }
        case "assistant.message":
            if event.Data.Content != nil {
                finalContent = *event.Data.Content
            }
        case "session.idle":
            done <- finalContent
        }
    })

    _, err = session.Send(copilot.MessageOptions{Prompt: "What is 2 + 2?"})
    if err != nil {
        panic(err)
    }

    response := <-done
    fmt.Printf("\n\nFinal response: %s\n", response)
}
```

## .NET (C#)

```csharp
using GitHub.Copilot.SDK;

await using var client = new CopilotClient();
await client.StartAsync();

await using var session = await client.CreateSessionAsync(new SessionConfig
{
    Model = "gpt-5",
    Streaming = true
});

var done = new TaskCompletionSource<string>();
var finalContent = "";

// Register handler BEFORE SendAsync()
session.On(evt =>
{
    switch (evt)
    {
        case AssistantMessageDeltaEvent delta:
            Console.Write(delta.Data.DeltaContent);
            break;
        case AssistantMessageEvent msg:
            finalContent = msg.Data.Content ?? "";
            break;
        case SessionIdleEvent:
            done.SetResult(finalContent);
            break;
    }
});

await session.SendAsync(new MessageOptions { Prompt = "What is 2 + 2?" });
var response = await done.Task;

Console.WriteLine($"\n\nFinal response: {response}");
```

---

# Custom Tools

The SDK allows defining tools that Copilot can invoke during conversations.

## TypeScript (using Zod)

```typescript
import { defineTool } from "@github/copilot-sdk";
import { z } from "zod";

const myTool = defineTool("lookup_issue", {
  description: "Fetch issue details from tracker",
  parameters: z.object({
    id: z.string().describe("Issue identifier"),
  }),
  handler: async ({ id }) => {
    // Implementation
    return { status: "found", title: "Bug report" };
  },
});

// Use in session
const session = await client.createSession({
  model: "gpt-5",
  tools: [myTool],
});
```

## Python (using Pydantic)

```python
from pydantic import BaseModel, Field
from copilot import CopilotClient, define_tool

class IssueParams(BaseModel):
    id: str = Field(description="Issue identifier")

@define_tool(description="Fetch issue details from tracker")
async def lookup_issue(params: IssueParams) -> dict:
    return {"status": "found", "title": "Bug report"}

# Use in session
session = await client.create_session({
    "model": "gpt-5",
    "tools": [lookup_issue],
})
```

## Go (using DefineTool)

```go
type IssueParams struct {
    ID string `json:"id" description:"Issue identifier"`
}

tool := copilot.DefineTool("lookup_issue", "Fetch issue details from tracker",
    func(params IssueParams, inv copilot.ToolInvocation) (any, error) {
        return map[string]string{"status": "found", "title": "Bug report"}, nil
    })

// Use in session
session, _ := client.CreateSession(&copilot.SessionConfig{
    Model: "gpt-5",
    Tools: []copilot.Tool{tool},
})
```

## .NET (using AIFunctionFactory)

```csharp
using Microsoft.Extensions.AI;

var tool = AIFunctionFactory.Create(
    (string id) => new { Status = "found", Title = "Bug report" },
    "lookup_issue",
    "Fetch issue details from tracker"
);

// Use in session
var session = await client.CreateSessionAsync(new SessionConfig
{
    Model = "gpt-5",
    Tools = new[] { tool }
});
```

```

### references/event-system.md

```markdown
# Event System

## Event Lifecycle

Events fire in this typical sequence for a single request:

```
1. user.message              → User prompt recorded
2. assistant.turn_start      → Model begins processing
3. session.usage_info        → Token/usage metadata
4. assistant.message_delta   → Streaming chunks (if enabled, repeats)
5. assistant.message         → Final complete response
6. assistant.reasoning       → Chain-of-thought (if available)
7. assistant.turn_end        → Model finished processing
8. session.idle              → Session ready for next prompt
```

When tools are invoked, additional events appear:
```
   tool.execution_start      → Tool invocation began
   tool.execution_end        → Tool execution completed
```

## SessionEvent Structure

Events are wrapped in a `SessionEvent` object (exact field names vary by language):

```
SessionEvent {
  type: string | enum       // Event type identifier
  data: {                   // Event-specific payload
    content?: string        // Full text (final events)
    deltaContent?: string   // Incremental text (delta events)
    // Other fields vary by event type
  }
  id?: string               // Event identifier
  timestamp?: string        // When event occurred
}
```

**Important access patterns:**
- TypeScript: `event.type` (string), `event.data.content`, `event.data.deltaContent`
- Python: `event.type.value` (enum requires `.value`), `event.data.content`, `event.data.delta_content`
- Go: `event.Type` (string), `*event.Data.Content`, `*event.Data.DeltaContent` (pointers)
- .NET: Pattern match on event class, then `evt.Data.Content`, `evt.Data.DeltaContent`

## Event Types Reference

| Event Type | Purpose | Key Data Fields |
|------------|---------|-----------------|
| `user.message` | User input recorded | `content` |
| `assistant.message` | Complete response | `content` |
| `assistant.message_delta` | Streaming chunk | `deltaContent` / `delta_content` |
| `assistant.reasoning` | Chain-of-thought | `content` |
| `assistant.reasoning_delta` | Reasoning chunk | `deltaContent` / `delta_content` |
| `assistant.turn_start` | Processing began | — |
| `assistant.turn_end` | Processing finished | — |
| `tool.execution_start` | Tool invoked | tool name, parameters |
| `tool.execution_end` | Tool completed | result |
| `session.idle` | Ready for next prompt | — |
| `session.usage_info` | Token/usage data | usage metrics |

## Streaming Behavior

The `streaming` configuration option controls **when** content arrives, not **which** events fire:

| Setting | Behavior |
|---------|----------|
| `streaming: false` (default) | Content arrives all at once in `assistant.message` |
| `streaming: true` | Content arrives incrementally via `assistant.message_delta` events |

**Important:** Final events (`assistant.message`, `assistant.reasoning`) **always fire** regardless of streaming setting. They contain the complete accumulated content.

To build a response progressively:
1. Accumulate `deltaContent` from each `assistant.message_delta` event
2. Or wait for `assistant.message` which contains the complete text

---

# Language-Specific Conventions

| Concept | TypeScript | Python | Go | .NET |
|---------|------------|--------|----|----|
| Client class | `CopilotClient` | `CopilotClient` | `Client` | `CopilotClient` |
| Create session | `createSession()` | `create_session()` | `CreateSession()` | `CreateSessionAsync()` |
| Send message | `send()` / `sendAndWait()` | `send()` / `send_and_wait()` | `Send()` | `SendAsync()` |
| Session config | `{ model, streaming }` | `{"model", "streaming"}` | `&SessionConfig{}` | `new SessionConfig{}` |
| Event handler | `session.on(fn)` | `session.on(fn)` | `session.On(fn)` | `session.On(fn)` |
| Delta content | `deltaContent` | `delta_content` | `DeltaContent` | `DeltaContent` |
| System message | `systemMessage` | `system_message` | `SystemMessage` | `SystemMessage` |
| CLI path option | `cliPath` | `cli_path` | `CLIPath` | `CliPath` |

```

### references/cli-agents-mcp.md

```markdown
# CLI, Custom Agents, and MCP Servers

## GitHub Copilot CLI Configuration

The SDK uses Copilot CLI as its engine. Configuration is stored in `~/.copilot/` (or `$XDG_CONFIG_HOME/copilot/`):

- `config.json` - General configuration
- `mcp-config.json` - MCP server definitions

For full CLI documentation, see [Using GitHub Copilot CLI](https://docs.github.com/en/copilot/how-tos/use-copilot-agents/use-copilot-cli).

---

# Custom Agents

Custom agents are specialized configurations with tailored expertise for specific tasks.

See [Creating Custom Agents](https://docs.github.com/en/copilot/how-tos/use-copilot-agents/coding-agent/create-custom-agents) and [Custom Agents Configuration Reference](https://docs.github.com/en/copilot/reference/custom-agents-configuration).

## Agent Profile Structure

Custom agents use Markdown files with YAML frontmatter:

```yaml
---
name: my-agent
description: A specialized agent for specific tasks
tools: ["read", "edit", "search"]
target: github-copilot
mcp-servers:
  custom-mcp:
    type: 'local'
    command: 'mcp-server'
    args: ['--flag']
---

# Agent Instructions

Detailed behavioral instructions here (max 30,000 characters).
```

## YAML Frontmatter Properties

| Property | Type | Purpose |
|----------|------|---------|
| `name` | string | Display name (optional, defaults to filename) |
| `description` | string | **Required** - describes purpose and capabilities |
| `target` | string | Environment: `vscode` or `github-copilot` |
| `tools` | list/string | Available tools; defaults to all if unset |
| `infer` | boolean | Allow automatic selection based on context |
| `mcp-servers` | object | MCP server configurations (org/enterprise level) |

## Tools Configuration

Configure tool access:

- **Enable all:** Omit `tools` or use `tools: ["*"]`
- **Enable specific:** `tools: ["read", "edit", "search"]`
- **Disable all:** `tools: []`

**Tool Aliases:**
- `execute` - Run shell commands
- `read` - Access file contents
- `edit` - Modify files
- `search` - Find files/text (grep, glob)
- `agent` - Invoke other custom agents
- `web` - Web search/fetch

**MCP Tool References:** `mcp-server-name/tool-name` or `mcp-server-name/*`

## Agent Storage Locations

- **Repository:** `.github/agents/` directory
- **Organization/Enterprise:** Configured via GitHub settings
- **System:** CLI includes default agents

**Priority (naming conflicts):** System > Repository > Organization

---

# MCP Server Integration

Model Context Protocol (MCP) servers extend Copilot's capabilities with external tools and resources.

See [Enhancing Agent Mode with MCP](https://docs.github.com/en/copilot/tutorials/enhance-agent-mode-with-mcp) and [Setting up the GitHub MCP Server](https://docs.github.com/en/copilot/how-tos/provide-context/use-mcp/set-up-the-github-mcp-server).

## Default MCP Server

Copilot CLI comes with the GitHub MCP server pre-configured, enabling:
- Repository access and management
- Pull request operations
- Issue tracking
- GitHub workflow management

## MCP Configuration Format

MCP servers are configured in `~/.copilot/mcp-config.json`:

```json
{
  "mcpServers": {
    "server-name": {
      "type": "local",
      "command": "mcp-server-command",
      "args": ["--arg1", "--arg2"],
      "env": {
        "API_KEY": "$COPILOT_MCP_API_KEY"
      }
    }
  }
}
```

## Environment Variables in MCP Config

Supported patterns:
- `$COPILOT_MCP_VAR`
- `${COPILOT_MCP_VAR}`
- `${{ secrets.COPILOT_MCP_VAR }}`
- `${{ var.COPILOT_MCP_VAR }}`

```

### references/troubleshooting.md

```markdown
# Troubleshooting

## Common Issues

| Problem | Cause | Solution |
|---------|-------|----------|
| Events fire but content is empty | Accessing wrong property | Use `event.data.content`, not `event.content` |
| Handler never fires | Registered after `send()` | Register handler **before** calling `send()` |
| `get_messages()` returns events, not messages | Method returns all `SessionEvent` objects | Filter by `event.type` and extract from `.data` |
| Response in console but not captured | SDK logs internally | Capture via event handler, not console output |
| Python: `event.type` returns enum object | Enum needs `.value` | Use `event.type.value` for the string |
| Go: nil pointer dereference | Content fields are pointers | Check `!= nil` before dereferencing |

## Event Handler Timing

**Correct pattern:**
```
1. Create session
2. Register event handler(s)
3. Call send()
4. Wait for session.idle or use sendAndWait()
```

**Incorrect pattern (misses events):**
```
1. Create session
2. Call send()
3. Register event handler  ← Too late, events already fired
```

## Debugging Events

To inspect all events during development:

**TypeScript:**
```typescript
session.on((event) => {
  console.log(JSON.stringify(event, null, 2));
});
```

**Python:**
```python
def debug_handler(event):
    print(f"Event: {event.type.value}")
    print(f"Data: {event.data}")

session.on(debug_handler)
```

**Go:**
```go
session.On(func(event copilot.SessionEvent) {
    fmt.Printf("Event: %s\n", event.Type)
    fmt.Printf("Data: %+v\n", event.Data)
})
```

**C#:**
```csharp
session.On(evt => {
    Console.WriteLine($"Event: {evt.GetType().Name}");
});
```

```