# Copilot SDK Plugin Directories and Custom Agent Types: A Complete Guide

> Unlock Copilot SDK capabilities by mastering plugin directories and custom agent types. Extend runtime features and build isolated sub-agents for advanced fleet mode execution.

- Repository: [GitHub/copilot-sdk](https://github.com/github/copilot-sdk)
- Tags: how-to-guide
- Published: 2026-08-02

---

**The Copilot SDK enables host applications to extend runtime capabilities by loading plugin directories via the `--plugin-dir` flag and defining custom agent types with isolated tool sets and system prompts that execute as sub-agents in fleet mode.**

The github/copilot-sdk repository provides a flexible framework for building AI-augmented development tools. Understanding how to leverage **Copilot SDK plugin directories and custom agent types** allows developers to create deterministic, extensible workflows that bundle skills, hooks, MCP servers, and specialized AI agents into cohesive capability packs.

## Understanding Plugin Directories

A **plugin directory** is a folder that bundles one or more SDK extensions—including skills, hooks, MCP servers, custom agents, and optional LSP configuration—behind a single manifest ([`plugin.json`](https://github.com/github/copilot-sdk/blob/main/plugin.json) or a top-level [`SKILL.md`](https://github.com/github/copilot-sdk/blob/main/SKILL.md)). When the SDK starts the Copilot CLI with the `--plugin-dir` flag, the runtime scans each supplied directory, loads the manifest, and registers every contribution it finds.

Plugin contributions appear in session APIs such as `session.skills.list()` and `session.rpc.plugins.list()`, and are selectable as sub-agents in fleet mode.

### Loading Plugin Directories via the CLI

The SDK forwards the `--plugin-dir` flag to the CLI when it spawns the runtime. In Node.js, instantiate the client with `RuntimeConnection.forStdio()` and pass the directory paths:

```typescript
import { CopilotClient, RuntimeConnection } from "@github/copilot-sdk";

const client = new CopilotClient({
  connection: RuntimeConnection.forStdio({
    args: ["--plugin-dir", "./plugins/code-reviewer", "--plugin-dir", "./plugins/lint-fix"],
  }),
});
await client.start();

```

(See the full example in the plugin-directory docs [here](https://github.com/github/copilot-sdk/blob/main/docs/features/plugin-directories.md).)

### Deterministic Plugin Sets

**Marketplace plugins** are *ambient*, meaning they load for every session automatically, whereas `--plugin-dir` plugins are *ephemeral* and take precedence over ambient ones. To ensure a deterministic plugin set and disable ambient discovery, set the `COPILOT_PLUGIN_DIR_ONLY` environment variable to `"true"`:

```typescript
process.env.COPILOT_PLUGIN_DIR_ONLY = "true";
const client = new CopilotClient({
  connection: RuntimeConnection.forStdio({ args: ["--plugin-dir", "./plugins/code-reviewer"] }),
});
await client.start();

```

This configuration ensures only explicitly loaded plugins from the specified directory are active, preventing marketplace interference.

### Inspecting Loaded Plugins

After creating a session, enumerate active plugins to verify which extensions are registered:

```typescript
const plugins = await session.rpc.plugins.list();
plugins.plugins.forEach(p => console.log(`${p.name} (${p.enabled ? "enabled" : "disabled"})`));

```

For a full manifest schema and loading details, see [`docs/features/plugin-directories.md`](https://github.com/github/copilot-sdk/blob/main/docs/features/plugin-directories.md) in the github/copilot-sdk repository.

## Defining Custom Agent Types

A **custom agent** is a lightweight definition attached to a session that supplies its own system prompt, optional description, a limited tool set, and optional per-agent MCP servers. When a user's request matches an agent's description, the runtime automatically delegates work to that agent as a **sub-agent**, executing it in an isolated context while streaming lifecycle events (`subagent.started`, `subagent.completed`, etc.) back to the parent session.

### Custom Agent Configuration Schema

Key properties of a custom agent, defined in the session config, include:

- **name** (`string`, required): Unique identifier used for selection.
- **displayName** (`string`): Human-readable name shown in UI events.
- **description** (`string`): Helps the runtime match intent; keep it specific.
- **tools** (`string[]`): Whitelist of tools the agent may use (`null` = all).
- **prompt** (`string`, required): System prompt that shapes the agent's behavior.
- **mcpServers** (`object`): Agent-scoped MCP server definitions.
- **infer** (`boolean`): `true` (default) enables automatic selection; set `false` to require explicit invocation.
- **skills** (`string[]`): Pre-load skill content into the agent's context at startup.
- **model** / **reasoningEffort** (`string`): Override the parent session's model or effort for this agent.

The TypeScript interfaces for these configurations are defined in [`nodejs/src/types.ts`](https://github.com/github/copilot-sdk/blob/main/nodejs/src/types.ts) (specifically `CustomAgentConfig`), while the SDK client code in [`nodejs/src/client.ts`](https://github.com/github/copilot-sdk/blob/main/nodejs/src/client.ts) handles the `customAgentsLocalOnly` parameter and plugin argument construction.

### Registering Custom Agents in Sessions

Define custom agents during session creation via the `customAgents` array:

```typescript
import { CopilotClient } from "@github/copilot-sdk";

const client = new CopilotClient();
await client.start();

const session = await client.createSession({
  model: "gpt-5.4",
  customAgents: [
    {
      name: "researcher",
      displayName: "Research Agent",
      description: "Explores codebases using read-only tools",
      tools: ["grep", "glob", "view"],
      prompt: "You are a research assistant. Analyze code and answer questions. Do not modify any files.",
    },
    {
      name: "editor",
      displayName: "Editor Agent",
      description: "Makes targeted code changes",
      tools: ["view", "edit", "bash"],
      prompt: "You are a code editor. Make minimal, surgical changes to files as requested.",
    },
  ],
  onPermissionRequest: async () => ({ kind: "approve-once" }),
});

```

### Custom Agents as Sub-Agents

Custom agents become **sub-agents** when the runtime selects them based on their description, or when invoked explicitly via the `task(agent_type=…)` tool. They execute in isolated contexts and fire the same sub-agent lifecycle hooks as any other sub-agent, enabling fine-grained orchestration in *fleet mode*.

The runtime session implementation in [`nodejs/src/session.ts`](https://github.com/github/copilot-sdk/blob/main/nodejs/src/session.ts) wires plugin contributions and handles sub-agent orchestration, ensuring that both SDK-defined agents and plugin-provided agents receive consistent lifecycle event streaming.

## Integration Between Plugins and Custom Agents

The Copilot SDK architecture allows seamless interaction between plugin directories and custom agent types:

- **Plugins can contribute agents** via the `agents/` folder; these agents are then available as sub-agents without any extra SDK code.
- **Plugin-provided agents** participate in fleet-mode dispatching, receiving the same lifecycle events as SDK-defined agents.
- The runtime merges plugin-provided extensions with inline registrations passed via SDK configuration, creating a unified capability surface.

This architecture enables sophisticated workflows where a plugin directory might bundle a "TypeScript reviewer" capability that includes both a custom agent definition and accompanying skills, while the host application can still define additional custom agents programmatically.

## Summary

- **Plugin directories** bundle extensions (skills, hooks, agents, MCP servers) behind a [`plugin.json`](https://github.com/github/copilot-sdk/blob/main/plugin.json) or [`SKILL.md`](https://github.com/github/copilot-sdk/blob/main/SKILL.md) manifest, loaded via the `--plugin-dir` CLI flag.
- Set `COPILOT_PLUGIN_DIR_ONLY=true` to disable ambient marketplace plugins and ensure deterministic loading.
- **Custom agents** define isolated AI workers with specific tools, prompts, and MCP servers, configured via the `customAgents` array in session creation.
- Custom agents execute as **sub-agents** in fleet mode, streaming lifecycle events back to the parent session.
- Plugins can contribute agents through an `agents/` folder, integrating seamlessly with programmatically defined custom agents.
- Key implementation files include [`nodejs/src/types.ts`](https://github.com/github/copilot-sdk/blob/main/nodejs/src/types.ts) (interfaces), [`nodejs/src/client.ts`](https://github.com/github/copilot-sdk/blob/main/nodejs/src/client.ts) (configuration), and [`nodejs/src/session.ts`](https://github.com/github/copilot-sdk/blob/main/nodejs/src/session.ts) (orchestration).

## Frequently Asked Questions

### How do I load a local plugin directory in Copilot SDK?

Pass the `--plugin-dir` flag through `RuntimeConnection.forStdio()` when instantiating `CopilotClient`. The SDK forwards this flag to the CLI runtime, which scans the directory for [`plugin.json`](https://github.com/github/copilot-sdk/blob/main/plugin.json) or [`SKILL.md`](https://github.com/github/copilot-sdk/blob/main/SKILL.md) manifests and registers all discovered contributions. You can specify multiple directories by repeating the flag.

### What is the difference between ambient and ephemeral plugins?

**Ambient plugins** are marketplace extensions loaded automatically for every session. **Ephemeral plugins** are those loaded explicitly via `--plugin-dir` flags. Ephemeral plugins take precedence over ambient ones, and setting `COPILOT_PLUGIN_DIR_ONLY=true` disables ambient discovery entirely, ensuring only your specified plugins are active.

### How do I prevent automatic agent selection in Copilot SDK?

Set the `infer` property to `false` in your `CustomAgentConfig` definition. When `infer` is `false`, the runtime will not automatically delegate requests to that agent based on description matching; instead, the agent must be invoked explicitly via the `task(agent_type=…)` tool or direct SDK calls.

### Where are the TypeScript interfaces for custom agents defined?

The `CustomAgentConfig` interface and related session options are defined in [`nodejs/src/types.ts`](https://github.com/github/copilot-sdk/blob/main/nodejs/src/types.ts) within the github/copilot-sdk repository. The SDK client implementation in [`nodejs/src/client.ts`](https://github.com/github/copilot-sdk/blob/main/nodejs/src/client.ts) handles the construction of request payloads including `customAgentsLocalOnly` logic, while [`nodejs/src/session.ts`](https://github.com/github/copilot-sdk/blob/main/nodejs/src/session.ts) manages the runtime wiring of these configurations.