The last lesson taught you to give an agent tasks and to review its commands. This lesson covers three things that belong together: you tell Copilot once, in the repository, how work is done at your place (instruction files). You let Copilot read pull requests too, without relying on it (code review). And you have tests generated and prove that they check something. The common thread: generated code is foreign code that arrives fast. It needs the same review as a colleague's, only more often.
The course assumes W3.1 and W3.2.1, plus from K2 the lesson "Reviews that help", the tests with xUnit (lesson "Unit tests for rules and endpoints") and the
rule for overlapping appointments in the Kladde. The rule lives in TimeRange from K1 and is a single line:
public bool Overlaps(TimeRange other) => Start < other.End && other.Start < End;
Two time ranges overlap if each begins before the other ends. An appointment until 10:00 and one from 10:00 only touch. Whoever creates an appointment like that
gets no error message. Whoever overlaps gets appointment.time.overlaps and the status 409 (K2). You practice on this line in the
second exercise.
As in the last lesson: no author has run the exercises with Copilot in the editor, every surface was read against the documentation. Code that Copilot "generates" in this lesson is an example of generated code, not the output of a run: it was written by hand and contains deliberate flaws. What your Copilot generates looks different, and that is exactly why you review it.
Instruction files
Without instructions, Copilot knows your rules only as far as the context shows them (W3.1.2). An instruction file is context that goes along with every request: how we build and test, which names apply, what is forbidden. According to GitHub's documentation ("Adding repository custom instructions"), there are three forms.
| File | Applies to | Special feature |
|---|---|---|
.github/copilot-instructions.md |
the whole repository | Markdown, one document for everything |
.github/instructions/NAME.instructions.md |
the files that the header entry applyTo names |
applyTo is a glob pattern, several separated by commas; excludeAgent takes "code-review" or "cloud-agent" |
AGENTS.md |
the folder it is in, and below | the nearest file in the directory tree applies |
Further points, as the documentation states them:
- Order of precedence: personal instructions before the repository's instructions before the organization's instructions. All are sent; the order of precedence decides whose word counts in a contradiction, it does not switch the others off. If two contradict each other, the result is not reliable: avoid contradictions instead of relying on the order of precedence.
- In chat they apply as soon as the file is saved.
- Code review reads them from the head branch of the pull request, that is, from the branch with the changes. Whoever changes the instructions in the same pull request changes the review of that pull request.
- The path-specific files apply on github.com only to the cloud agent and to code review.
What the pages that were read do not say, this course states openly: a size limit for the files was not stated there. And prompt files (reusable prompts in a file in the repository) the course does not cover in detail; whether and how your editor supports them is in its documentation.
What belongs in an instruction file
An instruction file is not a speech to the model but a short set of rules. It helps if every line is concrete and checkable.
| Good | Bad |
|---|---|
"Test methods are named in PascalCase without underscores, for example ATimeThatOverlapsIsRefused." |
"Write clean code." |
"Tests start with dotnet test --project tests/Kladde.Core.Tests." |
"Test thoroughly." |
| "Times are half-open: the end is not part of the range. An end at 10:00 does not overlap with a start at 10:00." | "Watch out for time zones." |
"Errors come as a code such as appointment.time.overlaps with the status fixed in K2, never as free text." |
"Handle errors correctly." |
| "Credentials are never in code or in tests." | "Be secure." |
And what does not belong in it: secrets (the file is in the repository and goes to the model), instructions that a tool already enforces (the formatter takes care of formatting), and wishes that you cannot check. An instruction file is a team's document: you change it by pull request, and somebody reads it.
An instruction file for the Kladde, written by hand and meant as a starting point for the exercise (not generated by Copilot):
# Kladde: instructions for GitHub Copilot
- Code and comments are English. Texts shown to people are German or English from the resource files.
- Build and test: `dotnet test --project tests/Kladde.Core.Tests`. Say which project you ran.
- Time ranges are half-open: `Overlaps` is `Start < other.End && other.Start < End`. Touching ranges do not overlap.
- Business errors use codes like `appointment.time.overlaps`, never free text.
- Tests: xUnit, method names in PascalCase without underscores, one behaviour per test.
- Tests never read the clock: pass the time in (`TimeProvider` or a parameter), never `DateTime.Now`.
- Never put keys, passwords or connection strings in code, tests or examples.
- Commit messages follow Conventional Commits.
Along with it, a path-specific file for tests only, .github/instructions/tests.instructions.md:
---
applyTo: "tests/**/*.cs"
---
- Every test states the rule it protects in its name.
- Check the boundary on both sides: exactly on it, just before, just after.
- An assertion must be able to fail: never compare a result with a copy of the code under test.
Whether the pattern in applyTo is written exactly the way you need it for your folders, you find in the documentation: the example is a draft, not run against
Copilot.
Checking whether the file works
Whether Copilot follows an instruction is not a guarantee but a probability. Check it with two tasks: one where the rule must apply ("Write a test for
Overlaps", the file demands boundary cases and no clock), and a control run without the file. If there is no difference, the instruction is too vague or is not
loaded. Then check whether the file is saved, whether it is in the right place and whether the editor picks it up. In the answer, look up which files are named as a source,
if your editor shows that.