Using Custom Agents with GitHub Copilot CLI
The intuitive reason to build a custom agent is to give it a personality — a security expert, a documentation writer. That is the least important part.
The reason that matters is the tools list. An agent defined without edit
cannot modify files. Not “has been asked not to” — cannot. Everything else about
agent design is prompt engineering, which is useful; the tool restriction is
architecture, which is enforceable.
Key takeaways
- Repository agents live in
.github/agents/NAME.agent.md; personal agents in~/.copilot/agents/. When the same name exists in both, the home-directory version wins. - Frontmatter carries
name,description,toolsandmcp-servers. Omittingtoolsgrants access to all available tools — the default is permissive. - Invoke with
/agent [name]interactively or--agent NAMEon the command line, using the filename without.agent.md. - Six built-in agents exist. Three are read-only:
explore,code-review,research. - A restricted
toolslist is the design decision. Prose in the agent body guides; the tool list constrains.
The built-in agents you already have
Before writing one, know what ships.
| Command | Purpose | Risk (editorial guidance, not a GitHub classification) |
|---|---|---|
exploreRead only | Read-only codebase analysis. | Low |
task | Runs development commands. | Medium |
general-purpose | Full Copilot capabilities. | Medium |
code-reviewRead only | Analyses changes for substantive issues. Behind /review. | Low |
researchRead only | Exhaustive investigation. Behind /research. | Low |
rubber-duckRead only | An alternative perspective, using a different model. Behind /rubber-duck. | Low |
Copilot selects an appropriate built-in agent based on your prompt and context,
and several have dedicated slash commands: /review runs code-review,
/research runs research, /rubber-duck runs the rubber duck.
The read-only three are the ones to reach for habitually. explore in particular
is the correct tool for understanding an unfamiliar repository, because the
question “what does this code do” should never carry a risk of changing it.
copilot --agent explore -i "How does authentication work in this project?"When a custom agent is worth building
Custom agents earn their place in three situations.
A repeated task with a repeated shape. Reviewing pull requests against your team’s conventions, auditing dependencies, checking migrations. Anything you have prompted three times the same way.
A task that should be structurally constrained. A reviewer that cannot edit. An auditor that cannot reach the network. The restriction is the point.
A task needing specific context every time. Your architecture, your conventions, the failure modes you have seen before.
They are not worth building for one-off work, or where the only difference is tone. If the prompt would be the same, a saved prompt is simpler.
Reading the built-in list as a design lesson
The six built-in agents are worth studying as examples rather than only as tools, because their split is instructive.
Three are read-only and three are not, and the division follows the task rather
than the difficulty. explore reads a codebase. code-review analyses changes.
research investigates. None of them needs to write anything to do its job, so
none of them can.
task runs development commands and general-purpose has full capabilities,
because those roles are defined by acting.
The lesson is that the tool list should follow from the verb in the agent’s description. If an agent’s job is described with “review”, “analyse”, “explain”, “audit” or “find”, it almost certainly wants a read-only tool list — and writing that list is what turns the description into a property of the system rather than an intention.
The file format
Markdown with YAML frontmatter. The filename determines the invocation name:
security-reviewer.agent.md is invoked as security-reviewer.
---
name: Security reviewer
description: Reviews changes for security problems without modifying anything.
tools: ["read", "search"]
---
You review code for security problems. You do not fix them.
## What to look for
- Input reaching a shell, a query, a path or a deserialiser without validation
- Credentials in source, configuration or test fixtures
- Authentication and authorisation checks that are missing or bypassable
- Unsafe defaults: permissive CORS, disabled verification, debug mode
- Dependencies with known problems
## How to report
For each finding: the file and line, what an attacker could do, and how
confident you are. Separate what you verified from what you suspect.
If you find nothing, say so plainly. Do not manufacture findings to
appear thorough.
## What you do not do
You do not modify files. You do not run commands that change state.
You report, and a human decides.Tool names and aliases go in the list, and tools from MCP servers can be included
with server-qualified names — tools: ["read", "search", "some-mcp-server/tool-1"].
An agent file may also declare mcp-servers of its own.
Invoking an agent
Interactively:
/agentBrowse and select, or name it directly with /agent security-reviewer.
Programmatically:
copilot --agent security-reviewer --prompt "Check src/auth/"The --agent value is the filename without .agent.md. That pairing —
--agent with -p/--prompt — is what makes agents useful in automation, since
the agent’s tool restrictions travel with it into a non-interactive run.
Repository versus personal agents
Repository agents in .github/agents/ are shared, versioned and reviewed —
appropriate for team conventions.
Personal agents in ~/.copilot/agents/ follow you across projects — appropriate
for how you like to work.
When both define the same name, the home-directory version wins.
Designing agents that work
Restrict tools first
Decide what the agent must not be able to do, then write the list. This is easier than the reverse and produces better agents.
| Pattern | Decision | Why |
|---|---|---|
reviewer — read, search | Allowed | Reads and reports. Cannot modify, so cannot be talked into it. |
reviewer — edit | Denied | Reviewing and fixing are different jobs with different review requirements. |
test-writer — read, search, edit | Allowed | Needs to write test files. |
test-writer — shell | Asks first | Running the suite is useful; running arbitrary commands is not required. |
auditor — read, search | Allowed | No network: an auditor has no reason to fetch anything. |
Written for this lesson to illustrate least privilege. Not a GitHub default and not a security guarantee — read every rule before using it.
Give it one job
An agent that reviews security, writes tests and updates documentation is a general-purpose agent with extra words. The value comes from narrowness — a narrow agent can be given a restrictive tool list, and its output is predictable enough to be useful in automation.
Say what “done” looks like
Agents used repeatedly should produce consistent output. Specify the format: what a finding contains, how confidence is expressed, what to say when there is nothing to report.
That last one matters more than it seems. An agent with no instruction for the empty case will often produce marginal findings rather than reporting nothing, because reporting nothing feels like failing the task.
Separate observation from inference
Separate what you verified from what you suspect.
If you read the code and confirmed the behaviour, say so. If you are inferring from a pattern, say that instead.
Never present an inference as a verified finding.
A second example: the migration checker
Security review is the obvious agent. A less obvious and often more useful one encodes institutional knowledge — the specific mistakes your team has actually made.
---
name: Migration checker
description: Reviews database migrations against the rules that have caused
incidents here before.
tools: ["read", "search"]
---
You review database migrations. You do not write or run them.
## Rules this team has learned the hard way
- A migration that adds a NOT NULL column with no default locks the
table for the duration of the rewrite. On tables over a million rows,
that is an outage.
- Dropping a column must come at least one deploy after the code that
read it stopped shipping. Otherwise a rollback breaks.
- Creating an index on a large table must be CONCURRENTLY, and
CONCURRENTLY cannot run inside a transaction.
- Renaming is a drop plus an add as far as running code is concerned.
- Every migration needs a down path that has actually been considered,
not one that was generated and never read.
## How to report
For each migration file: what it does, which of the rules above it
touches, and the expected impact on a table of a million rows.
State plainly if a migration looks safe. Do not invent concerns.That agent contains nothing a model does not already know about databases. What it contains is which of those facts your team keeps forgetting, in a form that gets applied every time rather than when someone remembers.
Agents versus instructions versus permissions
Three mechanisms with overlapping-looking purposes. The distinction is what happens when the model disagrees.
Instructions are guidance loaded into context. The model usually follows them. It can decline, misread, or lose them to context compaction. Use for “usually do it this way”.
Agent tool lists are structural. An agent without edit has no edit tool to
call — there is nothing to decline. Use for “this role cannot do that”.
Permission flags are enforced by the CLI at invocation time, and denial beats
everything including --allow-all-tools. Use for “this must never happen in this
session”.
They compose usefully. An agent restricted to ["read", "search"], invoked in a
session that also denies write and url, run against a repository whose
instructions describe your conventions — each layer catching what the others miss.
Subagents and parallelism
/tasks views and manages tasks including subagents. /fleet enables parallel
subagent execution. /subagents configures default and per-agent subagent models.
The real benefit is context isolation. A subagent asked “find every call site of this function” does that work in its own context and returns an answer, rather than filling the main session with file listings. Since context pressure directly degrades behaviour, that is a substantive gain rather than a tidiness one.
A worked example: the security reviewer
Create .github/agents/security-reviewer.agent.md with the content above, then:
/agent security-reviewer
Review the changes on this branch against main. Report findings with file, line, impact and confidence. Do not modify anything.
Two things to check the first time.
Did it stay in role? An agent that starts proposing fixes despite a read-only tool list is being blocked by the tool list, which is the system working. If it proposes fixes in prose, that is fine — it is reporting, not acting.
Are the findings real? Read them against the code. The code review lesson covers evaluating findings, and the short version is that plausible and correct are different things.
Agent architecture in practice
The tempting diagram is a hierarchy — a main agent delegating to security, testing, documentation and DevOps specialists, each with its own context.
The reason this works is not that each agent is expert. It is that each stage has a different tool list and a different framing, so a mistake made in one stage is being looked at by something that did not make it.
Read-only review after write-capable implementation is the useful pattern here. The reviewer cannot quietly fix what it finds, so findings surface as findings rather than disappearing into a diff — which is what makes them reviewable by you.
Testing an agent
An agent file is configuration that changes behaviour, and like any configuration it can be wrong in ways that are invisible until it matters. Two checks are worth running when you write one.
Check the restriction holds. Ask a read-only agent to make a change. It should
be unable to — not decline politely, but lack the tool. If it edits a file, the
tools list is wrong or missing.
Check it finds a planted problem. Introduce a flaw of the kind the agent exists to catch — a hard-coded credential for a security reviewer, a non-concurrent index for a migration checker — and confirm it is reported. An agent that reports nothing might be working perfectly or might be misconfigured, and the two are indistinguishable without a positive control.
/agent security-reviewer
Review src/config.py. I have deliberately introduced one issue of the kind you exist to find. Tell me what it is.
If you find nothing, say so — I want to know either way.
That second sentence is doing real work. Telling the agent a problem exists risks it inventing one, so the final line gives it explicit permission to report nothing. Running the same check both with and without a planted flaw is the stronger version, and it is worth the extra minute for an agent you intend to rely on in CI.
Where agents disappoint
They do not add knowledge. A “security expert” agent is the same model with different instructions. It does not know more about security; it attends differently.
Narrow roles miss cross-cutting problems. An agent looking for security problems will not tell you the architecture is wrong.
They inherit the model’s blind spots. Which is exactly why rubber-duck using
a different model is a genuinely different check rather than a rephrasing.
Over-specification makes them brittle. An agent with forty rules follows the first few and averages the rest.
Agents as a team asset
Once agents live in .github/agents/, they are shared infrastructure and behave
like it — which changes how they should be written and maintained.
They go through review. A pull request adding an agent is a pull request granting
a set of capabilities, and the tools list is the part that deserves the
attention. An agent quietly gaining shell in a later commit is a meaningful
change that looks small in a diff.
They accumulate knowledge. The migration checker above is more valuable in its second year than its first, because each incident adds a rule. This makes agents a better home for hard-won operational knowledge than a wiki page, since they are consulted automatically rather than when someone remembers.
They need pruning. An agent encoding a convention the team abandoned is actively harmful, because it argues confidently for something nobody believes any more.
When not to build one
Worth stating plainly, because the failure mode here is enthusiasm.
For a task you do once. A prompt is fine. An agent is a file to maintain.
To make the model better at something. It will not. Role descriptions change attention, not capability.
As a substitute for permissions. If something must not happen in a session, the flag is the mechanism. An agent restricts what that agent can do; it does not constrain the session around it.
Before you have prompted the task a few times. The third repetition is where you learn what the agent should actually say. Writing it earlier means writing a guess.
Skills, plugins and where agents stop
An agent is one of four packaging mechanisms, and picking the wrong one produces something awkward.
Skills are SKILL.md files describing how to perform a particular task,
discovered from .github/skills/, .agents/skills/, .claude/skills/,
~/.copilot/skills/ and ~/.agents/skills/. Where an agent is a role with
capabilities, a skill is a procedure available to whatever role is active.
“How to cut a release in this repository” is a skill; “release manager” is an
agent, and the first is usually what you actually wanted.
Plugins bundle skills, agents, hooks, MCP servers and LSP servers into one
installable unit, from a marketplace or any GitHub repository. Two marketplaces
ship by default: github/copilot-plugins and github/awesome-copilot.
MCP servers give agents tools that reach outside the CLI. An agent’s
frontmatter can declare its own mcp-servers, which is how a specialised agent
gets specialised capabilities rather than only specialised instructions.
What to carry forward
Write the tools list first. It is the only part that constrains rather than
suggests.
Remember the permissive default. No tools key means every tool.
One job per agent. Narrowness is what makes a restrictive tool list possible and what makes the output predictable enough to automate.
Specify the output format, including the empty case.
Prefer read-only agents wherever the task is analysis.
Check for personal agents shadowing team ones when behaviour surprises you.
The through-line of this lesson is a single asymmetry worth keeping. Prose in an
agent file describes intent, and a model interprets intent. The tools list
describes capability, and capability is not open to interpretation. When those two
disagree — and they disagree more often than anyone expects, because the prose is
easy to write and the list is easy to forget — the capability is what governs.
Writing the list first is the habit that keeps them aligned.
Starting small
If you build one agent, make it a read-only reviewer for the mistakes your team actually repeats. It is the highest-value agent for most teams, it cannot break anything, and writing it forces a useful conversation about what those mistakes are.
If you build a second, make it an explorer scoped to your codebase’s particular shape — the conventions, the layout, the places where things are not where a newcomer would look. That one pays back every time somebody works in an unfamiliar part of the system.
Beyond two, be honest about whether you are solving a problem or collecting configuration.
Next
Code review goes deep on the built-in code-review agent — what it examines and where it stops being sufficient. GitHub Actions is where restricted agents pay off most, because a reviewed tool list in version control is a much better CI control than flags copied between workflows.
For the permission grammar these tool lists interact with, see the commands cheat sheet and the pillar.
Sources
Every version-sensitive claim on this page was checked against first-party documentation. Only sources actually used are listed.
Primary sources
Additional references
Your progress
Saved in this browser only. No account, no server, and nothing leaves your device. Clearing site data resets it.Sync across devices if you want it everywhere.
Saved in this browser and synced to your account, so it follows you between devices. Manage or delete it.
Was this lesson helpful?
We record which lesson you rated and whether it helped. Nothing identifies you — no account, no cookie, no session.