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

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 or a top-level 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:

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.)

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":

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:

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 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 (specifically CustomAgentConfig), while the SDK client code in 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:

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 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 or 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 (interfaces), nodejs/src/client.ts (configuration), and 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 or 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 within the github/copilot-sdk repository. The SDK client implementation in nodejs/src/client.ts handles the construction of request payloads including customAgentsLocalOnly logic, while nodejs/src/session.ts manages the runtime wiring of these configurations.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →