Post

Building Custom Agents in GitHub Copilot

Building Custom Agents in GitHub Copilot

A single Copilot agent doing everything drowns in its own context after forty turns. Custom agents fix this by splitting work across specialized agents — each starting fresh with only the context it needs. This post shows how to build custom GitHub Copilot agents using plain Markdown files, from simple reviewers to multi-agent orchestration across VS Code, CLI, and Cloud.

Edit (2026-08-02):

  • Updated the CLI: building squads with the task tool section. Since v1.0.19, task(agent_type="<name>", prompt="…") can dispatch to other custom agents, not just built-ins — the CLI supports the same orchestrator + independent specialist files pattern as VS Code, with per-agent tools: and user-invocable: false for hidden specialists.
  • Clarified the model: frontmatter split: VS Code custom agents accept a fallback-chain array of qualified model names, while the Copilot CLI documents model: as a single string. On CLI, resilience comes from the per-user ~/.copilot/settings.jsonsubagents.agents.<name>.model override, not from an inline chain.

The problem: one agent doing everything

Picture a typical Copilot session. You ask it to add a feature. The agent searches your codebase, reads files, makes edits, runs tests, hits an error, backtracks, searches again. Forty turns in, the conversation is bloated with abandoned paths, irrelevant code snippets, and stale context.

The model starts producing worse output — not because it’s less capable, but because it’s drowning in accumulated context. Your token budget is being spent re-reading noise from twenty turns ago rather than focusing on the current step.

Now imagine the same task split across two agents. A Planner researches the codebase and writes a concise plan. Then an Implementer — starting with a fresh, clean context — reads only that plan and the relevant files, then codes the solution. Each agent sees only what it needs. No pollution from the other’s work.

That’s the core idea behind custom agents: separation of concerns at the AI layer, the same discipline we already apply to our code.

Your first custom agent

Every custom agent is a Markdown file: YAML frontmatter declaring capabilities, followed by a body that serves as the system prompt. No SDK, no build step, no deployment.

Step 1: Create the file

Create a file at .github/agents/security-reviewer.agent.md in your repository:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
description: Reviews code for security vulnerabilities using OWASP Top 10 guidelines.
target: vscode
model:
  - Claude Sonnet 4.6 (copilot)   # primary — strong at code review
  - GPT-5.4 (copilot)             # cross-family fallback
tools: ['read', 'search']
---

You are a security reviewer. For every file presented, identify potential vulnerabilities
following the OWASP Top 10 taxonomy. Report findings in a structured table with severity,
location, and remediation guidance.

Do NOT modify files. Report only.

Four things are happening here:

  • description tells the runtime (and other agents) when to invoke this agent.
  • target scopes which runtime lists this agent. vscode restricts it to the VS Code Agents dropdown; github-copilot restricts it to the Copilot CLI and cloud. Omit target (or leave it unset) and the agent appears in every runtime that can read the file. This is how you keep VS Code-only agents (those using vscode/memory, handoffs, or the agent tool) out of the CLI picker, and vice versa.
  • tools restricts what it can access — this reviewer can read and search, but cannot edit files or run commands.
  • The body is the system prompt — its personality, instructions, and constraints.

Step 2: Invoke it

In VS Code, open the Chat panel and select your agent from the Agents dropdown (it appears automatically once the file exists in your workspace). Then type your request:

Review the authentication middleware in src/auth/ for security vulnerabilities.

In the CLI, use @security-reviewer inline in your prompt, the /agent security-reviewer command, or the --agent security-reviewer flag.

Step 3: Verify it loaded

If the agent doesn’t appear in VS Code’s dropdown:

  • Confirm the file is in .github/agents/, ~/.copilot/agents/, or another recognized path.
  • Confirm the filename ends in .agent.md.
  • Check that the YAML frontmatter is valid (no tabs, proper indentation).

That’s it. You have a reusable, version-controlled, team-shareable agent that anyone on the project gets on git pull.

Why this beats a prompt

You could paste those same instructions into a chat message every time. But:

  • Every team member would need their own copy.
  • You’d waste tokens sending the instructions on every request.
  • You couldn’t restrict tool access — the model could still edit files.
  • Changes wouldn’t propagate automatically.

Custom agents solve all of this. They’re infrastructure, not prompts.

Why custom agents matter for token efficiency

If you read the token usage post, you know that context size is the main cost driver in agent sessions. Custom agents directly address this:

  • Fresh context per task. Each agent starts clean with only what it needs. No pollution from earlier conversation turns.
  • Right model, right job. Pin Claude Sonnet 4.6 on the Planner for deep codebase comprehension and on the Implementer for tool-use quality; drop to GPT-5.3-Codex only when a role is pure large-volume code generation. Match the model to the role, not the other way around.
  • Tool isolation. A read-only planner cannot accidentally modify files. Fewer tools in context means less noise for the model.
  • Encode knowledge once. Domain expertise lives in the agent definition, loaded automatically — you don’t re-send it on every message.

One cost tradeoff to keep in mind: splitting work across multiple agents means more total LLM interactions than a monolithic session — each agent starts its own conversation with the model. The tradeoff is usually worth it — fresh context per agent produces higher-quality output with fewer hallucinations, and parallelization cuts wall-clock time — but it’s a conscious cost decision. Multi-agent architectures trade token efficiency per-request for better results overall. The overhead can also be offset by applying the token-saving tools and context engineering techniques covered in the first post of this series — RTK-AI, Graphify, Caveman, and LSP keep each agent’s context lean, which directly reduces the cost per interaction.

The three runtimes

GitHub Copilot supports custom agents across three surfaces: VS Code, the Copilot CLI, and Cloud. They share the .agent.md file format and accept agent files from .github/agents/ or ~/.copilot/agents/. VS Code also recognizes .md files in .claude/agents/ following the Claude sub-agents format, making it possible to share agent definitions with Claude Code.

Beyond file format, the runtimes still differ in how they coordinate multiple agents — in what’s built in, how routing decisions are made, and which coordination primitives (allowlists, handoffs, plan mode, /fleet) are available.

VS Code: explicit orchestration

VS Code gives you precise control over multi-agent coordination through:

  • An agents: allowlist in frontmatter that declares which subagents an agent may invoke.
  • Visibility controls (user-invocable, disable-model-invocation) that lock down who can call whom.
  • The agent tool for dispatching subagents programmatically.
  • Handoffs for human-in-the-loop transitions between agents.
  • Platform-specific tools like vscode/memory (persistent memory) and vscode/askQuestions (structured user interaction).

VS Code also ships with built-in agents that are always available:

AgentUser-invocableWhat it does
AgentyesAutonomously plans and implements changes across files, runs terminal commands, and invokes tools
PlanyesCreates a structured, step-by-step implementation plan before writing any code; hands the plan off to an implementation agent when ready
AskyesAnswers questions about coding concepts, your codebase, or VS Code itself without making file changes
Exploreno (subagent only)Fast read-only codebase exploration and Q&A — runs in a separate context to avoid bloating the main conversation; safe to call in parallel

CLI: autonomous delegation (and explicit orchestration)

The CLI defaults to a lighter-touch style: rather than requiring an orchestrator, the CLI model can autonomously decide when to delegate — reading each agent’s description field and routing accordingly.

This means the description field does double duty: it tells humans what the agent does and tells the model when to invoke it. Vague descriptions like “Backend developer” won’t trigger delegation. Be specific about scope and triggers.

You can also invoke agents explicitly: @agentName inline in your prompt, the /agent slash command, or the --agent CLI flag.

And since v1.0.19 the CLI supports the same orchestrator pattern as VS Code — a custom agent can dispatch to other custom agents through the task tool (see CLI: building squads with the task tool below). So the CLI covers both ends: implicit routing based on descriptions and explicit orchestrator agents with their own tool restrictions.

One caveat that shapes the sections below: the CLI does not implement the agents: allowlist property in frontmatter. There is no way to declare “only this orchestrator may invoke this specialist,” which also means disable-model-invocation: true has nothing to grant an exception to — on the CLI it effectively removes the agent from model invocation across the board. The workarounds (per-file tools: lists and user-invocable: false to hide specialists from the picker) are covered below.

When to use which approach: Use autonomous delegation (good descriptions, let the model route) for simple projects with a handful of agents. Define an explicit orchestrator agent when you need deterministic sequencing — when the order of operations matters and you can’t leave routing decisions to the model’s judgment.

The CLI ships with built-in specialist agents it uses automatically:

AgentWhat it does
ExploreQuick codebase analysis without bloating the main context
TaskRuns commands (tests, builds); brief summaries on success, full output on failure
General PurposeHandles complex, multi-step tasks requiring the full toolset; runs in a separate context
Code ReviewReviews changes, focuses on genuine issues, minimizes noise
ResearchDeep research across codebase and web; produces reports with citations
Rubber DuckConstructive critic on non-trivial tasks; invoked automatically

The CLI also provides the /fleet command — a built-in way to parallelize work without writing an orchestrator yourself. When you prefix a prompt with /fleet, Copilot analyzes the request, decomposes it into independent subtasks, and dispatches subagents to execute them in parallel. Each subagent gets its own fresh context window, preventing the bloat problem we discussed in the token usage post.

A typical /fleet workflow:

  1. Press Shift+Tab to enter plan mode and collaborate on an implementation plan.
  2. Once the plan is complete, select Accept plan and build on autopilot + /fleet.
  3. Copilot decomposes the plan into parallelizable subtasks and assigns subagents.
  4. If you have custom agents, Copilot will route subtasks to the most appropriate one — or you can force it with @agent-name in your prompt.

/fleet is ideal for tasks that decompose naturally: creating a test suite for multiple modules, refactoring several independent files, or updating dependencies across packages. It’s less useful for inherently sequential work where each step depends on the previous one.

The key tradeoff: /fleet is an ad-hoc command, not infrastructure committed to your repository. Unlike a custom orchestrator agent (which lives in .github/agents/, evolves with the codebase, and is shared via git pull), /fleet decomposition is ephemeral — the model decides how to split work on each invocation, and that logic isn’t reproducible or reviewable by your team. For well-understood workflows that you want to run consistently, a committed orchestrator agent is the more disciplined choice; /fleet shines for exploratory or one-off parallelization.

Cloud: fire-and-forget autonomous execution

Cloud agents run on remote infrastructure, working autonomously without real-time interaction. You assign a task and walk away. Their natural output is a pull request.

The tradeoffs:

  • No local tools. They can’t see your VS Code selections, terminal output, or local file system. Limited to cloud-configured MCP servers.
  • Asynchronous. Progress appears in VS Code’s Chat view or on GitHub.com.
  • Custom agent support. You can select a custom agent when starting a cloud session, giving the remote agent your specialized instructions — but multi-agent coordination (subagents, squads) is not available.

You can start a cloud session through several entry points:

  • VS Code: New Chat → Cloud, or the Agents window.
  • MCP clients: any IDE or agentic tool that supports MCP via the GitHub MCP server (Use Cloud Agent with MCP).
  • CLI handoff: a local session using the /delegate command.
  • GitHub.com repository UI: the Agents tab or assign an issue/PR to the Copilot cloud agent.

The handoff pattern is powerful: use a local Plan agent to interactively clarify requirements, then hand off to a cloud agent for autonomous implementation. The cloud agent receives the entire conversation history as context.

Platform comparison

Now that you’ve seen each runtime in action, here’s the full comparison:

FeatureVS CodeCLICloud
Multi-agent coordinationOrchestrator pattern + handoffsExplicit + autonomous delegationSingle agent per session
Subagent invocationagent/runSubagent tool + agents: allowlisttask tool, /agent command, /fleet, or auto-delegationNot available
Memory handoffvscode/memory toolFile systemPR context + repository
User interactionvscode/askQuestions toolask_user toolAsynchronous (PR comments)
Terminal/shell executionexecute/runInTerminal toolShell commands via tool approvalSandboxed environment
Skill loadingAutomatic (from multiple paths)Loaded when task matches descriptionNot available
Model pinningmodel: frontmatter (single string or fallback-chain array)model: frontmatter (single string per CLI reference) or --model flagSelected at session start
MCP tools<server>/* tool pattern<server>/* tool patternCloud-configured MCP servers only
Visibility controluser-invocable + disable-model-invocation + agents: allowlistuser-invocable + disable-model-invocation (no agents: allowlist)N/A
Organization sharing.github-private repo.github-private repo.github-private repo
Execution environmentLocal machineLocal machineRemote infrastructure

Building a two-agent workflow (VS Code)

Let’s build something practical: a Planner that researches and writes a plan, followed by an Implementer that codes the solution. This is the simplest useful multi-agent setup.

The Planner

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
---
name: Planner
description: Researches the codebase and writes a concrete implementation plan.
target: vscode
model:
  - Claude Sonnet 4.6 (copilot)   # primary — deep comprehension for plan synthesis
  - GPT-5.4 (copilot)             # cross-family fallback
tools: ['search', 'read', 'vscode/memory']
handoffs:
  - label: Start Implementation
    agent: Implementer
    prompt: Implement the plan in /memories/session/plan.md
    send: false
---

You are the Planner. Your job is to research the codebase and produce a plan.

## Protocol
1. Understand the user's request
2. Explore relevant files using search and read
3. Write your plan to `/memories/session/plan.md`
4. Never write production code — only the plan

The Implementer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
---
name: Implementer
description: Implements code changes following a plan written by the Planner.
target: vscode
model:
  - Claude Sonnet 4.6 (copilot)   # primary — strong tool use and code reasoning
  - GPT-5.3-Codex (copilot)       # cross-family last resort — code-tuned for large boilerplate
tools: ['search', 'read', 'edit', 'run_in_terminal', 'vscode/memory']
---

You are the Implementer. Follow the plan exactly.

## Protocol
1. Read the plan from `/memories/session/plan.md`
2. Implement each step
3. Run tests after changes
4. Report completion

Both roles pin Claude Sonnet 4.6 as the primary — the Planner leans on its deep comprehension for plan synthesis, the Implementer on its tool-use quality and code reasoning during the edit/test loop. GPT-5.3-Codex only appears as the Implementer’s cross-family last resort — the house rule reserves it for cases where large-volume boilerplate is the dominant output.

The handoffs: property on the Planner creates a button that appears after the plan is generated. Click it to switch to the Implementer with a pre-filled prompt. Since send: false, you get to review the prompt before it submits — a human checkpoint in the pipeline.

Visibility controls explained

By default, any agent can invoke any other agent in VS Code. The visibility controls let you lock this down:

  • user-invocable: false — the developer cannot select this agent from the dropdown; only other agents can invoke it.
  • disable-model-invocation: true — no agent can invoke this one unless it explicitly lists it in its agents: allowlist.

When combined, these create a strict hierarchy: only agents that declare a specific subagent in their agents: array can call it. This prevents accidental invocations and makes the coordination graph explicit and auditable.

In VS Code, the model: field also accepts a prioritized array (fallback chain) — the runtime tries each entry in order until an available one is found, so a rate limit, preview instability, or provider outage falls through to the next model instead of failing the run. One constraint: a subagent’s requested model cannot exceed the cost tier of the main model; if it does, the subagent falls back to the main model. The Copilot CLI documents model: as a single string — arrays are undocumented and may be flagged by strict validators; on CLI, add resilience through ~/.copilot/settings.jsonsubagents.agents.<name>.model instead.

Handoffs vs. subagents: choosing the right coordination

You now have two ways to connect agents:

Handoffs insert a human checkpoint between steps. After one agent finishes, a button appears. You review the output, optionally edit the pre-filled prompt, then click to continue. Use handoffs when:

  • The intermediate output needs human review (plans, architectural decisions).
  • You want to abort early if the plan is wrong.
  • The workflow is high-stakes or unfamiliar.

Subagent orchestration is fully autonomous. An Orchestrator agent dispatches subagents via the agent tool without pausing. Use subagents when:

  • The workflow is repetitive and well-understood.
  • You trust the pipeline and don’t need to inspect intermediate steps.
  • Speed matters more than oversight.

To define handoffs, add them to the agent’s frontmatter:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---
description: Generate an implementation plan
target: vscode
tools: ['search', 'read']
model:
  - Claude Sonnet 4.6 (copilot)   # primary — deep comprehension for plan synthesis
  - GPT-5.4 (copilot)             # cross-family fallback
handoffs:
  - label: Start Implementation
    agent: implementation
    prompt: Now implement the plan outlined above.
    send: false
---

You are a planning agent. Research the codebase and produce a step-by-step plan.

When send: true, the prompt auto-submits without confirmation. The optional model field switches models at the transition point.

Squads: orchestrated teams (VS Code)

Once you’re comfortable with two-agent workflows, you can scale up to full squads — coordinated teams with an Orchestrator as the single entry point.

flowchart TD
    User([User]) --> Orch[Orchestrator]
    Orch --> Planner
    Orch --> Backend[Backend Dev]
    Orch --> Reviewer[Code Reviewer]
    Planner -- writes plan --> Memory[(Session Memory)]
    Backend -- reads plan --> Memory

Each role has a clear responsibility. The Orchestrator routes tasks but never edits files. The Planner researches but never writes production code. Specialists implement. Code Reviewers critique.

Naming convention

To avoid naming clashes when a project has multiple squads, all agents in a squad share a short prefix:

  • mod-Orchestrator.agent.md
  • mod-Planner.agent.md
  • mod-BackendFixer.agent.md
  • mod-Verifier.agent.md

A documentation squad might use doc-Orchestrator.agent.md, doc-Writer.agent.md, etc. Memory files follow the same convention: /memories/session/mod-plan.md, /memories/session/doc-outline.md.

Orchestrator example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
name: mod-Orchestrator
description: Routes legacy modernization tasks to specialist agents.
target: vscode
model:
  - GPT-5.6 Terra (copilot)       # primary — 24h prompt-cache retention for coordinator idle gaps
  - GPT-5.4 (copilot)             # same-family fallback (same 24h cache retention)
  - Claude Sonnet 4.6 (copilot)   # cross-family last resort
tools: ['search', 'read', 'vscode/memory', 'agent']
agents: ['mod-Planner', 'mod-BackendFixer', 'mod-Verifier']
user-invocable: true
---

You are the Modernization Orchestrator. You coordinate the team but never write code.

## Protocol
1. Write the task brief to `/memories/session/mod-task-brief.md`
2. Invoke mod-Planner to research and plan
3. Invoke mod-BackendFixer to implement
4. Invoke mod-Verifier to validate
5. Report results to the user

The agents: allowlist declares which subagents this Orchestrator may invoke — without it, the agent tool could call any agent in the workspace. The Orchestrator is the only squad member with user-invocable: true; all others use disable-model-invocation: true, creating a controlled hierarchy.

CLI: building squads with the task tool

The CLI supports plan mode (Shift+Tab) where it builds a structured implementation plan before writing code. In plan mode, the CLI may delegate individual plan steps to different agents — achieving something like VS Code’s squad pattern, but driven by the model’s judgment.

You can also define an explicit orchestrator in the CLI. The task tool spawns a fresh context for each subtask — the CLI equivalent of VS Code’s agent tool. Since v1.0.19, task(agent_type="<agent-name>", prompt="...") can dispatch not just to built-in subagents (explore, general-purpose, rubber-duck, …) but to other custom agents in the same repo. That means the VS Code squad pattern — an orchestrator plus separate specialist files, each with its own tools: list — works in the CLI too:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
---
description: Orchestrates multi-step tasks by delegating to specialist agents
  via the `task` tool. Use for complex tasks that benefit from specialized roles.
target: github-copilot
model: Claude Sonnet 4.6 (copilot)
tools: ['read', 'ask_user', 'task']
---

You are an orchestrator. You never write code directly — you delegate via the `task` tool.

## Protocol
1. Analyze the task and break it into subtasks.
2. For each independent subtask, dispatch a `task` naming the specialist agent:
   - `task(agent_type="mod-Planner", prompt="…")` for research and planning.
   - `task(agent_type="mod-Implementer", prompt="…")` for source edits.
   - `task(agent_type="mod-Verifier", prompt="…")` for validation.
3. Independent tasks CAN be dispatched in parallel.
4. Synthesize results and report back to the user.

Notice the orchestrator’s tools: list has no edit and no shell — since v1.0.42 the CLI is biased against unnecessary delegation, so stripping direct-work tools is what makes the model actually dispatch instead of doing work inline. Each specialist agent lives in its own file with its own tools: list, and setting user-invocable: false on internal specialists hides them from the /agent picker while keeping them dispatchable via task.

One thing the CLI cannot reproduce from VS Code is the agents: allowlist — that property is not part of the CLI schema. In VS Code, agents: lets an orchestrator declare which specialists it may invoke, and pairs with disable-model-invocation: true on specialists so only allowlisted orchestrators can call them. On the CLI, any agent with the task tool can dispatch to any specialist that isn’t excluded some other way, and disable-model-invocation: true — with no allowlist to grant exceptions — just removes the specialist from model dispatch entirely. Practical consequences:

  • Per-file tools: lists still enforce what each specialist can do, so a specialist with only read and search cannot edit files regardless of who invokes it.
  • Enforcing who can invoke whom requires convention rather than schema — clear naming, user-invocable: false on specialists, and orchestrator prompts that name only the intended specialists.
  • If multiple orchestrators coexist in a repo, there is no way to say “only orchestrator X can call specialist Y” the way agents: does in VS Code.

One difference from VS Code: the CLI documents model: as a single string per the CLI reference — VS Code’s fallback-chain array form is not part of the CLI schema. In return, the CLI lets the caller specify the model at invocation time (via task(...) or --model), so you can reuse the same agent with different models dynamically, and per-user resilience is expressed through ~/.copilot/settings.jsonsubagents.agents.<name>.model.

Skills: keeping agent files lean

When an agent needs deep domain knowledge (API patterns, validation rules, output templates), putting everything in the agent body wastes context tokens on every invocation — even when that knowledge isn’t relevant to the current step.

Skills solve this by externalizing reference material into separate files that are loaded on demand. The agent body defines the protocol (what steps to follow); the skill contains the reference material (templates, checklists, examples). For a deeper dive into skills as a concept, see post #3 in this series.

VS Code searches for skills in several default locations (configurable via chat.agentSkillsLocations):

ScopePath
Workspace.agents/skills/, .github/skills/, .claude/skills/
User~/.agents/skills/, ~/.copilot/skills/, ~/.claude/skills/

Each path should contain skill subfolders with a SKILL.md file inside, e.g., .agents/skills/security-review/SKILL.md. This pattern keeps agent definitions to 50–100 lines while skills can contain hundreds of lines of domain knowledge — loaded only when needed.

Sharing agents and skills across teams

Custom agents and skills can be shared at multiple levels:

ScopeAgents locationSkills locationAvailable to
User~/.copilot/agents/~/.copilot/skills/ or ~/.agents/skills/All projects on your machine
Repository.github/agents/.github/skills/, .claude/skills/, or .agents/skills/Current project
Organization / Enterprise/agents/ in the .github-private repo/skills/ in the .github-private repoAll projects under the org or enterprise

In VS Code, enabling github.copilot.chat.organizationCustomAgents.enabled makes organization-level agents appear in the Agents dropdown. The organization tier is powerful for standardization: a platform team can ship shared agents that every project inherits automatically. For versioned dependency management of these configurations, see APM.

Decision guide

flowchart TD
    Start([Need a custom agent?]) --> Q1{Single focused task?}
    Q1 -- Yes --> One[Create one .agent.md]
    Q1 -- No --> Q2{Which platform?}

    Q2 --> VSC[VS Code]
    Q2 --> CLI[CLI]
    Q2 --> Cloud[Cloud]
    Q2 --> Cross[Cross-platform]

    VSC --> QV{Human review<br/>at each step?}
    QV -- Yes --> HO[Handoffs]
    QV -- No --> VO[Orchestrator +<br/>agent tool]

    CLI --> QC{Deterministic<br/>sequencing?}
    QC -- Yes --> CO[Orchestrator +<br/>task tool]
    QC -- No --> AD[Auto-delegate<br/>via descriptions]

    Cloud --> QCl{Well-defined scope +<br/>all context in repo?}
    QCl -- Yes --> CAg[Cloud agent]
    QCl -- No --> LocalHO[Start local,<br/>hand off to cloud]

    Cross --> MCP[MCP tools +<br/>shared files]

    One & HO & VO & CO & AD & CAg & LocalHO & MCP --> Pin([Pin optimal model per role])

Troubleshooting

SymptomLikely causeFix
Agent doesn’t appear in VS Code dropdownWrong file location or extensionEnsure file is in .github/agents/ and named *.agent.md
Agent appears but never gets invoked by other agentsVague description fieldMake description specific about scope and triggers
Subagent silently uses a different model than requestedCost tier exceededA subagent can’t request a model more expensive than the parent; check the parent’s model tier
CLI ignores your agentMissing or ambiguous descriptionThe CLI routes based on description quality; add explicit trigger phrases
disable-model-invocation seems to have no effectNo other agents are trying to invoke itThis property only matters when other agents exist; without it, any agent with the agent tool can invoke yours
disable-model-invocation on CLI blocks all invocation, not just non-allowlisted onesCLI does not implement the agents: allowlistOn CLI there is no allowlist to grant exceptions to; use user-invocable: false plus per-file tools: restrictions instead, and rely on orchestrator prompts to name intended specialists
Cloud session can’t use your squadMulti-agent not supported in cloudCloud supports single custom agents only; use local for multi-agent, then hand off the result
Agent loads but produces poor outputToo many tools in contextRestrict tools: to only what the agent actually needs

Advanced: adversarial review with per-agent model pinning

Both VS Code and the CLI can run subagents in parallel — VS Code through the agent tool, the CLI through parallel task dispatches (see the orchestrator example above). Parallelism is table stakes, and the built-in review agents (VS Code’s Code Review, the CLI’s Code Review and Rubber Duck) already exploit it.

The feature that turns parallel review into adversarial review is one that only custom agents have: per-agent model pinning. Built-in review agents run on whatever model the session is currently using, so spawning two of them in parallel gives you two runs of the same model — same training data, same blind spots, same systematic misses. Custom agents let you pin a specific model (or fallback chain) per file, so you can put a Claude reviewer next to a GPT reviewer and get findings that are genuinely independent.

That flips the design priority. When building an adversarial review setup, model diversity is the primitive; parallelism is just how you keep wall-clock time reasonable.

The example below defines a single reviewer role. The tribunal pattern in the next subsection is what actually makes it adversarial — two instances of this role, each pinned to a different vendor family, invoked in parallel by a merge arbiter.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
name: Thorough Reviewer
target: vscode
model:
  - GPT-5.6 Terra (copilot)       # primary — 24h prompt-cache retention while parallel reviewers run
  - GPT-5.4 (copilot)             # same-family fallback
  - Claude Sonnet 4.6 (copilot)   # cross-family last resort
tools: ['agent', 'read', 'search']
---
You review code through multiple perspectives simultaneously. Run each perspective
as a parallel subagent so findings are independent and unbiased.

When asked to review code, run these subagents in parallel:
- Correctness reviewer: logic errors, edge cases, type issues.
- Code quality reviewer: readability, naming, duplication.
- Security reviewer: input validation, injection risks, data exposure.
- Architecture reviewer: codebase patterns, design consistency.

After all subagents complete, synthesize findings into a prioritized summary.

The same shape works in the CLI: swap the agent tool for task, drop the VS Code-only frontmatter, and remember that the CLI’s model: is a single string per the CLI reference — pin a different string in each reviewer file to get cross-family diversity.

Important: By default, subagents cannot spawn further subagents — this prevents infinite recursion. To enable nested delegation, set chat.subagents.allowInvocationsFromSubagents to true in VS Code settings. When enabled, subagents can spawn their own subagents up to a maximum nesting depth of 5.

The review tribunal pattern

The recommended pattern for high-quality review uses a review tribunal — three agents forming a complete review stage:

AgentRoleKey constraint
<prefix>-ReviewerAIndependent reviewer #1Pinned to vendor family A; writes findings to its own output file
<prefix>-ReviewerBIndependent reviewer #2Pinned to vendor family B; writes findings to its own output file
<prefix>-CodeReviewerMerge arbiterInvokes both in parallel, deduplicates, merges, classifies severity

The critical constraint: ReviewerA and ReviewerB must be pinned to models from two different vendor families (e.g., Claude vs GPT, GPT vs Gemini) via the model: field in each reviewer’s frontmatter. Same-family models share blind spots, defeating the purpose — which is exactly why you can’t get this from two invocations of a built-in reviewer.

flowchart TD
    Orch[Orchestrator] -- invoke --> CR[CodeReviewer]
    CR -- dispatch in parallel --> RA[ReviewerA<br/>GPT family]
    CR -- dispatch in parallel --> RB[ReviewerB<br/>Claude family]
    RA -- writes --> OA[reviewerA-output.md]
    RB -- writes --> OB[reviewerB-output.md]
    OA & OB -- read + merge --> Merged[review-output.md<br/>deduplicated + severity-classified]

The workflow:

  1. The Orchestrator invokes CodeReviewer (never the individual reviewers directly).
  2. CodeReviewer invokes ReviewerA and ReviewerB in parallel. Neither sees the other’s output.
  3. CodeReviewer reads both output files, deduplicates, merges, and classifies severity (CRITICAL / HIGH / MEDIUM / LOW).
  4. The Orchestrator reads the merged report and loops back to specialists for fixes if needed.

Rubber Duck in the CLI

The CLI takes a different approach. Rather than requiring explicit adversarial agents, it includes a built-in Rubber Duck agent that acts as a constructive critic automatically. On non-trivial tasks, the CLI silently consults the Rubber Duck before finalizing its response — challenging assumptions and flagging potential issues without any configuration on your part.

Conclusion

The core principle is the same across all three platforms: divide work into focused contexts, assign the right model to each, and pass only necessary context between steps.

In VS Code, you achieve this through explicit orchestration — the agents: allowlist, handoffs, and subagent invocation give you precise control. The CLI now supports the same orchestrator pattern via the task tool, and additionally lets the model delegate autonomously based on agent descriptions when no orchestrator is defined. In the Cloud, agents work independently on well-scoped tasks and deliver pull requests.

Start simple: one custom agent that solves a real pain point. Verify it works. Then add a second agent and coordinate them. Build complexity gradually — the same way you’d build any other system.

One caveat: despite sharing the .agent.md format, VS Code, the CLI, and Cloud are developed by independent teams at GitHub and Microsoft. Frontmatter properties like target, tool names, and coordination mechanisms don’t always translate across platforms. A squad that works perfectly in VS Code won’t automatically run in the CLI without adjustments. Hopefully, as the ecosystem matures, these runtimes will converge — but for now, be prepared to maintain platform-specific variants when needed.

This post is licensed under CC BY 4.0 by the author.