GitHub Copilot Customization That Actually Sticks: A Field Guide
A practical guide to GitHub Copilot's customization options — what each one is for, when to reach for it, and the mistakes that quietly waste your effort.
Most teams I talk to use one Copilot customization feature, usually a single
copilot-instructions.md, and then wonder why the AI still drifts off-style. The real win comes from knowing which lever to pull for which problem. This post is that map.
GitHub publishes a handy customization cheat sheet that lists every file type, where it lives, and what tool supports it. It’s a great reference — but a reference doesn’t tell you what to do on Monday morning. This post fills that gap.
I’m going to assume you’ve skimmed the cheat sheet. Instead of repeating the table, I’ll answer the three questions it doesn’t: which one do I need, why, and what goes wrong.
The mental model: four layers, four jobs
Copilot customization isn’t one feature — it’s a stack. Each layer answers a different question.
flowchart TD
A["Repository custom instructions<br/>(copilot-instructions.md)"] --> B["Path-specific instructions<br/>(*.instructions.md)"]
B --> C["Prompt files<br/>(*.prompt.md)"]
C --> D["Custom agents / chat modes<br/>(*.agent.md, *.chatmode.md)"]
A -.->|"How should you ALWAYS behave here?"| A
B -.->|"How to behave for THESE files?"| B
C -.->|"Do THIS repeatable task"| C
D -.->|"Be THIS persona with THESE tools"| D
Read that diagram as a sentence:
- Repository instructions = the standing rules for the whole repo.
- Path-specific instructions = exceptions and specializations scoped to a folder or file glob.
- Prompt files = saved, reusable requests you invoke on demand.
- Custom agents = a personality + a restricted toolset for a specific kind of work.
The single most common mistake is cramming everything into layer one. Let’s go layer by layer.
Layer 1 — Repository instructions: your constitution
File: .github/copilot-instructions.md
This is the document Copilot reads on every request in the repo. Think of it as your team’s constitution: short, stable, and rarely amended.
What belongs here:
- Tech stack and versions (
Node 20,Python 3.12,React 18 with function components only). - Hard rules (
never use class components,all dates are UTC,tests use Vitest, not Jest). - Project vocabulary (
a "tenant" is a paying customer; a "user" is a seat within a tenant).
What does not belong here:
- A 600-line style guide. The longer this file, the less weight any single line carries.
- Task instructions (“when I ask you to add an endpoint…”). That’s a prompt file’s job.
- Anything that’s only true for one folder. That’s layer 2.
Treat this file like a dependency: keep it lean and review it in PRs. A bloated instructions file is the AI equivalent of a 200-line function — technically valid, practically ignored.
A good repo-level file fits on one screen. If yours doesn’t, you probably have layer-2 content hiding in it.
Layer 2 — Path-specific instructions: scoped expertise
File: *.instructions.md with an applyTo frontmatter glob
This is the layer most people don’t know exists, and it’s the one that quietly solves the “Copilot uses the wrong patterns in our test folder” problem.
1
2
3
4
5
6
---
applyTo: "**/*.test.ts"
---
- Use the Arrange-Act-Assert structure.
- Mock external services with `vi.mock`, never real network calls.
- One behavior per `it()` block; describe blocks group by method name.
Now those rules only fire when Copilot touches a test file. Your frontend .tsx files don’t get polluted with test conventions, and your repo-level instructions stay short.
When to reach for this: the moment you find yourself writing “for files in src/api, do X, but for files in src/ui, do Y” in your main instructions file. That sentence is the signal to split.
Layer 3 — Prompt files: turning tribal knowledge into a command
File: *.prompt.md
Instructions describe how to behave. Prompt files describe a task to perform. The difference matters: instructions are passive context; prompt files are something you actively invoke.
The killer use case is the repeatable multi-step chore everyone does slightly differently:
1
2
3
4
5
6
7
8
9
10
11
12
---
mode: agent
description: Scaffold a new REST endpoint following our conventions
---
Create a new endpoint for the resource named ${input:resource}.
Steps:
1. Add the route handler in `src/api/${input:resource}.ts`.
2. Add a Zod schema for request validation.
3. Wire it into the router in `src/api/index.ts`.
4. Generate a test file with happy-path and 400/404 cases.
5. Add an entry to `docs/api.md`.
Save it once, and “add a new endpoint” becomes a one-line command instead of a paragraph you retype (and subtly change) every time. This is how you stop new inconsistency from entering the codebase.
Prompt files are the highest-leverage customization for teams. They encode the steps your senior engineers do automatically and your juniors forget. That’s onboarding-as-code.
Layer 4 — Custom agents: a persona with guardrails
File: *.agent.md (and chat modes via *.chatmode.md)
An agent bundles three things: a persona (how it thinks), a toolset (what it’s allowed to touch), and instructions (how it works). The persona is the least interesting part — the restricted toolset is the point.
Two examples that show the range:
- A “Reviewer” agent with read-only file access and no terminal. It can analyze and comment but physically cannot edit code or run commands — safe to hand to anyone.
- A “Migration” agent with file edit + terminal access and a tightly scoped prompt for moving you from one library to another, one module at a time.
The value isn’t the friendly name. It’s that you’ve constrained what the AI can do to match the job. A review agent that can’t delete files is safer than a general agent you’re hoping behaves.
A decision table you’ll actually use
| If you’re thinking… | Reach for… |
|---|---|
| “It should always know our stack and rules.” | Repository instructions |
| “This only applies to tests / migrations / one folder.” | Path-specific *.instructions.md |
| “We do this same chore over and over.” | Prompt file |
| “I want a safe, focused mode for one kind of work.” | Custom agent |
| “I want it to stop suggesting class components.” | Repository instructions (one line) |
| “Generate our standard PR description.” | Prompt file |
The four mistakes that waste the effort
- Everything in one file. A 500-line
copilot-instructions.mddilutes every rule. Split by scope into layer-2 files. - Writing essays, not rules. “We generally prefer, where appropriate, to consider using…” gets ignored. Write imperatives: “Use X. Never Y.”
- Instructions that contradict each other. When the repo file says “prefer async/await” and a path file says “use
.then()chains,” you get coin-flip behavior. Audit for conflicts. - No review process. These files are code. Unreviewed, they rot — pointing at deprecated libraries and dead conventions. Put them in PRs.
Start here (a 30-minute plan)
You don’t need all four layers on day one. Here’s the order of return-on-effort:
- Today: write a 20-line
copilot-instructions.md— stack, top 5 rules, vocabulary. Ship it. - This week: notice the one chore your team does most. Make it a prompt file.
- When it hurts: the first time you write a folder-specific exception, pull it into a path-specific file.
- Later: build a custom agent only when you have a workflow (not a task) that needs its own guardrails.
Customization compounds. A lean constitution plus two good prompt files will outperform a sprawling instructions document every single time — because the AI, like a new teammate, follows clear rules better than long ones.
Got a Copilot customization pattern that’s worked well for your team? I’d love to hear it — drop a comment below.
