GitHub Copilot SDK Core Components: Client, Session, Tools, and Hooks Explained
The GitHub Copilot SDK architecture centers on four primary building blocks: the Client manages the CLI subprocess lifecycle and RPC connections; the Session maintains conversation state and coordinates tools; Tools provide model-callable functions through built-in and custom definitions; and Hooks enable interception of execution flow via callback handlers.
The GitHub Copilot SDK allows developers to programmatically drive GitHub Copilot from Node.js applications. Understanding these GitHub Copilot SDK core components is essential for implementing custom AI agents that leverage the Copilot CLI subprocess through structured JSON-RPC communication.
The Client Component
The Client serves as the primary entry point for all SDK interactions. Implemented in nodejs/src/client.ts, the CopilotClient class handles the initialization of the Copilot CLI subprocess and manages the RPC protocol negotiation.
When instantiated, the client establishes the foundation for session management and exposes a global RPC API (hooks.invoke) for hook-related operations. The CopilotClient exports the main interface used to create or resume conversation sessions with the underlying Copilot engine.
The Session Component
The Session represents a single conversation instance with the Copilot CLI. Defined in nodejs/src/session.ts, the CopilotSession class maintains the JSON-RPC connection, event routing systems, and registries for both tools and hooks.
Key responsibilities include:
- Managing the
MessageConnectionto the subprocess - Maintaining a
Map<string, ToolHandler>calledtoolHandlersfor resolving tool invocations - Dispatching hook callbacks during the tool execution lifecycle
- Handling session lifecycle events from start to disconnection
The session stores an optional SessionHooks object (defined as private hooks?: SessionHooks) and triggers appropriate handlers during execution.
The Tools Framework
Tools provide callable functions that the Copilot model can invoke during conversations. The SDK ships with BuiltInTools and allows registration of custom tools via the ToolSet abstraction in nodejs/src/toolSet.ts.
Key types include:
ToolandToolHandlerinterfaces for defining tool contractsToolSetfor collecting multiple toolsdefineToolhelper for creating type-safe tool definitions
Developers can override built-in tools by registering a custom Tool with the same name and setting overridesBuiltInTool: true in the configuration. The session routes tool invocation requests to the appropriate handler stored in its internal toolHandlers map.
The Hooks System
Hooks provide extension points that allow code execution before or after tool operations and during session lifecycle events. The SessionHooks interface is defined in nodejs/src/types.ts (lines 1481-1528) and includes handlers such as onPreToolUse, onPostToolUse, and onPostToolUseFailure.
Hook capabilities include:
- Pre-execution interception:
onPreToolUsehandlers can inspect or modify arguments, or abort execution by throwing - Post-execution handling:
onPostToolUsereceives results for logging or transformation - Failure recovery:
onPostToolUseFailureenables custom retry logic (e.g., returning{ retryCount: 1 }) - Lifecycle management:
onSessionStartandonSessionEndtrack session state
Hook inputs undergo deserialization via deserializeHookInput to convert raw RPC data into developer-friendly objects with proper timestamp and working-directory formatting.
How the Components Interact
The four components form a unified pipeline: Client → Session → Tools → Hooks.
- Initialization:
CopilotClient.createSession()(orresumeSession) spawns the subprocess, creates theMessageConnection, and instantiatesCopilotSession - Registration: The session accepts an optional
SessionHooksobject viaregisterHooks(defined innodejs/src/session.ts, lines 1153-1157) and maintains thetoolHandlersmap for routing - Execution: When the model invokes a tool, the session looks up the handler, then sequentially triggers
onPreToolUse, the tool handler itself, and eitheronPostToolUseoronPostToolUseFailure - RPC Bridging: The client exposes
hooks.invokefor forwarding hook-related JSON-RPC calls to the session's dispatcher
Implementation Examples
Creating a Client and Session with Custom Hooks
import { CopilotClient, type SessionHooks } from "@github/copilot-sdk";
const hooks: SessionHooks = {
// Run before any tool call
onPreToolUse: async ({ toolName, args }) => {
console.log(`About to run ${toolName} with`, args);
// Return nothing to allow the call, or throw to abort
},
// Run after a successful tool call
onPostToolUse: async ({ toolName, result }) => {
console.log(`Tool ${toolName} succeeded:`, result);
},
// Run after a failed tool call
onPostToolUseFailure: async ({ toolName, error }) => {
console.warn(`Tool ${toolName} failed:`, error);
// Example: retry once
return { retryCount: 1 };
},
// Session lifecycle hooks
onSessionStart: async () => console.log("Session started"),
onSessionEnd: async () => console.log("Session ended"),
};
async function main() {
const client = new CopilotClient();
const session = await client.createSession({ hooks });
await session.sendAndWait({ prompt: "Explain the Fibonacci sequence." });
await session.disconnect();
}
main();
Registering a Custom Tool
import { defineTool, CopilotClient } from "@github/copilot-sdk";
const myTool = defineTool({
name: "weather",
description: "Get current weather for a city",
parameters: {
type: "object",
properties: {
city: { type: "string", description: "City name" },
},
required: ["city"],
},
// Core logic for the tool
handler: async ({ city }) => {
// Pretend we call an external API
return `The weather in ${city} is sunny, 25 °C.`;
},
});
async function demo() {
const client = new CopilotClient();
const session = await client.createSession();
// Register the tool with the session
session.registerTool(myTool);
// Invoke the tool via a prompt
await session.sendAndWait({ prompt: "What’s the weather in Paris?" });
await session.disconnect();
}
demo();
Modifying Tool Arguments with Hooks
const hooks = {
onPreToolUse: async ({ toolName, args }) => {
if (toolName === "weather") {
// Normalize city names
args.city = args.city.trim().toLowerCase();
}
},
};
Summary
- Client (
nodejs/src/client.ts): Entry point that manages the Copilot CLI subprocess lifecycle and RPC protocol negotiation viaCopilotClient - Session (
nodejs/src/session.ts): Maintains conversation state, JSON-RPC connection, and registries for tools (toolHandlersMap) and hooks - Tools (
nodejs/src/toolSet.ts): Model-callable functions defined viaToolandToolHandlerinterfaces, registered throughToolSetwith optional built-in overrides - Hooks (
nodejs/src/types.ts): Callback system enabling pre-execution (onPreToolUse), post-execution (onPostToolUse), and failure handling (onPostToolUseFailure) interception points
Frequently Asked Questions
How do I override a built-in tool in the GitHub Copilot SDK?
Register a custom tool with the same name as the built-in tool and set overridesBuiltInTool: true in the tool definition. According to the source code in nodejs/src/session.ts, the session checks this flag when building the toolHandlers map, allowing your custom implementation to replace the default behavior.
What is the difference between Session and Client in the Copilot SDK?
Client (CopilotClient) is a long-lived factory that manages the subprocess and can create multiple sessions, while Session (CopilotSession) represents a single conversation instance with isolated state, tool registries, and hook configurations. As implemented in nodejs/src/client.ts, the client handles createSession() and resumeSession() calls, returning distinct CopilotSession instances defined in nodejs/src/session.ts.
Can hooks modify tool arguments before execution?
Yes. The onPreToolUse hook receives the tool name and arguments object before the handler executes, allowing you to transform inputs (such as normalizing strings or adding computed properties) or abort the call by throwing an error. This occurs after deserializeHookInput processes the raw RPC data into the structured format passed to your handler.
Where are the hook TypeScript interfaces defined?
The SessionHooks interface and all related handler types (PreToolUseHandler, PostToolUseHandler, etc.) are declared in nodejs/src/types.ts at lines 1481-1528. This file also contains the deserialization logic that prepares hook inputs from the JSON-RPC layer for consumption by your callback functions.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →