# GitHub Copilot SDK Core Components: Client, Session, Tools, and Hooks Explained

> Explore the GitHub Copilot SDK core components: Client for CLI management, Session for conversation state, Tools for functions, and Hooks for execution flow. Understand the architecture.

- Repository: [GitHub/copilot-sdk](https://github.com/github/copilot-sdk)
- Tags: deep-dive
- Published: 2026-07-18

---

**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`](https://github.com/github/copilot-sdk/blob/main/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`](https://github.com/github/copilot-sdk/blob/main/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 `MessageConnection` to the subprocess
- Maintaining a `Map<string, ToolHandler>` called `toolHandlers` for 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`](https://github.com/github/copilot-sdk/blob/main/nodejs/src/toolSet.ts).

Key types include:

- `Tool` and `ToolHandler` interfaces for defining tool contracts
- `ToolSet` for collecting multiple tools
- `defineTool` helper 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`](https://github.com/github/copilot-sdk/blob/main/nodejs/src/types.ts) (lines 1481-1528) and includes handlers such as `onPreToolUse`, `onPostToolUse`, and `onPostToolUseFailure`.

Hook capabilities include:

- **Pre-execution interception**: `onPreToolUse` handlers can inspect or modify arguments, or abort execution by throwing
- **Post-execution handling**: `onPostToolUse` receives results for logging or transformation
- **Failure recovery**: `onPostToolUseFailure` enables custom retry logic (e.g., returning `{ retryCount: 1 }`)
- **Lifecycle management**: `onSessionStart` and `onSessionEnd` track 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**.

1. **Initialization**: `CopilotClient.createSession()` (or `resumeSession`) spawns the subprocess, creates the `MessageConnection`, and instantiates `CopilotSession`
2. **Registration**: The session accepts an optional `SessionHooks` object via `registerHooks` (defined in [`nodejs/src/session.ts`](https://github.com/github/copilot-sdk/blob/main/nodejs/src/session.ts), lines 1153-1157) and maintains the `toolHandlers` map for routing
3. **Execution**: When the model invokes a tool, the session looks up the handler, then sequentially triggers `onPreToolUse`, the tool handler itself, and either `onPostToolUse` or `onPostToolUseFailure`
4. **RPC Bridging**: The client exposes `hooks.invoke` for forwarding hook-related JSON-RPC calls to the session's dispatcher

## Implementation Examples

### Creating a Client and Session with Custom Hooks

```typescript
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

```typescript
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

```typescript
const hooks = {
  onPreToolUse: async ({ toolName, args }) => {
    if (toolName === "weather") {
      // Normalize city names
      args.city = args.city.trim().toLowerCase();
    }
  },
};

```

## Summary

- **Client ([`nodejs/src/client.ts`](https://github.com/github/copilot-sdk/blob/main/nodejs/src/client.ts))**: Entry point that manages the Copilot CLI subprocess lifecycle and RPC protocol negotiation via `CopilotClient`
- **Session ([`nodejs/src/session.ts`](https://github.com/github/copilot-sdk/blob/main/nodejs/src/session.ts))**: Maintains conversation state, JSON-RPC connection, and registries for tools (`toolHandlers` Map) and hooks
- **Tools ([`nodejs/src/toolSet.ts`](https://github.com/github/copilot-sdk/blob/main/nodejs/src/toolSet.ts))**: Model-callable functions defined via `Tool` and `ToolHandler` interfaces, registered through `ToolSet` with optional built-in overrides
- **Hooks ([`nodejs/src/types.ts`](https://github.com/github/copilot-sdk/blob/main/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`](https://github.com/github/copilot-sdk/blob/main/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`](https://github.com/github/copilot-sdk/blob/main/nodejs/src/client.ts), the client handles `createSession()` and `resumeSession()` calls, returning distinct `CopilotSession` instances defined in [`nodejs/src/session.ts`](https://github.com/github/copilot-sdk/blob/main/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`](https://github.com/github/copilot-sdk/blob/main/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.