MSBA-304 · Lesson 3 of 12 · 19 min

Custom instructions and prompt files

▶ Video coming soon A video version of this lesson is on the way.

By Friday, July 30, Dmitri had noticed a pattern. In almost every chat request he typed the same reminders: use Python type hints, use the team's error dictionary format, follow the date format in the report note, write tests with plain assert statements. "I am repeating myself to a machine," he said. Priya agreed that was a sign. Rules that apply to every request should not live in each prompt; they belong in custom instructions, which Copilot adds to the context automatically. Tasks that the team repeats, such as writing a test file in a set style, can be saved as prompt files and reused. This lesson covers both, plus agent instruction files such as AGENTS.md, and how the different kinds combine.

Three places instructions can live

Custom instructions are plain Markdown text that tells Copilot about your project and how you want it to work. They can be set at three levels. Personal instructions belong to one user and follow them across repositories, for example a preference for short answers. Repository instructions live in files in the repository and apply to anyone using Copilot there. Organization instructions, available on business plans, are set by owners and apply across the organization's repositories. When more than one set applies, Copilot receives all of them. GitHub's documentation gives personal instructions the highest priority, then repository instructions, then organization instructions, but it also recommends avoiding conflicts, because the model sees all the sets and may not resolve a clash the way you expect.

Three stacked bands feeding into a request. The top band is personal instructions, labelled highest priority. The middle band is repository instructions, split into three files: .github/copilot-instructions.md for the whole repository, .github/instructions/NAME.instructions.md files with an applyTo pattern for matching paths, and AGENTS.md files for agents. The bottom band is organization instructions. A separate box beside them, labelled prompt files in .github/prompts, connects to the request with a dashed arrow marked "only when you run one".
Where instructions come from, and how prompt files differ: instructions apply automatically, prompt files only when invoked.

Repository-wide instructions

The most common file is .github/copilot-instructions.md. Its contents apply to requests made in the context of the repository. Copilot Chat uses it, and so do the cloud agent and code review on GitHub.com. When chat uses the file, it appears in the list of references under the answer, which is a useful way to check that it was picked up. There is no special syntax; short, specific statements work best. GitHub ignores whitespace between instructions, so you can format them as a list.

Tidewater's .github/copilot-instructions.md for the trailcheck repository.
# TrailCheck: instructions for Copilot

## About the project
- TrailCheck is a Python 3.12 web app that shows trail conditions for Tidewater Trail Guides.
- Trail reports are single lines: date|trail|condition. See docs/report-format.md.

## How we write code
- Use type hints on every function and a one-line docstring.
- Parsers return a dict; errors are {"error": "<message>"} rather than exceptions.
- Dates are ISO 8601 (YYYY-MM-DD). Reject dates in the future.
- Use only the standard library unless requirements.txt already lists the package.

## Tests
- Tests live in tests/ and use pytest with plain assert statements.
- Every new function gets at least one normal case, one edge case and one error case.

## Never
- Never put credentials or real volunteer names in code, tests or examples.

Look at what the file contains: facts the model cannot infer (Python version, report format, where the format note is), team conventions (type hints, error dictionaries, ISO dates) and firm rules (no credentials or real names). It does not contain vague advice such as "write good code", which adds tokens and changes nothing. Priya kept the file to about thirty lines, because it is sent with every request and a long file crowds out other context.

Worked problem

Deciding what belongs in instructions

Dmitri listed six rules. Which belong in copilot-instructions.md, and which do not? (1) Use type hints. (2) Fix the bug in issue 214. (3) Dates are ISO 8601. (4) Be concise. (5) The API key is in config/secrets.toml. (6) Tests use pytest with plain asserts.

Show solution
  1. Rules 1, 3 and 6 are lasting project conventions, so they belong.
  2. Rule 2 is a single task; it belongs in a prompt or an issue, not in instructions.
  3. Rule 4 is a personal preference; it fits personal instructions better than repository ones.
  4. Rule 5 points Copilot at a secret; it must never be in instructions, and that path is excluded anyway.

Answer: Rules 1, 3 and 6. Tasks go in prompts, preferences in personal instructions, and anything about secrets stays out entirely.

Path-specific instructions

Some rules apply only to part of a repository. TrailCheck's data files have rules that make no sense for Python code, and its templates follow HTML conventions. Path-specific instructions handle this. They live in files named NAME.instructions.md inside .github/instructions/ (subfolders are allowed), and each starts with a short frontmatter block whose applyTo value is a glob pattern saying which files it covers. Several patterns can be separated by commas. When a file matches, Copilot uses both the path-specific instructions and the repository-wide file.

A path-specific instructions file: .github/instructions/data.instructions.md.
---
applyTo: "data/**/*.csv,data/**/*.txt"
---
# Trail data files
- One trail per line. Fields are separated by a vertical bar.
- Trail names use title case and match the names in data/trails.csv exactly.
- Never add or invent volunteer names; the volunteer column stays empty in examples.

GitHub's documentation notes an important limit: on GitHub.com, path-specific instruction files are currently used only by the Copilot cloud agent and Copilot code review, and support is described as limited. Editors such as VS Code also read them in chat and agent features. A frontmatter keyword, excludeAgent, can stop either the code review or the cloud agent from reading a particular file, for example when a rule is meant for writing code but would produce noisy review comments.

Agent instructions: AGENTS.md

Agents, which lesson 8 covers, also read instruction files. Copilot supports one or more AGENTS.md files anywhere in a repository, or a single CLAUDE.md or GEMINI.md at the root, so that teams using several agent tools can share one set of guidance. When an agent works on a file, the nearest AGENTS.md in the folder tree above it takes precedence, which lets a subfolder carry its own rules. Agent instructions usually describe how to build, test and check the project, because an agent that runs commands needs to know which commands are safe and which prove the work is done.

An AGENTS.md file telling agents how to build, test and when work counts as finished.
# AGENTS.md (repository root)

## Build and test
- Create a virtual environment and install requirements.txt.
- Run the tests with: pytest -q
- Run the data checks with: python tools/validate_data.py data/

## Done means
- All tests pass and the data check reports no errors.
- New code has tests; changed behaviour is described in CHANGELOG.md.

## Do not
- Do not edit files under data/archive/ or change requirements.txt without asking.

Prompt files

Prompt files are different in one key way: they are not applied automatically. A prompt file is a reusable Markdown template for a particular task, saved with the extension .prompt.md, usually in .github/prompts/. You run it on purpose from chat, by selecting or referencing it, when you want that task done. Prompt files can include placeholders for input and references to files that give context, so one template can be reused with different inputs. GitHub lists them as available in VS Code, Visual Studio, JetBrains IDEs and Xcode, and its customization library describes them as being in public preview, so details may change.

A prompt file, .github/prompts/write-tests.prompt.md, with an input placeholder for the function name.
---
description: "Write pytest tests for a TrailCheck function"
---
Write pytest tests for the function I name below, following
.github/copilot-instructions.md and the examples in tests/test_parse.py.

Function: ${input:function_name}

Include:
- at least two normal cases taken from docs/report-format.md
- edge cases: empty string, extra spaces, upper-case condition
- error cases that check the exact error dictionary
Put the tests in tests/test_${input:function_name}.py and do not change the function.

Treat the exact frontmatter fields and placeholder syntax as editor details that can change; the concept is what matters. Instructions answer "how do we always work here?" Prompt files answer "how do we do this particular task well?" Tidewater started with three prompt files: write tests, explain a module for a newcomer, and draft a changelog entry.

Instructions and prompt files compared.
FeatureAppliesWhere it livesGood for
Personal instructionsAutomatically, for one userUser settingsAnswer length, preferred language for explanations
Repository instructionsAutomatically, in the repository.github/copilot-instructions.mdProject facts and conventions
Path-specific instructionsAutomatically, for matching files.github/instructions/*.instructions.mdRules for data, templates or a subproject
Organization instructionsAutomatically, across the organizationOrganization settingsCompany-wide rules such as no real customer data
Agent instructionsAutomatically, for agentsAGENTS.md, or CLAUDE.md or GEMINI.md at the rootBuild, test and done criteria
Prompt filesOnly when you run one.github/prompts/*.prompt.mdRepeatable tasks

Measuring the effect

Priya wanted evidence that the instructions file helped, not just a feeling. For a week before adding it, Dmitri had kept a tally of chat answers that needed a follow-up because they ignored a team convention. He kept the same tally for a week after.

Python Example · Comparing how often answers ignored team conventions before and after the instructions file.
before = {"answers": 46, "needed_fix": 19}
after = {"answers": 51, "needed_fix": 7}
for label, week in (("before", before), ("after", after)):
    share = week["needed_fix"] / week["answers"]
    print(label, "needed a follow-up:", round(share * 100), "in 100")
change = before["needed_fix"] / before["answers"] - after["needed_fix"] / after["answers"]
print("fall:", round(change * 100), "in 100 answers")
Output
before needed a follow-up: 41 in 100
after needed a follow-up: 14 in 100
fall: 28 in 100 answers

What this code does

The example takes two weeks of Dmitri's tallies: how many chat answers he received and how many needed a follow-up because they broke a team rule. For each week it divides the second number by the first to get a rate per 100 answers, then subtracts to show the change. The output shows the rate falling from about 41 to about 14 answers in 100, a drop of about 28 in 100, which suggests the instructions file was doing its job.

Two weeks of one person's tally is a small sample, and Dmitri was also getting better at prompting, so the improvement is not all due to the file. It was still a large enough change to justify keeping the file and adding the path-specific one for data.

Organization instructions and personal instructions in practice

Tidewater is small, but Rosa still set one organization instruction for every repository: never use real volunteer or customer names, addresses or phone numbers in code, tests, examples or documentation, and use invented data instead. The rule came from the privacy advice the owners received about the volunteer list in the first course, and putting it at organization level meant it applied even in repositories nobody had written instructions for yet. Personal instructions were left to each person. Dmitri set his to ask for short answers with code first and explanation after; Lena set hers to explain unfamiliar terms, because she was still learning the Moncton team's codebase. Because personal instructions have the highest priority, the two of them could ask the same question in the same repository and get answers shaped differently, both following the same project rules.

Maintaining instructions

Instructions are code-adjacent documents and should be treated like code. Tidewater put .github/ under the same rules as the rest of the repository: changes go through a pull request, the code owners for the folder are Priya and Dmitri, and a reviewer checks that a new rule is specific, true and not in conflict with another file. When the project changes, for example a move to a newer Python version, the instructions change in the same pull request. Stale instructions are worse than none, because they confidently steer Copilot toward the old way.

A quick check that instructions are working is to ask chat a question whose answer depends on a rule, such as "write a parser for the volunteer roster line format", and look for two things: the instructions file listed among the references under the answer, and the rule actually followed in the code. If the file is listed but the rule is ignored, the rule is probably too vague or contradicted elsewhere. If the file is not listed at all, check its path and name, because a file saved as .github/copilot_instructions.md or outside the .github folder will simply not be found.

Copilot can help write the first draft. GitHub's cloud agent can be asked to generate a copilot-instructions.md by studying a repository, and in editors you can ask chat to propose instructions based on the codebase. Priya used that as a starting point and then cut the draft by half, removing anything generic.

Common mistakes

  • MistakeTyping the same team rules into every prompt.

    InsteadPut lasting conventions in .github/copilot-instructions.md.

  • MistakeWriting long, vague instructions such as "write high quality code".

    InsteadKeep instructions short, specific and checkable.

  • MistakePutting a one-off task in the instructions file.

    InsteadUse a prompt or a prompt file for tasks.

  • MistakeExpecting a prompt file to apply automatically.

    InsteadPrompt files run only when you invoke them.

  • MistakeLetting personal, repository and organization instructions contradict each other.

    InsteadAvoid conflicts; all sets are sent to the model.

Summary and key terms

  • Custom instructions are Markdown guidance that Copilot adds to requests automatically.
  • Personal, repository and organization instructions can all apply; personal has the highest priority, but conflicts should be avoided.
  • .github/copilot-instructions.md covers the whole repository and is used by chat, the cloud agent and code review.
  • Path-specific .instructions.md files use an applyTo glob; on GitHub.com they are used by the cloud agent and code review.
  • AGENTS.md files give agents build, test and done criteria; the nearest file takes precedence.
  • Prompt files (.prompt.md) are reusable task templates that run only when invoked.
Custom instructions
Guidance in Markdown that Copilot includes with requests automatically.
applyTo
The frontmatter value in a path-specific instructions file that lists the file patterns it covers.
AGENTS.md
An instructions file for AI agents; the nearest one in the folder tree takes precedence.
Prompt file
A reusable task template with the .prompt.md extension, run on demand.
Frontmatter
A short block of settings at the top of a Markdown file, between lines of three hyphens.

Practice problems

Work each problem on paper first, then reveal the answer to check.

  1. Where does repository-wide guidance for Copilot go?

    Show answer

    In .github/copilot-instructions.md.

  2. What is the difference between an instructions file and a prompt file?

    Show answer

    Instructions apply automatically to requests in their scope; a prompt file is a task template that runs only when you invoke it.

  3. How can a path-specific instructions file be kept away from code review?

    Show answer

    Add excludeAgent with the value "code-review" to its frontmatter.

Lesson quiz · 5 questions

Score 60% or more to complete this lesson.

Take the quiz