Using Custom Instructions with Copilot CLI
Every correction you type twice belongs in a file. “Use the virtual environment.” “Run the tests before you say you are done.” “Do not add dependencies.” Repeating these each session is not prompt engineering; it is a configuration problem with a configuration answer.
Copilot CLI reads instructions from several places, and the common mistake is
assuming there is only one. .github/copilot-instructions.md is the best known
and it is not the whole story — which matters, because an instruction file you
forgot about is one of the most common explanations for behaviour you cannot
account for.
Key takeaways
- The CLI reads
.github/copilot-instructions.md, path-scoped files under.github/instructions/, andAGENTS.md— for which the nearest file in the directory tree wins.CLAUDE.mdandGEMINI.mdat the repository root are also recognised. - Path-scoped files use
applyTowith glob syntax; multiple patterns go in one quoted string separated by commas. - Per GitHub’s documentation, personal instructions rank highest, then repository, then organisation — but all relevant sets are provided, rather than one replacing another.
/instructionsshows which files loaded and lets you toggle them./envshows the complete picture including agents, hooks and MCP servers.--no-custom-instructionsdisables the lot, which is the fastest way to test whether an instruction file is the cause of a problem.- Instruction files are executable influence over an agent. Treat one arriving in a pull request as code, not documentation.
Where instructions come from
Four mechanisms, with different jobs:
.github/copilot-instructions.md applies to everything in the repository.
This is the main file and the one to write first.
.github/instructions/NAME.instructions.md applies to files matching a glob,
declared in frontmatter. Subdirectories under .github/instructions are allowed.
AGENTS.md can live anywhere in the tree, and the nearest one to the file
being worked on takes precedence. That makes it well suited to monorepos, where
each package can carry its own conventions.
CLAUDE.md and GEMINI.md at the repository root are also recognised — a
compatibility affordance so a repository already configured for another agent is
not starting from nothing.
Start by generating one
Rather than writing from scratch, let the CLI read the project:
copilot initOr /init from inside a session. It analyses the codebase using a restricted set
of read-only tools and writes .github/copilot-instructions.md describing build
and test commands, coding conventions, project structure and technology stack.
The generated file is a starting point, not a finished artefact. It is good at the factual parts — the commands, the layout, the stack — and it cannot know your preferences, because those are not in the code.
Writing a repository instruction file
The rules worth writing share a property: they are things you would otherwise say in every session.
# Project conventions
## Environment
- Python 3.12 in a virtual environment at `.venv`.
- Always invoke tools as `.venv/bin/python -m <tool>`, never bare.
## Before completing a task
- Run `.venv/bin/python -m pytest -q` and report the actual output.
- Run `.venv/bin/python -m ruff check .` and fix what it reports.
## Constraints
- Do not modify tests to make them pass. Fix the cause, or stop and explain.
- Do not add dependencies. If one seems necessary, explain why and wait.
- Do not change public function signatures without saying so explicitly.
- Never commit secrets. `.env` is local only.Four properties make instructions like these work.
They are checkable. “Run pytest and report the output” either happened or did not. “Write high-quality code” cannot be evaluated by either of you.
They are specific to this project. Generic advice about good practice is already in the model. Your virtual environment path is not.
They state what to do when blocked. “Explain why and wait” gives the agent a defined action, which is what prevents it finding a creative route to the goal you did not want.
They are short. Every line competes with every other line for attention.
Path-scoped instructions
Rules that apply to only part of a repository belong in .github/instructions/,
with an applyTo glob in frontmatter.
---
applyTo: "tests/**/*.py"
---
# Test conventions
- Use pytest, not unittest.
- Each test covers one behaviour and is named for that behaviour.
- Include the failure case, not only the success case.
- No network access. No real filesystem writes outside tmp_path.
- Tests must be deterministic: no wall-clock time, no randomness without a seed.Multiple patterns go in a single quoted string, comma-separated:
---
applyTo: "**/*.ts,**/*.tsx"
---An optional excludeAgent keyword excludes an instruction file from code-review
or cloud-agent — useful when a rule is about how to write code rather than how
to review it.
AGENTS.md and monorepos
AGENTS.md differs from the others in one important way: it can live anywhere,
and the nearest file to the work takes precedence.
The root file carries what is true everywhere — the repository layout, the commit
convention, the review process. Each package carries its own language, test
runner and constraints. An agent working in services/api/ picks up the nearest
file rather than an average of everything.
This solves a real problem. A monorepo with a Go service, a TypeScript frontend and a Python data pipeline cannot describe its conventions in one file without most of the content being irrelevant to any given task.
Personal instructions
Instructions that are about you rather than about a project belong at your user level, not in a repository. Preferences about explanation depth, or a standing instruction to always show the diff, are not things your colleagues should inherit.
GitHub documents the precedence as personal first, then repository, then organisation — with all relevant sets provided rather than one overriding another.
Seeing what actually loaded
Two commands answer this, and they are the first things to run when behaviour is inexplicable.
/instructionsShows the instruction files in effect and lets you toggle them. Toggling is the fast way to test a hypothesis: disable a file, ask again, see whether the behaviour changes.
/envThe complete picture — instructions, MCP servers, skills, agents, hooks, plugins, LSPs, extensions. When an agent behaves in a way nothing in your repository explains, the cause is usually in this list.
copilot --no-custom-instructionsThe blunt version: load nothing. If the strange behaviour disappears, it came
from an instruction file, and /instructions will narrow down which.
What belongs in instructions, and what does not
A useful way to decide: instructions should carry information the agent cannot derive from the code, and rules it would otherwise violate by reasonable default.
Belongs in instructions. The commands to build, test and lint — because invoking them wrongly is the most common failure and the correct invocation is frequently not guessable. Decisions with a history: a linting rule you disabled deliberately, a library you rejected, a pattern you migrated away from. Boundaries: what must not change, what needs discussion first. And environment facts an agent cannot see — which distribution, which interpreter, whether SELinux is enforcing.
Does not belong. General language style the model already knows. Anything already enforced by a linter, since the linter is more reliable and the instruction is duplicated maintenance. Information that changes weekly, which will be stale before anyone notices. And anything that must be guaranteed — that is a permission flag.
Keeping instructions honest
Instruction files rot in a specific way: the project changes and the file does not, so it now describes something that was true. This is worse than having no file, because the agent follows it confidently.
Three habits keep them current.
Update instructions in the same pull request as the change. Migrating from
pip to uv means the instruction file changes in that pull request, not later.
Treating it as part of the change rather than follow-up work is the only version
of this that actually happens.
Read them when onboarding someone. If a rule needs explaining to a new colleague, it needs rewriting for the agent too — the ambiguity is in the text, not the reader.
Notice when you correct the agent. A correction you type twice is either a missing instruction or a broken one. That is the signal to act on, and it arrives naturally in the course of work.
Instructions and the other customisation surfaces
Instructions are one of four mechanisms, and conflating them causes people to reach for the wrong one.
Instructions are prose guidance loaded into context. They shape behaviour across the whole session and cost context window.
Skills are reusable SKILL.md capabilities, discovered from .github/skills/,
.agents/skills/, .claude/skills/, ~/.copilot/skills/ and ~/.agents/skills/.
A skill is a packaged procedure for a specific kind of task rather than a standing
rule.
Custom agents package a role with a restricted tool list. Where an instruction
says “do not modify files”, an agent whose tools list omits edit cannot. That
difference is the subject of the next lesson.
Hooks run at defined events, configured from .github/hooks/*.json. They
execute rather than advise, which makes them the enforcement mechanism of the four
— and also the one to review most carefully in someone else’s repository.
The rule of thumb: instructions for “usually do it this way”, agents for “this role has these capabilities”, hooks for “this must happen every time”, skills for “here is how to do this particular task”.
Instruction files are a security surface
An instruction file changes how an agent behaves. That is the feature, and it is also why one arriving in a pull request deserves review.
Consider what a malicious AGENTS.md could attempt: instructing the agent to
include a particular dependency, to skip a validation step, to treat a directory
as trusted, or to send data somewhere as part of “normal” workflow. None of that
is exotic; it is the intended mechanism used against you.
That last point is the practical one, and the GitHub Actions lesson develops it: a workflow triggered by a fork is running against a repository state the contributor controls, including any instruction files in it.
A worked example
Build the configuration for a small project.
Generate the base:
copilot initThen edit it down to what matters, add a path-scoped file for tests, and verify:
Which instruction files are you currently following, and what do they tell you to do before completing a code task?
Do not change any files.
Asking the agent to restate the rules is a genuinely useful check. If it cannot summarise them, they are not loaded, they are too long, or they are ambiguous — and all three are worth knowing before you rely on them.
Instructions across a team
A single developer’s instruction file is a convenience. A team’s is closer to shared infrastructure, and it behaves differently.
The main shift is that instructions become a place where conventions get decided rather than merely recorded. “Do not add dependencies without discussion” written into a repository file is a policy, and a colleague encountering it through an agent’s refusal is encountering it for the first time. That is worth being deliberate about — the file should say things the team has agreed, not things one person prefers.
The practical split is clean. Repository files carry team decisions and go through review like any other change. Personal instructions carry individual preferences about explanation style or output verbosity, and stay out of the repository entirely. When someone finds a repository rule wrong, the fix is a pull request, not a local override — which keeps the file matching reality.
Making rules the agent can act on
The difference between an instruction that changes behaviour and one that does not usually comes down to whether it names something concrete.
A rule that names a command works: “run .venv/bin/python -m pytest -q”. A
rule that names a path works: “only modify files under src/”. A rule that
names a defined action for a blocked case works: “stop and explain rather than
proceeding”.
Rules that name a quality do not: “write maintainable code”, “be careful with migrations”, “follow best practices”. These are not wrong, they are simply not actionable — there is no observation the agent can make that tells it whether it complied.
The test is whether you could check compliance yourself by looking at the output. If you cannot, neither can the model.
Common mistakes
Writing an essay. Long instruction files dilute. Eight rules that get followed beat forty that get averaged.
Vague rules. “Write clean code” is unfalsifiable. “Functions under 50 lines” can be checked.
Duplicating the model’s general knowledge. It knows PEP 8. It does not know that your team rejected a linting rule for a specific reason — write that.
Forgetting the file exists. Six months later, instructions describe a
framework you migrated away from. /instructions is how you find out, usually
after spending an hour wondering why the agent keeps suggesting something nobody
has used since spring.
Using instructions where permissions belong. “Never run terraform apply” in
an instruction file is a hope. --deny-tool='shell(terraform apply:*)' is a
guarantee.
Contradicting yourself across scopes. A repository file and a path-scoped file that disagree produce unpredictable behaviour, because both are supplied.
What to carry forward
Generate with copilot init, then cut it down.
Write rules that are checkable, specific, and short.
Use path-scoped files when conventions differ by area.
Use AGENTS.md nesting for monorepos.
Run /instructions and /env first when behaviour is unexplained.
Review instruction files as code, especially from outside contributors.
Use permissions for anything that must not happen. An instruction is advice the model usually takes; a denied tool is a rule it cannot decline.
A last framing that helps when deciding whether something belongs in a file at all. Instructions are the answer to “what would I tell a competent new colleague on their first day that they could not work out from reading the code”. That excludes language basics, which they know, and it excludes anything obvious from the repository, which they will read. What remains is the history, the constraints, and the commands — which is exactly the right content for the file.
Instructions and the context window
One practical constraint that shapes how long an instruction file should be: instructions occupy context. Every rule competes with the code the agent needs to read, and on a long session they compete with the conversation too.
A short, sharp file costs little and survives. A long one costs real room and, as
/compact summarises history over a long session, the details most likely to be
lost are exactly the specific rules you cared about.
/context shows the pressure. If a session is running close to full and the agent
has started missing instructions it followed earlier, the answer is usually to
compact deliberately or start fresh — not to restate the rule more forcefully.
Next
Custom agents is the natural progression: where instructions shape every session, an agent packages a role together with a restricted tool list, making the constraint structural rather than advisory.
The commands cheat sheet lists every configuration location the CLI reads, and the pillar covers how instructions relate to skills, MCP servers and plugins.
Sources
Every version-sensitive claim on this page was checked against first-party documentation. Only sources actually used are listed.
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.