Install
$ agentstack add skill-sinedied-agent-skills-copilot-sdk-nodejs ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
GitHub Copilot SDK — Node.js / TypeScript
Core Principles
- The SDK is in technical preview and may have breaking changes
- Requires Node.js 18.0 or later
- Requires GitHub Copilot CLI installed and in PATH
- Built with TypeScript for type safety
- Uses async/await patterns throughout
- Provides full TypeScript type definitions
Installation
npm install @github/copilot-sdk
# or
pnpm add @github/copilot-sdk
# or
yarn add @github/copilot-sdk
Client Initialization
Basic Client Setup
import { CopilotClient, approveAll } from "@github/copilot-sdk";
const client = new CopilotClient();
await client.start();
// Use client...
await client.stop();
Client Configuration Options
CopilotClientOptions:
cliPath- Path to CLI executable (default: "copilot" from PATH)cliArgs- Extra arguments prepended before SDK-managed flags (string[])cliUrl- URL of existing CLI server (e.g., "localhost:8080"). When provided, client won't spawn a processport- Server port (default: 0 for random)useStdio- Use stdio transport instead of TCP (default: true)logLevel- Log level (default: "debug")autoStart- Auto-start server (default: true)autoRestart- Auto-restart on crash (default: true)cwd- Working directory for the CLI process (default: process.cwd())env- Environment variables for the CLI process (default: process.env)
Manual Server Control
const client = new CopilotClient({ autoStart: false });
await client.start();
// Use client...
await client.stop();
Use forceStop() when stop() takes too long.
Session Management
Creating Sessions
const session = await client.createSession({
onPermissionRequest: approveAll,
model: "gpt-5",
streaming: true,
tools: [...],
systemMessage: { ... },
availableTools: ["tool1", "tool2"],
excludedTools: ["tool3"],
provider: { ... }
});
Session Config Options
sessionId- Custom session ID (string)model- Model name ("gpt-5", "claude-sonnet-4.5", etc.)tools- Custom tools exposed to the CLI (Tool[])systemMessage- System message customization (SystemMessageConfig)availableTools- Allowlist of tool names (string[])excludedTools- Blocklist of tool names (string[])provider- Custom API provider configuration (BYOK) (ProviderConfig)streaming- Enable streaming response chunks (boolean)mcpServers- MCP server configurations (MCPServerConfig[])customAgents- Custom agent configurations (CustomAgentConfig[])configDir- Config directory override (string)skillDirectories- Skill directories (string[])disabledSkills- Disabled skills (string[])onPermissionRequest- Permission request handler (PermissionHandler)
Resuming Sessions
const session = await client.resumeSession("session-id", {
tools: [myNewTool],
onPermissionRequest: approveAll,
});
Session Operations
session.sessionId- Get session identifier (string)await session.send({ prompt: "...", attachments: [...] })- Send message, returns Promise\await session.sendAndWait({ prompt: "..." }, timeout)- Send and wait for idle, returns Promise\await session.abort()- Abort current processingawait session.getMessages()- Get all events/messages, returns Promise\await session.destroy()- Clean up session
Event Handling
Event Subscription Pattern
ALWAYS use async/await or Promises for waiting on session events:
await new Promise((resolve) => {
session.on((event) => {
if (event.type === "assistant.message") {
console.log(event.data.content);
} else if (event.type === "session.idle") {
resolve();
}
});
session.send({ prompt: "..." });
});
Unsubscribing from Events
The on() method returns an unsubscribe function:
const unsubscribe = session.on((event) => { /* handler */ });
unsubscribe();
Event Types
Use discriminated unions with type guards:
session.on((event) => {
switch (event.type) {
case "user.message": break;
case "assistant.message": console.log(event.data.content); break;
case "tool.executionStart": break;
case "tool.executionComplete": break;
case "session.start": break;
case "session.idle": break;
case "session.error": console.error(event.data.message); break;
}
});
Streaming Responses
Enable with streaming: true in SessionConfig. Handle both delta and final events:
session.on((event) => {
switch (event.type) {
case "assistant.message_delta":
process.stdout.write(event.data.deltaContent); break;
case "assistant.reasoning_delta":
process.stdout.write(event.data.deltaContent); break;
case "assistant.message":
console.log(event.data.content); break;
case "assistant.reasoning":
console.log(event.data.content); break;
case "session.idle": break;
}
});
Final events (assistant.message, assistant.reasoning) are ALWAYS sent regardless of streaming setting.
Custom Tools
defineTool (JSON Schema)
import { defineTool } from "@github/copilot-sdk";
defineTool({
name: "lookup_issue",
description: "Fetch issue details from tracker",
parameters: {
type: "object",
properties: { id: { type: "string", description: "Issue ID" } },
required: ["id"],
},
handler: async (args) => {
return await fetchIssue(args.id);
},
})
defineTool (Zod)
import { z } from "zod";
import { defineTool } from "@github/copilot-sdk";
defineTool({
name: "get_weather",
description: "Get weather for a location",
parameters: z.object({
location: z.string().describe("City name"),
units: z.enum(["celsius", "fahrenheit"]).optional(),
}),
handler: async (args) => {
return { temperature: 72, units: args.units || "fahrenheit" };
},
})
Tool Return Types
- Return any JSON-serializable value (automatically wrapped)
- Or return
ToolResultObjectfor full control:
{ textResultForLlm: string; resultType: "success" | "failure"; error?: string; toolTelemetry?: Record; }
System Message Customization
Append Mode (default — preserves guardrails)
systemMessage: { mode: "append", content: "Additional instructions..." }
Replace Mode (full control — removes guardrails)
systemMessage: { mode: "replace", content: "You are a helpful assistant." }
File Attachments
await session.send({
prompt: "Analyze this file",
attachments: [{ type: "file", path: "/path/to/file.ts", displayName: "My File" }],
});
Message Delivery Modes
"enqueue"- Queue message for processing"immediate"- Process message immediately
Multiple Sessions
Sessions are independent and can run concurrently. See [multiple-sessions recipe](references/multiple-sessions.md).
Bring Your Own Key (BYOK)
const session = await client.createSession({
onPermissionRequest: approveAll,
provider: { type: "openai", baseUrl: "https://api.openai.com/v1", apiKey: "your-api-key" },
});
Session Lifecycle Management
const sessions = await client.listSessions(); // List all sessions
await client.deleteSession(sessionId); // Delete a session
const lastId = await client.getLastSessionId(); // Get last session ID
const state = client.getState(); // "disconnected" | "connecting" | "connected" | "error"
Resource Cleanup
ALWAYS use try-finally:
const client = new CopilotClient();
try {
await client.start();
const session = await client.createSession({ onPermissionRequest: approveAll });
try {
// Use session...
} finally {
await session.destroy();
}
} finally {
await client.stop();
}
Cleanup Helper Pattern
async function withClient(fn: (client: CopilotClient) => Promise): Promise {
const client = new CopilotClient();
try { await client.start(); return await fn(client); }
finally { await client.stop(); }
}
async function withSession(client: CopilotClient, fn: (session: CopilotSession) => Promise): Promise {
const session = await client.createSession({ onPermissionRequest: approveAll });
try { return await fn(session); }
finally { await session.destroy(); }
}
Connectivity Testing
const response = await client.ping("health check");
TypeScript Features
Type Inference
import type { SessionEvent, AssistantMessageEvent } from "@github/copilot-sdk";
session.on((event: SessionEvent) => {
if (event.type === "assistant.message") {
const content: string = event.data.content; // narrowed
}
});
Generic Event Helper
async function waitForEvent(
session: CopilotSession, eventType: T,
): Promise> {
return new Promise((resolve) => {
const unsubscribe = session.on((event) => {
if (event.type === eventType) { unsubscribe(); resolve(event as any); }
});
});
}
Best Practices
- Always use try-finally for resource cleanup
- Use Promises to wait for session.idle event
- Handle session.error events for robust error handling
- Use type guards or switch statements for event handling
- Enable streaming for better UX in interactive scenarios
- Use defineTool for type-safe tool definitions
- Use Zod schemas for runtime parameter validation
- Dispose event subscriptions when no longer needed
- Use systemMessage with mode: "append" to preserve safety guardrails
- Handle both delta and final events when streaming is enabled
- Leverage TypeScript types for compile-time safety
Cookbook Recipes
For practical, copy-pasteable examples, see the references:
- [Error Handling](references/error-handling.md): Connection failures, timeouts, abort, graceful shutdown
- [Multiple Sessions](references/multiple-sessions.md): Parallel conversations, custom IDs, listing/deleting
- [Managing Local Files](references/managing-local-files.md): AI-powered file organization by metadata
- [PR Visualization](references/pr-visualization.md): Interactive PR age charts using GitHub MCP Server
- [Persisting Sessions](references/persisting-sessions.md): Save and resume sessions across restarts
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: sinedied
- Source: sinedied/agent-skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.