Most advice about getting better output from Copilot is advice about phrasing. Be specific. Give it context. Ask it to think step by step.
That plateaus quickly, and it plateaus for a structural reason: better phrasing asks the model to try harder. It does not tell the model anything it did not already know.
The thing that actually moves output is a file. .github/copilot-instructions.md, committed to the repository, read on every request.
.github/copilot-instructions.md
Inside the .github directory, not the repository root. Plain Markdown, no frontmatter required. That is the whole setup.
Compare these two:
- Write clean, maintainable code.
- Use proper error handling.
- Money is `Decimal`, never `float`. Round half-up to two places at the
response boundary only, never mid-calculation.
- All datetimes are timezone-aware UTC. `datetime.utcnow()` returns a naive
datetime and will compare incorrectly against everything else here.
The first pair costs context on every request and changes nothing — the model already agrees with both, and agreeing is not the same as knowing what you meant.
The second pair changes the output, because it contains information the model did not have: a fact about your codebase that is not inferable from the code it can see.
Three properties, and a rule wants all three:
Durable. True next month. Anything task-shaped belongs in a prompt, not here.
Specific. datetime.utcnow() returns a naive datetime — not "handle timezones correctly".
Checkable. Somebody can look at a diff and say whether the rule was followed.
"Do not use datetime.utcnow(); it returns a naive datetime and this codebase compares against aware ones."
gets followed.
"Use timezone-aware datetimes."
gets agreed with, and then not done.
The difference is that the first one names the specific thing to avoid and says why. Give a reason and the rule survives contact with a situation you did not anticipate.
Eight rules that get followed beat forty that get averaged.
The file is prepended to requests, so a 400-line instruction file is a tax on every interaction and it dilutes the rules that matter among the ones that do not. If you keep only five lines, keep the non-obvious ones.
Delete anything a tool already enforces. If ruff fails the build on import order, do not spend a line on import order. Say it once, in the place that can actually reject the change.
The pattern holds outside application code, and infrastructure is where it pays best because the mistakes are more expensive.
Terraform:
- for_each for collections; count only for on/off conditionals. count is
positional, so removing the second of three items destroys the third.
- Every variable has a type, a description, and a validation block where
the value is bounded.
- No hardcoded region, account id or ARN.
Kubernetes:
- Every container sets resources.requests and resources.limits.
- Three probes, pointing at different endpoints. A liveness probe that
duplicates readiness turns a slow dependency into a restart loop.
- Images pinned by digest. :latest is not deployable here.
GitHub Actions:
- Never interpolate anything under github.event into a run: block. Pass it
through env:.
- permissions: contents: read at workflow level, widened per job.
- Third-party actions pinned to a full commit SHA, never a tag.
Each of those is a defect class that is invisible in review because the wrong version looks exactly like the right version.
It is committed and reviewed like code.
That sounds administrative and it is the most useful property of the whole mechanism. Your conventions stop being a thing one person prefers and become a thing the team agreed to, in a file with a history, changed by pull request.
I have watched a fifteen-minute argument about a convention end with "put it in the instructions file" — not because the file settled the argument, but because it turned a preference into a proposal somebody had to approve.
Open the file. Write three rules about your codebase that a competent new joiner would get wrong in their first week. Not style. Not anything the linter catches. The three things that are true of this repository and not obvious from reading it.
That will take ten minutes and outperform every prompt-engineering tip you have read, including this one.
Full lesson — including path-specific instruction files, the precedence order when several apply, and which surfaces read which file — at GitHub Copilot custom instructions. The stack-specific examples above are condensed from longer ones on The Copilot Stack.