# Custom Agents vs Sub-Agent Orchestration Patterns in the Copilot SDK

> Explore custom agents vs sub-agent orchestration in Copilot SDK. Understand static definitions versus dynamic runtime behavior for agent management and execution.

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

---

**Custom agents are static configuration definitions that you declare at session creation, while sub-agent orchestration is the dynamic runtime behavior that selects, launches, and manages their execution within a parent session.**

When building complex AI workflows with the GitHub Copilot SDK, understanding the distinction between agent definitions and their execution model is critical for designing scalable applications. Custom agents serve as reusable building blocks configured in your session setup, whereas sub-agent orchestration represents the runtime intelligence—defined in [`docs/features/custom-agents.md`](https://github.com/github/copilot-sdk/blob/main/docs/features/custom-agents.md)—that determines which agent runs, when it activates, and how its results integrate back into the conversation.

## What Are Custom Agents?

**Custom agents** are static configurations that you attach to a session via the `customAgents` array. Each agent carries its own system prompt, an optional list of allowed tools, optional MCP servers, and per-agent settings such as `infer`, `model`, or `reasoningEffort`. According to the Copilot SDK source code, these definitions act as candidate sub-agents that the runtime may later invoke based on user intent or explicit requests.

In [`docs/features/custom-agents.md`](https://github.com/github/copilot-sdk/blob/main/docs/features/custom-agents.md), custom agents are declared at session initialization and remain visible in `sessionConfig.customAgents` throughout the session lifetime. They do not execute on their own; they serve strictly as metadata-rich definitions that describe capabilities, constraints, and behavioral instructions.

```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: "Read-only exploration of the codebase",
      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" }),
});

```

## What Is Sub-Agent Orchestration?

**Sub-agent orchestration** is the runtime behavior that decides *when* and *how* a custom agent is actually executed. As implemented in `github/copilot-sdk`, the runtime performs inference when a user's intent matches an agent's `description` and the `infer` property is not explicitly set to `false`.

The orchestration layer manages the full lifecycle of agent execution, running each sub-agent in an isolated context with its own prompt and restricted tool set. The parent session receives streamed events that UI layers can render, providing visibility into which agent was selected and its current state.

### Sub-Agent Event Lifecycle

When the runtime selects and executes a custom agent, it emits a sequence of lifecycle events that the parent session can observe:

```typescript
session.on((event) => {
  switch (event.type) {
    case "subagent.selected":
      console.log(`🧭 Selected ${event.data.agentDisplayName}`);
      break;
    case "subagent.started":
      console.log(`▶️ Started ${event.data.agentDisplayName}`);
      break;
    case "subagent.completed":
      console.log(`✅ Completed ${event.data.agentDisplayName}`);
      break;
    case "subagent.failed":
      console.error(`❌ Failed ${event.data.agentDisplayName}: ${event.data.error}`);
      break;
  }
});

await session.sendAndWait({ prompt: "Explain the authentication flow in this repo" });

```

### Parallel Execution with Fleet Mode

For truly parallel sub-agent orchestration, the SDK provides **Fleet mode**, detailed in [`docs/features/fleet-mode.md`](https://github.com/github/copilot-sdk/blob/main/docs/features/fleet-mode.md). This pattern dispatches multiple sub-agents concurrently using the `task` tool and a shared SQL-based todo coordination model, allowing independent units of work to execute simultaneously.

```typescript
const result = await session.rpc.fleet.start({
  prompt: "Refactor each SDK package independently, then summarize the changes.",
});
if (result.started) {
  console.log("🚀 Fleet mode launched");
}

```

## Key Differences Between Configuration and Runtime

Drawing from [`docs/features/custom-agents.md`](https://github.com/github/copilot-sdk/blob/main/docs/features/custom-agents.md) and [`docs/features/fleet-mode.md`](https://github.com/github/copilot-sdk/blob/main/docs/features/fleet-mode.md), the distinction between these concepts breaks down across several dimensions:

- **Purpose**: Custom agents provide *static definitions* (name, prompt, tool set, description) that can be selected later. Sub-agent orchestration *dynamically selects, launches, and manages* the execution of these agents based on user intent or explicit tool calls.
- **Creation**: Agents are declared in the `customAgents` array at session creation time. Orchestration triggers automatically when intent matches description, or when explicitly invoked via the `session.rpc.fleet.start` API.
- **Execution Context**: Custom agents exist only as metadata with no execution context. Sub-agent orchestration runs agents in isolated contexts with restricted tool sets and emits lifecycle events (`subagent.started`, `subagent.completed`, etc.).
- **Parallelism**: Individual custom agents are not inherently parallel; each may be invoked multiple times sequentially. Fleet mode enables true parallelism by dispatching many sub-agents concurrently with coordination via the SQL-based todo model.
- **Control**: Developers adjust custom agents via properties like `tools`, `infer`, `model`, and `skills`. They control orchestration through runtime events, explicit selections, or by disabling inference (`infer: false`) to require explicit user requests.

## Disabling Automatic Agent Selection

You can prevent the runtime from automatically selecting a specific agent by setting `infer: false` in the configuration. This forces explicit invocation, ensuring the agent only runs when the user specifically requests it or when called via a tool.

```typescript
{
  name: "dangerous-cleanup",
  description: "Deletes unused files and dead code",
  tools: ["bash", "edit", "view"],
  prompt: "You clean up codebases by removing dead code and unused files.",
  infer: false, // Must be called explicitly
}

```

Even when handling parallel workloads in Fleet mode, the same event stream tracks each sub-agent's progress:

```python
def handle(event):
    if event.type == "subagent.started":
        print(f"▶ {event.data.agent_display_name} started")
    elif event.type == "subagent.completed":
        print(f"✅ {event.data.agent_display_name} finished")

session.on(handle)

```

## Summary

- **Custom agents** are static definitions configured in the `customAgents` array of your session configuration, specifying prompts, tool sets, and metadata.
- **Sub-agent orchestration** is the dynamic runtime logic—implemented in [`docs/features/custom-agents.md`](https://github.com/github/copilot-sdk/blob/main/docs/features/custom-agents.md)—that selects and executes agents based on inference or explicit calls.
- The runtime emits lifecycle events (`subagent.selected`, `subagent.started`, `subagent.completed`, `subagent.failed`) that parent sessions observe to track execution.
- **Fleet mode**, documented in [`docs/features/fleet-mode.md`](https://github.com/github/copilot-sdk/blob/main/docs/features/fleet-mode.md), enables parallel sub-agent orchestration using `session.rpc.fleet.start` and SQL-based coordination.
- Setting `infer: false` forces explicit agent invocation, bypassing automatic intent matching while maintaining the agent's availability for direct requests.

## Frequently Asked Questions

### How do I prevent the Copilot SDK from automatically selecting a custom agent?

Set the `infer` property to `false` in your agent configuration within the `customAgents` array. According to [`docs/features/custom-agents.md`](https://github.com/github/copilot-sdk/blob/main/docs/features/custom-agents.md), this prevents the runtime from matching user intent against the agent's description, requiring either explicit user requests or programmatic tool calls to invoke the agent.

### What events indicate that a sub-agent has started or completed its work?

The runtime emits `subagent.selected` when inference chooses an agent, `subagent.started` when execution begins, and either `subagent.completed` upon success or `subagent.failed` if an error occurs. These events are streamed to the parent session and can be handled via the `session.on()` event listener as shown in the Node.js and Python examples above.

### Can custom agents run in parallel, and how is this coordinated?

Yes, through **Fleet mode**, a specialized sub-agent orchestration pattern detailed in [`docs/features/fleet-mode.md`](https://github.com/github/copilot-sdk/blob/main/docs/features/fleet-mode.md). You initiate parallel execution by calling `session.rpc.fleet.start()`, which dispatches multiple sub-agents concurrently using the `task` tool and coordinates their work through a shared SQL-based todo model, aggregating results back into the parent session.

### Where are custom agent definitions stored versus orchestration logic?

Agent definitions reside in your session configuration's `customAgents` array and are documented in [`docs/features/custom-agents.md`](https://github.com/github/copilot-sdk/blob/main/docs/features/custom-agents.md). The orchestration logic—the algorithms for selection, lifecycle management, and parallel coordination—is implemented in the SDK runtime and documented across [`docs/features/custom-agents.md`](https://github.com/github/copilot-sdk/blob/main/docs/features/custom-agents.md) (for sequential orchestration) and [`docs/features/fleet-mode.md`](https://github.com/github/copilot-sdk/blob/main/docs/features/fleet-mode.md) (for parallel execution), with RPC bindings available in language-specific sources like `go/rpc/fleet.proto`.