Embed Copilot's agentic workflows in any application using Python, TypeScript, Go, or .NET.
The GitHub Copilot SDK exposes the same engine behind Copilot CLI: a production-tested agent runtime you can invoke programmatically. No need to build your own orchestration - you define agent behavior, Copilot handles planning, tool invocation, file edits, and more.
- GitHub Copilot access and an authenticated environment
- Language runtime: Node.js ^20.19.0 or >=22.12.0, Python 3.11+, Go 1.24+, or a .NET Standard 2.0-compatible implementation
- Go: GitHub Copilot CLI installed and authenticated (Installation guide)
The TypeScript, Python, and .NET packages use a bundled Copilot runtime by default, so they do not need a separate CLI installation.
Note: Replace
<version> with the current release tag from the
Releases page. Pinning versions prevents silent adoption of compromised registry publishes.
mkdir copilot-demo && cd copilot-demo
npm init -y --init-type module
# Pin to a specific release — check https://github.com/github/copilot-sdk/releases for latest
npm install @github/copilot-sdk@<version> tsx@<tsx-version>
# Pin to a specific release — check https://github.com/github/copilot-sdk/releases for latest
pip install github-copilot-sdk==<version>
# For production environments, always pre-download and verify the runtime.
python -m copilot download-runtime
⚠️
Runtime integrity: The published Python wheel pins a specific runtime version, but the download itself is performed without a user-visible checksum step. Before deploying:
Always run
python -m copilot download-runtime explicitly — do not rely on on-demand auto-download in production.
After download, verify the runtime binary hash against the checksum published in the
GitHub release notes for your wheel version.
Do not allow the SDK to auto-download the runtime in network-restricted or production environments.
mkdir copilot-demo && cd copilot-demo
go mod init copilot-demo
# Pin to a specific release — check https://github.com/github/copilot-sdk/releases for latest
go get github.com/github/copilot-sdk/go@v<version>
dotnet new console -n CopilotDemo && cd CopilotDemo
# Pin to a specific release — check https://github.com/github/copilot-sdk/releases for latest
dotnet add package GitHub.Copilot.SDK --version <version>
⚠️
Security: Permission Handlers
The
approveAll /
PermissionHandler.approve_all /
PermissionHandler.ApproveAll helpers shown throughout this skill
auto-approve every permission request (file reads/writes, shell execution, network calls). This is a development convenience only. Never use
approveAll in any environment where the agent has access to real data, repositories, credentials, or production systems.
Use
availableTools and
excludedTools in
SessionConfig to restrict which tools the agent may call, and implement a scoped
onPermissionRequest handler for any environment beyond a local sandbox. See the
Scoped Permission Handler section below for the recommended production pattern.
import { CopilotClient, approveAll } from "@github/copilot-sdk";
const client = new CopilotClient();
const session = await client.createSession({
// ⚠️ DEV ONLY — replace with a scoped handler before any non-sandbox use
onPermissionRequest: approveAll,
model: "gpt-4.1",
});
const response = await session.sendAndWait({ prompt: "What is 2 + 2?" });
console.log(response?.data.content);
await client.stop();
process.exit(0);
To run your script, add a start script to your package.json to use the locally installed tsx binary rather than relying on npx:
{ "scripts": { "start": "tsx index.ts" } }
npm run start
import asyncio
from copilot import CopilotClient, PermissionHandler
async def main():
async with CopilotClient() as client:
async with await client.create_session(
# ⚠️ DEV ONLY — replace with a scoped handler before any non-sandbox use
on_permission_request=PermissionHandler.approve_all,
model="gpt-4.1",
) as session:
response = await session.send_and_wait("What is 2 + 2?")
print(response.data.content)
asyncio.run(main())
package main
import (
"fmt"
"log"
"os"
copilot "github.com/github/copilot-sdk/go"
)
func main() {
client := copilot.NewClient(nil)
if err := client.Start(); err != nil {
log.Fatal(err)
}
defer client.Stop()
session, err := client.CreateSession(&copilot.SessionConfig{
// ⚠️ DEV ONLY — replace with a scoped handler before any non-sandbox use
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
Model: "gpt-4.1",
})
if err != nil {
log.Fatal(err)
}
response, err := session.SendAndWait(copilot.MessageOptions{Prompt: "What is 2 + 2?"}, 0)
if err != nil {
log.Fatal(err)
}
fmt.Println(*response.Data.Content)
os.Exit(0)
}
using GitHub.Copilot.SDK;
await using var client = new CopilotClient();
await using var session = await client.CreateSessionAsync(new SessionConfig
{
// ⚠️ DEV ONLY — replace with a scoped handler before any non-sandbox use
OnPermissionRequest = PermissionHandler.ApproveAll,
Model = "gpt-4.1",
});
var response = await session.SendAndWaitAsync(new MessageOptions { Prompt = "What is 2 + 2?" });
Console.WriteLine(response?.Data.Content);
Run: dotnet run
Enable real-time output for better UX:
import { CopilotClient, approveAll, SessionEvent } from "@github/copilot-sdk";
const client = new CopilotClient();
const session = await client.createSession({
// ⚠️ DEV ONLY — replace with a scoped handler before any non-sandbox use
onPermissionRequest: approveAll,
model: "gpt-4.1",
streaming: true,
});
session.on((event: SessionEvent) => {
if (event.type === "assistant.message_delta") {
process.stdout.write(event.data.deltaContent);
}
if (event.type === "session.idle") {
console.log(); // New line when done
}
});
await session.sendAndWait({ prompt: "Tell me a short joke" });
await client.stop();
process.exit(0);
import asyncio
import sys
from copilot import CopilotClient, PermissionHandler
from copilot.generated.session_events import SessionEventType
async def main():
async with CopilotClient() as client:
async with await client.create_session(
# ⚠️ DEV ONLY — replace with a scoped handler before any non-sandbox use
on_permission_request=PermissionHandler.approve_all,
model="gpt-4.1",
streaming=True,
) as session:
def handle_event(event):
if event.type == SessionEventType.ASSISTANT_MESSAGE_DELTA:
sys.stdout.write(event.data.delta_content)
sys.stdout.flush()
if event.type == SessionEventType.SESSION_IDLE:
print()
session.on(handle_event)
await session.send_and_wait("Tell me a short joke")
asyncio.run(main())
session, err := client.CreateSession(&copilot.SessionConfig{
// ⚠️ DEV ONLY — replace with a scoped handler before any non-sandbox use
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
Model: "gpt-4.1",
Streaming: true,
})
session.On(func(event copilot.SessionEvent) {
if event.Type == "assistant.message_delta" {
fmt.Print(*event.Data.DeltaContent)
}
if event.Type == "session.idle" {
fmt.Println()
}
})
_, err = session.SendAndWait(copilot.MessageOptions{Prompt: "Tell me a short joke"}, 0)
await using var session = await client.CreateSessionAsync(new SessionConfig
{
// ⚠️ DEV ONLY — replace with a scoped handler before any non-sandbox use
OnPermissionRequest = PermissionHandler.ApproveAll,
Model = "gpt-4.1",
Streaming = true,
});
session.On(ev =>
{
if (ev is AssistantMessageDeltaEvent deltaEvent)
Console.Write(deltaEvent.Data.DeltaContent);
if (ev is SessionIdleEvent)
Console.WriteLine();
});
await session.SendAndWaitAsync(new MessageOptions { Prompt = "Tell me a short joke" });
Define tools that Copilot can invoke during reasoning. When you define a tool, you tell Copilot:
- What the tool does (description)
- What parameters it needs (schema)
- What code to run (handler)
import { CopilotClient, approveAll, defineTool, SessionEvent } from "@github/copilot-sdk";
const getWeather = defineTool("get_weather", {
description: "Get the current weather for a city",
parameters: {
type: "object",
properties: {
city: { type: "string", description: "The city name" },
},
required: ["city"],
},
handler: async (args: { city: string }) => {
const { city } = args;
// In a real app, call a weather API here
const conditions = ["sunny", "cloudy", "rainy", "partly cloudy"];
const temp = Math.floor(Math.random() * 30) + 50;
const condition = conditions[Math.floor(Math.random() * conditions.length)];
return { city, temperature: `${temp}°F`, condition };
},
});
const client = new CopilotClient();
const session = await client.createSession({
// ⚠️ DEV ONLY — replace with a scoped handler before any non-sandbox use
onPermissionRequest: approveAll,
model: "gpt-4.1",
streaming: true,
tools: [getWeather],
});
session.on((event: SessionEvent) => {
if (event.type === "assistant.message_delta") {
process.stdout.write(event.data.deltaContent);
}
});
await session.sendAndWait({
prompt: "What's the weather like in Seattle and Tokyo?",
});
await client.stop();
process.exit(0);
import asyncio
import random
import sys
from copilot import CopilotClient, PermissionHandler
from copilot.tools import define_tool
from copilot.generated.session_events import SessionEventType
from pydantic import BaseModel, Field
class GetWeatherParams(BaseModel):
city: str = Field(description="The name of the city to get weather for")
@define_tool(description="Get the current weather for a city")
async def get_weather(params: GetWeatherParams) -> dict:
city = params.city
conditions = ["sunny", "cloudy", "rainy", "partly cloudy"]
temp = random.randint(50, 80)
condition = random.choice(conditions)
return {"city": city, "temperature": f"{temp}°F", "condition": condition}
async def main():
async with CopilotClient() as client:
async with await client.create_session(
# ⚠️ DEV ONLY — replace with a scoped handler before any non-sandbox use
on_permission_request=PermissionHandler.approve_all,
model="gpt-4.1",
streaming=True,
tools=[get_weather],
) as session:
def handle_event(event):
if event.type == SessionEventType.ASSISTANT_MESSAGE_DELTA:
sys.stdout.write(event.data.delta_content)
sys.stdout.flush()
session.on(handle_event)
await session.send_and_wait(
"What's the weather like in Seattle and Tokyo?"
)
asyncio.run(main())
type WeatherParams struct {
City string `json:"city" jsonschema:"The city name"`
}
type WeatherResult struct {
City string `json:"city"`
Temperature string `json:"temperature"`
Condition string `json:"condition"`
}
getWeather := copilot.DefineTool(
"get_weather",
"Get the current weather for a city",
func(params WeatherParams, inv copilot.ToolInvocation) (WeatherResult, error) {
conditions := []string{"sunny", "cloudy", "rainy", "partly cloudy"}
temp := rand.Intn(30) + 50
condition := conditions[rand.Intn(len(conditions))]
return WeatherResult{
City: params.City,
Temperature: fmt.Sprintf("%d°F", temp),
Condition: condition,
}, nil
},
)
session, _ := client.CreateSession(&copilot.SessionConfig{
// ⚠️ DEV ONLY — replace with a scoped handler before any non-sandbox use
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
Model: "gpt-4.1",
Streaming: true,
Tools: []copilot.Tool{getWeather},
})
using GitHub.Copilot.SDK;
using Microsoft.Extensions.AI;
using System.ComponentModel;
var getWeather = AIFunctionFactory.Create(
([Description("The city name")] string city) =>
{
var conditions = new[] { "sunny", "cloudy", "rainy", "partly cloudy" };
var temp = Random.Shared.Next(50, 80);
var condition = conditions[Random.Shared.Next(conditions.Length)];
return new { city, temperature = $"{temp}°F", condition };
},
"get_weather",
"Get the current weather for a city"
);
await using var session = await client.CreateSessionAsync(new SessionConfig
{
// ⚠️ DEV ONLY — replace with a scoped handler before any non-sandbox use
OnPermissionRequest = PermissionHandler.ApproveAll,
Model = "gpt-4.1",
Streaming = true,
Tools = [getWeather],
});
When Copilot decides to call your tool:
- Copilot sends a tool call request with the parameters
- The SDK runs your handler function
- The result is sent back to Copilot
- Copilot incorporates the result into its response
Copilot decides when to call your tool based on the user's question and your tool's description.
Build a complete interactive assistant:
import { CopilotClient, approveAll, defineTool, SessionEvent } from "@github/copilot-sdk";
import * as readline from "readline";
const getWeather = defineTool("get_weather", {
description: "Get the current weather for a city",
parameters: {
type: "object",
properties: {
city: { type: "string", description: "The city name" },
},
required: ["city"],
},
handler: async ({ city }) => {
const conditions = ["sunny", "cloudy", "rainy", "partly cloudy"];
const temp = Math.floor(Math.random() * 30) + 50;
const condition = conditions[Math.floor(Math.random() * conditions.length)];
return { city, temperature: `${temp}°F`, condition };
},
});
const client = new CopilotClient();
const session = await client.createSession({
// ⚠️ DEV ONLY — replace with a scoped handler before any non-sandbox use
onPermissionRequest: approveAll,
model: "gpt-4.1",
streaming: true,
tools: [getWeather],
});
session.on((event: SessionEvent) => {
if (event.type === "assistant.message_delta") {
process.stdout.write(event.data.deltaContent);
}
});
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
console.log("Weather Assistant (type 'exit' to quit)");
console.log("Try: 'What's the weather in Paris?'\n");
const prompt = () => {
rl.question("You: ", async (input) => {
if (input.toLowerCase() === "exit") {
await client.stop();
rl.close();
return;
}
process.stdout.write("Assistant: ");
await session.sendAndWait({ prompt: input });
console.log("\n");
prompt();
});
};
prompt();
import asyncio
import random
import sys
from copilot import CopilotClient, PermissionHandler
from copilot.tools import define_tool
from copilot.generated.session_events import SessionEventType
from pydantic import BaseModel, Field
class GetWeatherParams(BaseModel):
city: str = Field(description="The name of the city to get weather for")
@define_tool(description="Get the current weather for a city")
async def get_weather(params: GetWeatherParams) -> dict:
conditions = ["sunny", "cloudy", "rainy", "partly cloudy"]
temp = random.randint(50, 80)
condition = random.choice(conditions)
return {"city": params.city, "temperature": f"{temp}°F", "condition": condition}
async def main():
async with CopilotClient() as client:
async with await client.create_session(
# ⚠️ DEV ONLY — replace with a scoped handler before any non-sandbox use
on_permission_request=PermissionHandler.approve_all,
model="gpt-4.1",
streaming=True,
tools=[get_weather],
) as session:
def handle_event(event):
if event.type == SessionEventType.ASSISTANT_MESSAGE_DELTA:
sys.stdout.write(event.data.delta_content)
sys.stdout.flush()
session.on(handle_event)
print("Weather Assistant (type 'exit' to quit)")
print("Try: 'What's the weather in Paris?'\n")
while True:
try:
user_input = input("You: ")
except EOFError:
break
if user_input.lower() == "exit":
break
sys.stdout.write("Assistant: ")
await session.send_and_wait(user_input)
print("\n")
asyncio.run(main())
Connect to MCP (Model Context Protocol) servers for pre-built tools. Connect to GitHub's MCP server for repository, issue, and PR access:
Note: Connecting to https://api.githubcopilot.com/mcp/ sends your prompts and tool results to GitHub's Copilot API, identical to using Copilot directly. Review your organization's data-handling policy before connecting production or sensitive data to this endpoint.
const session = await client.createSession({
// ⚠️ DEV ONLY — replace with a scoped handler before any non-sandbox use
onPermissionRequest: approveAll,
model: "gpt-4.1",
mcpServers: {
github: {
type: "http",
url: "https://api.githubcopilot.com/mcp/",
},
},
});
async with await client.create_session(
# ⚠️ DEV ONLY — replace with a scoped handler before any non-sandbox use
on_permission_request=PermissionHandler.approve_all,
model="gpt-4.1",
mcp_servers={
"github": {
"type": "http",
"url": "https://api.githubcopilot.com/mcp/",
},
},
) as session:
...
session, _ := client.CreateSession(&copilot.SessionConfig{
// ⚠️ DEV ONLY — replace with a scoped handler before any non-sandbox use
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
Model: "gpt-4.1",
MCPServers: map[string]copilot.MCPServerConfig{
"github": {
"type": "http",
"url": "https://api.githubcopilot.com/mcp/",
},
},
})
await using var session = await client.CreateSessionAsync(new SessionConfig
{
// ⚠️ DEV ONLY — replace with a scoped handler before any non-sandbox use
OnPermissionRequest = PermissionHandler.ApproveAll,
Model = "gpt-4.1",
McpServers = new Dictionary<string, McpServerConfig>
{
["github"] = new McpServerConfig
{
Type = "http",
Url = "https://api.githubcopilot.com/mcp/",
},
},
});
Define specialized AI personas for specific tasks:
const session = await client.createSession({
// ⚠️ DEV ONLY — replace with a scoped handler before any non-sandbox use
onPermissionRequest: approveAll,
model: "gpt-4.1",
customAgents: [{
name: "pr-reviewer",
displayName: "PR Reviewer",
description: "Reviews pull requests for best practices",
prompt: "You are an expert code reviewer. Focus on security, performance, and maintainability.",
}],
});
async with await client.create_session(
# ⚠️ DEV ONLY — replace with a scoped handler before any non-sandbox use
on_permission_request=PermissionHandler.approve_all,
model="gpt-4.1",
custom_agents=[{
"name": "pr-reviewer",
"display_name": "PR Reviewer",
"description": "Reviews pull requests for best practices",
"prompt": "You are an expert code reviewer. Focus on security, performance, and maintainability.",
}],
) as session:
...
Customize the AI's behavior and personality:
const session = await client.createSession({
// ⚠️ DEV ONLY — replace with a scoped handler before any non-sandbox use
onPermissionRequest: approveAll,
model: "gpt-4.1",
systemMessage: {
content: "You are a helpful assistant for our engineering team. Always be concise.",
},
});
async with await client.create_session(
# ⚠️ DEV ONLY — replace with a scoped handler before any non-sandbox use
on_permission_request=PermissionHandler.approve_all,
model="gpt-4.1",
system_message={
"content": "You are a helpful assistant for our engineering team. Always be concise.",
},
) as session:
...
Run the CLI in server mode separately and connect the SDK to it. Useful for debugging, resource sharing, or custom environments.
Note: This command launches a long-running server process and should be run manually by the user before invoking the SDK. It is a prerequisite step, not an agent-executed command.
copilot --server --port 4321
const client = new CopilotClient({
cliUrl: "localhost:4321"
});
const session = await client.createSession({
// ⚠️ DEV ONLY — replace with a scoped handler before any non-sandbox use
onPermissionRequest: approveAll,
model: "gpt-4.1",
});
from copilot import CopilotClient, PermissionHandler, RuntimeConnection
async with CopilotClient(
connection=RuntimeConnection.for_uri("localhost:4321")
) as client:
async with await client.create_session(
# ⚠️ DEV ONLY — replace with a scoped handler before any non-sandbox use
on_permission_request=PermissionHandler.approve_all,
model="gpt-4.1",
) as session:
...
client := copilot.NewClient(&copilot.ClientOptions{
CLIUrl: "localhost:4321",
})
if err := client.Start(); err != nil {
log.Fatal(err)
}
session, _ := client.CreateSession(&copilot.SessionConfig{
// ⚠️ DEV ONLY — replace with a scoped handler before any non-sandbox use
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
Model: "gpt-4.1",
})
using var client = new CopilotClient(new CopilotClientOptions
{
CliUrl = "localhost:4321"
});
await using var session = await client.CreateSessionAsync(new SessionConfig
{
// ⚠️ DEV ONLY — replace with a scoped handler before any non-sandbox use
OnPermissionRequest = PermissionHandler.ApproveAll,
Model = "gpt-4.1",
});
Note: When configured to use an external server, the SDK manages only its connection and does not manage the external process.
| Event | Description |
|---|
user.message
| User input added |
assistant.message
| Complete model response |
assistant.message_delta
| Streaming response chunk |
assistant.reasoning
| Model reasoning (model-dependent) |
assistant.reasoning_delta
| Streaming reasoning chunk |
tool.execution_start
| Tool invocation started |
tool.execution_complete
| Tool execution finished |
session.idle
| No active processing |
session.error
| Error occurred |
| Option | Description | Default |
|---|
cliPath
| Path to Copilot CLI executable | System PATH |
cliUrl
| Connect to existing server (e.g., "localhost:4321") | None |
port
| Server communication port | Random |
useStdio
| Use stdio transport instead of TCP | true |
logLevel
| Logging verbosity | "info" |
autoStart
| Launch server automatically | true |
autoRestart
| Restart on crashes | true |
cwd
| Working directory for CLI process | Inherited |
| Option | Description | Example |
|---|
model
| LLM to use ("gpt-4.1", "claude-sonnet-4.5", etc.) | "gpt-4.1"
|
sessionId
| Custom session identifier | "user-123-conversation"
|
tools
| Custom tool definitions | [getWeather, getStockPrice]
|
mcpServers
| MCP server connections | { github: { type: "http", url: "..." } }
|
customAgents
| Custom agent personas | [{ name: "pr-reviewer", ... }]
|
systemMessage
| Override default system prompt | { content: "You are..." }
|
streaming
| Enable incremental response chunks | true
|
availableTools
| Whitelist of permitted tools (agent may only call listed tools) | ["get_weather", "read_file"]
|
excludedTools
| Blocklist of disabled tools | ["execute_shell"]
|
In any non-sandbox environment, replace approveAll with a handler that approves only what your application specifically requires. The examples below use availableTools to whitelist the exact tool set this session needs, and annotate the permission handler clearly.
// ✅ Production pattern — whitelist only the tools this session needs
const session = await client.createSession({
// Replace this comment-block with logic appropriate to your application.
// The handler below is illustrative; adapt the approved conditions to match
// the actual permission types your SDK version exposes.
onPermissionRequest: async (request) => {
// Consult the SDK's PermissionRequest type for the actual fields available.
// Deny everything by default; approve only what you explicitly expect.
console.warn(`[SECURITY] Permission request received: ${JSON.stringify(request)} — denied by default. Implement application-specific approval logic here.`);
return { approved: false };
},
availableTools: ["get_weather"], // whitelist only the tools this session needs
model: "gpt-4.1",
});
# ✅ Production pattern — deny by default, whitelist only needed tools
async with await client.create_session(
# Replace with a handler that approves only the specific requests your
# application requires. Consult the SDK docs for the PermissionRequest fields.
on_permission_request=PermissionHandler.deny_all, # or a custom async handler
model="gpt-4.1",
available_tools=["get_weather"], # whitelist only the tools this session needs
) as session:
...
// ✅ Production pattern — deny by default, whitelist only needed tools
session, _ := client.CreateSession(&copilot.SessionConfig{
// Replace with a handler that approves only the specific requests your
// application requires. Consult the SDK docs for the PermissionRequest fields.
OnPermissionRequest: copilot.PermissionHandler.DenyAll, // or a custom handler
Model: "gpt-4.1",
AvailableTools: []string{"get_weather"},
})
// ✅ Production pattern — deny by default, whitelist only needed tools
await using var session = await client.CreateSessionAsync(new SessionConfig
{
// Replace with a handler that approves only the specific requests your
// application requires. Consult the SDK docs for the PermissionRequest fields.
OnPermissionRequest = PermissionHandler.DenyAll, // or a custom handler
Model = "gpt-4.1",
AvailableTools = new[] { "get_weather" },
});
Save and resume conversations across restarts:
const session = await client.createSession({
// ⚠️ DEV ONLY — replace with a scoped handler before any non-sandbox use
onPermissionRequest: approveAll,
sessionId: "user-123-conversation",
model: "gpt-4.1"
});
const session = await client.resumeSession("user-123-conversation", {
// ⚠️ DEV ONLY — replace with a scoped handler before any non-sandbox use
onPermissionRequest: approveAll
});
await session.send({ prompt: "What did we discuss earlier?" });
const sessions = await client.listSessions();
await client.deleteSession("old-session-id");
try {
const client = new CopilotClient();
const session = await client.createSession({
// ⚠️ DEV ONLY — replace with a scoped handler before any non-sandbox use
onPermissionRequest: approveAll,
model: "gpt-4.1",
});
const response = await session.sendAndWait(
{ prompt: "Hello!" },
30000 // timeout in ms
);
} catch (error) {
if (error.code === "ENOENT") {
console.error("Copilot CLI not installed");
} else if (error.code === "ECONNREFUSED") {
console.error("Cannot connect to Copilot server");
} else {
console.error("Error:", error.message);
}
} finally {
await client.stop();
}
process.on("SIGINT", async () => {
console.log("Shutting down...");
await client.stop();
process.exit(0);
});
const session = await client.createSession({
// ⚠️ DEV ONLY — replace with a scoped handler before any non-sandbox use
onPermissionRequest: approveAll,
model: "gpt-4.1",
});
await session.sendAndWait({ prompt: "My name is Alice" });
await session.sendAndWait({ prompt: "What's my name?" });
// Response: "Your name is Alice"
await session.send({
prompt: "Analyze this file",
attachments: [{
type: "file",
path: "./data.csv",
displayName: "Sales Data"
}]
});
const timeoutId = setTimeout(() => {
session.abort();
}, 60000);
session.on((event) => {
if (event.type === "session.idle") {
clearTimeout(timeoutId);
}
});
Query available models at runtime:
const models = await client.getModels();
// Returns: ["gpt-4.1", "gpt-4o", "claude-sonnet-4.5", ...]
- Never use
approveAll outside a local sandbox: approveAll / PermissionHandler.approve_all / PermissionHandler.ApproveAll disables all security gates, granting the agent unrestricted access to files, shell commands, and network resources. Always implement a scoped onPermissionRequest handler that approves only the minimum necessary permissions, or use availableTools to whitelist specific functions. See the Scoped Permission Handler section for production patterns.
- Always clean up: Use language-native context managers or disposal, or explicitly disconnect sessions and stop clients
- Set timeouts: Use
sendAndWait with timeout for long operations
- Handle events: Subscribe to error events for robust error handling
- Use streaming: Enable streaming for better UX on long responses
- Persist sessions: Use custom session IDs for multi-turn conversations
- Define clear tools: Write descriptive tool names and descriptions
- Scope permissions: Replace
approveAll with a handler that approves only the specific permission types your application requires. Use availableTools to whitelist the minimum tool set for each session.
Your Application
|
SDK Client
| JSON-RPC
Copilot CLI (server mode)
|
GitHub (models, auth)
The SDK manages the CLI process lifecycle automatically. All communication happens via JSON-RPC over stdio or TCP.
This SDK is in Technical Preview and may have breaking changes. Not recommended for production use yet.