·10 min read

GitHub Copilot Custom Agents: The .agent.md Guide

Learn how GitHub Copilot custom agents work: .agent.md anatomy, the .github/agents directory, CLI and IDE usage, and how they differ from instructions files.

GitHub Copilot custom agents are reusable agent definitions stored as .agent.md files in your repository's .github/agents/ directory. Each file pairs YAML frontmatter — a name, a description, and an optional tool allowlist — with a markdown body that becomes the agent's system prompt. Invoke one by name in Copilot CLI, VS Code, or the Copilot coding agent, and Copilot stops being a generalist and starts behaving like the specialist you defined.

This guide walks through the anatomy of the .agent.md file, where the files live, how to write agent profiles that measurably change output, how to use them in the CLI and the IDE, and when a custom agent beats an instructions file.

What are Copilot custom agents?

A custom agent is a named persona for Copilot. Instead of one general-purpose assistant that you re-brief in every chat, you define specialists once and switch between them:

  • test-writer — writes and repairs unit tests, never touches production code
  • security-reviewer — reads diffs, flags injection and authz issues, edits nothing
  • migration-helper — knows your ORM and your migration conventions
  • docs-agent — updates reference docs to match code changes

You'll also see these files called Copilot agent profiles — same thing. The important properties are that they're explicitly invoked (unlike instructions files, which apply passively), tool-scoped (an agent can be forbidden from running shell commands or editing files), and checked into git, so the whole team gets the same specialists.

If you're familiar with Claude Code subagents, the mental model transfers directly: a markdown file with frontmatter defines a focused worker with its own prompt and its own tool permissions.

Anatomy of a .agent.md file

Every .agent.md file has two parts: YAML frontmatter and a markdown prompt body.

---
name: test-writer
description: Writes and repairs Vitest unit tests. Use for any test-related task.
tools: ["read", "search", "edit", "shell"]
---

You are the test engineer for this repository.

## Scope
- Write and fix tests under src/**/*.test.ts. Do not modify production code.
- If a test fails because the implementation is wrong, report it — don't "fix" the test.

## Conventions
- Vitest only. Never introduce Jest APIs.
- Use vi.mock() with factory functions, not manual stubs.
- One describe block per exported function; name tests "does X when Y".
- Run the affected test file after every change and paste the output.

Frontmatter fields

FieldRequiredWhat it does
nameNoInvocation handle. Defaults to the filename (test-writer.agent.mdtest-writer)
descriptionYesShown in agent pickers, and used to decide when the agent is relevant — write it like routing criteria, not marketing
toolsNoAllowlist of tools the agent may use. Omit it and the agent inherits everything available

Some surfaces accept additional fields (VS Code, for example, supports a model hint), but name, description, and tools are the portable core. Keep the frontmatter minimal and put everything else in the body.

The prompt body

Everything below the frontmatter is the agent's system prompt. This is where the behavior change actually happens — the frontmatter just handles discovery and permissions. Treat it like any high-stakes prompt: concrete rules, file paths, naming conventions, and an explicit definition of what the agent must not do.

Where agent files live: .github/agents and beyond

The canonical location is the .github/agents directory at your repository root:

.github/
  agents/
    test-writer.agent.md
    security-reviewer.agent.md
    migration-helper.agent.md
  copilot-instructions.md

Repo-level agents are the reliable baseline: they're versioned, they ride along with clones, and every Copilot surface that supports custom agents looks there first.

Two other locations matter:

  • Personal agents. Copilot CLI also loads user-level agents from your home directory configuration, so a personal code-golf or commit-message agent follows you across repositories without polluting any repo's .github/ folder.
  • Organization-wide reuse. There's no magic org-level sync for agent files — teams that want the same agents in forty repos end up copying files around. Keep agent names unique across the locations you use; a repo agent and a personal agent with the same name is a debugging session waiting to happen.

How to create Copilot custom agents step by step

Here's the full loop, from empty repo to a working specialist.

  1. Create the directory.
mkdir -p .github/agents
  1. Write your first agent file. Start with the job you re-explain most often in chat. For most teams that's code review:
---
name: pr-reviewer
description: Reviews diffs for correctness and convention violations. Read-only.
tools: ["read", "search"]
---

You are a senior reviewer for this codebase. Review the changes you're given.

- Flag any endpoint that reads request data without Zod validation.
- Flag any new dependency added without justification.
- Flag missing error handling on async database calls.
- Output findings as a markdown list: severity, file:line, one-sentence issue,
  suggested fix. If there are no findings, say so in one line.
  1. Scope the tools deliberately. The tools allowlist above is doing real work: a reviewer with read and search but no edit or shell physically cannot "helpfully" rewrite your code mid-review. Start narrow and widen only when the agent hits a wall.

  2. Test it in Copilot CLI. Launch copilot in the repo and list discovered agents with /agents — your pr-reviewer should appear. Select it and give it a real diff. If the output looks like default Copilot, your prompt body is too vague (more on that below).

  3. Commit it. The file is just markdown in git, so it goes through code review like everything else — and every teammate gets the agent on their next pull.

git add .github/agents/pr-reviewer.agent.md
git commit -m "Add pr-reviewer custom agent"

Writing agent profiles that actually change behavior

Most first-draft agent files fail the same way: they read like job descriptions instead of instructions. "You are an expert security engineer with deep knowledge of OWASP" changes almost nothing about the output. Rules change output.

Weak → strong, line by line:

WeakStrong
"Write high-quality tests""One describe per exported function; every test asserts on behavior, not implementation details like call counts"
"Be security-conscious""Flag any string interpolation inside a SQL template; require parameterized queries"
"Follow project conventions""API routes return { data } on success and { error } with an HTTP error status on failure — flag anything else"

Three habits that separate agents people use from agents people abandon:

  • One job per agent. An agent that reviews and fixes and documents converges back to default behavior. Split it.
  • Define the output format. "Output findings as severity / file:line / issue / fix" makes results scannable and makes regressions in the agent's behavior obvious.
  • Iterate on failures. When the agent does something wrong, don't add a paragraph — add the one rule that would have prevented it, and delete any vague line it ignored. Short, dense profiles outperform long, aspirational ones.

The same discipline applies to instructions files; agents just raise the stakes because they often run with less supervision.

Using custom agents in Copilot CLI and the IDE

Copilot CLI

Copilot CLI custom agents are discovered when the session starts — repo agents from .github/agents/ plus your personal ones. Inside an interactive session, /agents lists them and lets you switch. You can also point a non-interactive run at an agent, which is where custom agents get genuinely powerful: a scripted pr-reviewer pass in CI, or a migration-helper invoked from a make target, runs with exactly the prompt and tool scope you committed — no per-developer drift.

VS Code

In VS Code, custom agents appear in Copilot Chat's agent picker alongside the built-in modes. Pick test-writer, and the chat session runs under that agent's prompt and tool restrictions until you switch. This is the fastest way to iterate on a profile: edit the .agent.md file, start a fresh chat, replay the same request, and diff the behavior.

Copilot coding agent

The Copilot coding agent — the one you assign GitHub issues to — also picks up custom agents from the repository. That makes .github/agents/ the highest-leverage place to encode "how we do things here" for asynchronous work, because nobody is watching the agent mid-task to correct it.

Custom agents vs instructions files

Copilot has two persistent-context mechanisms, and they solve different problems:

Custom agentsInstructions files
Location.github/agents/*.agent.md.github/copilot-instructions.md, .github/instructions/*.instructions.md
ActivationExplicitly invoked by nameApplied automatically (always, or by glob)
GranularityPer-task personaRepo-wide or path-scoped conventions
Tool controlYes — allowlist per agentNo
Best forRepeatable specialist workflowsBaseline conventions every task needs

Use an instructions file for facts that are true of every task: tech stack, naming conventions, error-handling patterns. Our Copilot custom instructions guide covers that file in depth, and the applyTo frontmatter guide covers path-scoped variants. Use a custom agent when a workflow — reviewing, testing, migrating — needs its own rules, its own output format, or its own tool restrictions.

They stack, which is the point: instructions files set the baseline, AGENTS.md provides the cross-tool contract that Copilot also reads, and custom agents specialize on top.

Sharing custom agents across repos and teams

The failure mode shows up around repo number three: someone improves pr-reviewer in one repository, and the other copies silently rot. Agent files are prompts, and prompts need versioning, review, and distribution like any other shared artifact.

That's the problem localskills.sh solves. Publish your agent prompt and its supporting material as a skill — skills are versioned packages with a root SKILL.md, and can bundle extra docs, scripts, and templates — then install it anywhere. One published skill can target multiple tools at once, so the conventions behind your Copilot agents can also land as .cursor/rules for Cursor or .claude/skills/ for Claude Code teammates. With rollback, private visibility, and bidirectional GitHub sync for org libraries, the "which repo has the good version" question disappears.

FAQ

Do custom agents replace copilot-instructions.md?

No. Instructions files apply to everything automatically; custom agents are opt-in specialists. A healthy setup has one lean instructions file for repo-wide facts and a small set of agents for repeatable workflows. If a rule matters for every single task, it belongs in instructions, not in an agent.

Can a custom agent use MCP tools?

The tools allowlist governs whatever tools the surface exposes to the session — including tools contributed by configured MCP servers. List the MCP tool names you want the agent to have, or omit tools to inherit everything. Restricting agents to the few tools they need also keeps context lean.

How many custom agents should a repo have?

Fewer than you think. Three to six focused agents that people actually invoke beat fifteen that nobody remembers. If two agents share most of their prompt, merge them or move the shared rules into your instructions file.

Does the filename matter?

Yes — the file must end in .agent.md, and without an explicit name in frontmatter the filename (minus the extension) becomes the agent's name. Use short, kebab-case names like pr-reviewer since you'll be typing or selecting them constantly.


Your agent profiles are team assets — version them, review them, and share them like code. Sign up for localskills.sh to publish them once and install them across every repo and every tool your team uses.

npm install -g @localskills/cli
localskills login
localskills install your-org/your-agents --target copilot cursor claude