Copilot SDK for Node.js/TypeScript
TypeScript SDK for programmatic control of GitHub Copilot CLI via JSON-RPC.
Installation
npm install @github/copilot-sdk
Quick Start
import { CopilotClient } from "@github/copilot-sdk";
const client = new CopilotClient();
await client.start();
const session = await client.createSession({
model: "gpt-5"
});
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();
API Reference
CopilotClient
Constructor
new CopilotClient(options?: CopilotClientOptions)
Options:
cliPath?: string - Path to CLI executable (default: "copilot" from PATH)
cliArgs?: string[] - Extra arguments prepended before SDK-managed flags (e.g. ["./dist-cli/index.js"] when using node)
cliUrl?: string - URL of existing CLI server to connect to (e.g., "localhost:8080", "http://127.0.0.1:9000", or just "8080"). When provided, the client will not spawn a CLI process. Mutually exclusive with cliPath and useStdio.
port?: number - Server port (default: 0 for random)
useStdio?: boolean - Use stdio transport (default: true)
logLevel?: string - Log level (default: "info")
autoStart?: boolean - Auto-start server (default: true)
autoRestart?: boolean - Auto-restart on crash (default: true)
Methods
start(): Promise<void>
Start the CLI server and establish connection.
stop(): Promise<Error[]>
Stop the server and close all sessions. Returns a list of any errors encountered during cleanup.
forceStop(): Promise<void>
Force stop the CLI server without graceful cleanup. Use when stop() takes too long.
createSession(config?: SessionConfig): Promise<CopilotSession>
Create a new conversation session.
Config:
sessionId?: string - Custom session ID
model?: string - Model to use ("gpt-5", "claude-sonnet-4.5", etc.)
tools?: Tool[] - Custom tools exposed to the CLI
systemMessage?: SystemMessageConfig - System message customization (see below)
resumeSession(sessionId: string, config?: ResumeSessionConfig): Promise<CopilotSession>
Resume an existing session.
ping(message?: string): Promise<{ message: string; timestamp: number }>
Ping the server to check connectivity.
getState(): ConnectionState
Get current connection state.
listSessions(): Promise<SessionMetadata[]>
List all available sessions.
deleteSession(sessionId: string): Promise<void>
Delete a session and its data from disk.
CopilotSession
Represents a single conversation session.
Methods
send(options: MessageOptions): Promise<string>
Send a message to the session.
Options:
prompt: string - The message/prompt to send
attachments?: Array<{type, path, displayName}> - File attachments
mode?: "enqueue" | "immediate" - Delivery mode
Returns the message ID.
on(handler: SessionEventHandler): () => void
Subscribe to session events. Returns an unsubscribe function.
const unsubscribe = session.on((event) => {
console.log(event);
});
unsubscribe();
abort(): Promise<void>
Abort the currently processing message in this session.
getMessages(): Promise<SessionEvent[]>
Get all events/messages from this session.
destroy(): Promise<void>
Destroy the session and free resources.
Event Types
Sessions emit various events during processing:
user.message - User message added
assistant.message - Assistant response
assistant.message_chunk - Streaming response chunk
tool.execution_start - Tool execution started
tool.execution_end - Tool execution completed
- And more...
See SessionEvent type in the source for full details.
Advanced Usage
Manual Server Control
const client = new CopilotClient({ autoStart: false });
await client.start();
await client.stop();
Tools
You can let the CLI call back into your process when the model needs capabilities you own. Use defineTool with Zod schemas for type-safe tool definitions:
import { z } from "zod";
import { CopilotClient, defineTool } from "@github/copilot-sdk";
const session = await client.createSession({
model: "gpt-5",
tools: [
defineTool("lookup_issue", {
description: "Fetches issue details from our internal tracker",
parameters: z.object({
id: z.string().describe("Issue identifier"),
}),
handler: async ({ id }) => {
const issue = await fetchIssue(id);
return issue;
},
}),
],
});
When Copilot invokes lookup_issue, the client automatically runs your handler and responds to the CLI. Handlers can return any JSON-serializable value (automatically wrapped), a simple string, or a ToolResultObject for full control over result metadata. Raw JSON schemas are also supported if Zod isn't desired.
System Message Customization
Control the system prompt using systemMessage in session config:
const session = await client.createSession({
model: "gpt-5",
systemMessage: {
content: `
<workflow_rules>
- Always check for security vulnerabilities
- Suggest performance improvements when applicable
</workflow_rules>
`,
},
});
The SDK auto-injects environment context, tool instructions, and security guardrails. The default CLI persona is preserved, and your content is appended after SDK-managed sections. To change the persona or fully redefine the prompt, use mode: "replace".
For full control (removes all guardrails), use mode: "replace":
const session = await client.createSession({
model: "gpt-5",
systemMessage: {
mode: "replace",
content: "You are a helpful assistant.",
},
});
Multiple Sessions
const session1 = await client.createSession({ model: "gpt-5" });
const session2 = await client.createSession({ model: "claude-sonnet-4.5" });
await session1.send({ prompt: "Hello from session 1" });
await session2.send({ prompt: "Hello from session 2" });
Custom Session IDs
const session = await client.createSession({
sessionId: "my-custom-session-id",
model: "gpt-5",
});
File Attachments
await session.send({
prompt: "Analyze this file",
attachments: [
{
type: "file",
path: "/path/to/file.js",
displayName: "My File",
},
],
});
Error Handling
try {
const session = await client.createSession();
await session.send({ prompt: "Hello" });
} catch (error) {
console.error("Error:", error.message);
}
Requirements
- Node.js >= 18.0.0
- GitHub Copilot CLI installed and in PATH (or provide custom
cliPath)
License
MIT