GitHub Copilot Context: How to Give Copilot Better Information
Most disappointing Copilot output is not a prompting failure. It is an information failure: the model answered well, given what it could see, and what it could see was wrong or incomplete.
That reframing changes what you do about it. A wrong answer produced from good evidence is a reason to try a different model or a sharper prompt. A wrong answer produced from absent evidence is a reason to supply the evidence, and no amount of rewording substitutes.
Key takeaways
- Relevant context beats maximum context. Supplying a whole module when three functions carry the problem dilutes the signal and degrades the answer.
- Context is not one thing: what you supply, what the surface adds automatically, what persists in instruction files, and what is simply absent.
- The category that causes most trouble is the fourth. A model reasoning from incomplete information produces a confident answer, not an error.
- Attention across a long context is uneven. A bigger window buys headroom, not uniform recall.
- Whatever you paste is sent for processing. Redact at paste time rather than judging at send time.
The four kinds of context
What you supplied is the part you control completely: a selection, a file you attached, an error you pasted. Reliable, because you chose it.
What the surface added varies by where you are. An IDE knows your open file and your selection. Repository-aware surfaces can search the codebase. The CLI reads files within its allowed paths. This layer is helpful and only partly visible to you, which is the source of most “why did it think that” moments.
What persists is instruction files — repository, path-specific and personal. Always in scope within their scope, which is exactly why they must be short.
What is absent is the interesting category. Your ticketing system. The Slack thread where the decision was made. The reason the previous developer wrote it that way. The current state of your database. The fact that this endpoint is public.
Relevant beats maximum
The instinct is that more context is safer. It is not, and understanding why changes how you work.
Signal gets diluted. A model given a 4,000-line file to find one bug has to locate the relevant part before reasoning about it. Given the three relevant functions, it starts from the reasoning. The first version is doing strictly more work for a strictly worse result.
Attention is uneven. Every model attends less reliably to the middle of a long context than to either end. This is true regardless of the advertised window size, and it means the important detail buried in the middle of a large paste is the detail most likely to be missed.
Context is finite and shared. Everything competes: your instruction files, the conversation history, tool output, and the code under discussion. Filling it with a repository dump is spending a budget on material that is not helping.
The useful instinct is evidence selection. Assemble what you would put in front of a colleague: the error, the function, the failing test, the expected behaviour. Not the repository.
What each surface can see
Automatic context differs by where you are working, and assuming otherwise produces a specific confusion: a colleague’s identical prompt getting a better answer because their surface supplied something yours did not.
IDE chat has the strongest automatic context for the code you are looking at. Your open file and your selection are available, and the client can search the workspace. This is why the same question often works better in an editor than elsewhere — you have supplied context without noticing.
GitHub.com chat works from repository context rather than editor state. There is no “current file” and no selection, so anything you would have relied on being implicit has to be named.
The CLI reads within its allowed paths — by default the working directory and its subdirectories. It can run commands, which means it can generate context rather than only receive it: reading a file, running a test, checking a service. That is a genuine difference in kind rather than degree.
The cloud agent works from the repository on GitHub’s infrastructure. Nothing local is available to it, which includes your uncommitted changes.
Code review sees the diff. That is a narrower view than it sounds, and it explains a characteristic limitation covered in Cluster 5: review cannot see absences. A missing authorisation check does not appear in a diff, so it is not in the review’s context at all.
Selection is the sharpest tool available
Where a surface supports selecting code before asking, that is the highest signal-to-noise context there is — and it is underused.
A selection says “this, specifically” in a way that no amount of description matches. It removes the search step entirely, and it bounds the problem in a way that discourages scope expansion: an agent given three functions is much less likely to propose restructuring a module than one given the module.
Three ways to use it well.
Select the smallest thing that contains the problem. If the bug is in one function, select that function rather than the class.
Select the thing you want changed, not the thing that is broken, when those differ. If a caller is misusing an API, selecting the caller is usually more productive than selecting the API.
Combine selection with a named file. “Fix the selected function, following
the pattern in handlers/update.py” gives both precision and an example.
Context and cost
There is a practical dimension people notice only when their allowance runs low.
Larger context costs more to process, but the more significant effect is indirect: bad context produces answers that need correcting, and each correction is another request. A well-supplied first attempt that lands costs one; a vague first attempt plus three rounds of clarification costs four.
That arithmetic is the strongest efficiency argument in this cluster, and it points the same way as the quality argument. Assembling evidence before asking takes thirty seconds and routinely saves three exchanges.
The corollary is worth stating too: an agentic session that has accumulated a large context is spending that on every subsequent turn, not once. A long conversation is not just at risk of drift — it is more expensive per exchange than a fresh one.
Context for debugging
Debugging is where context discipline pays most, because the evidence is objective and the failure is expensive.
Six things belong in a debugging request:
The exact error. Not a description of it. Paste the traceback, the assertion failure, the exit code. A described error is a lossy summary, and the lost part is frequently the part that mattered.
Where it happens. File and function names, not “in the user service somewhere”. Naming makes the model read; describing makes it search.
What you expected. The half people skip. “This returns 500” does not say whether 404, 200 or an empty list was correct.
What actually happens. Including the parts that are working, since those bound the problem.
What changed recently. If it worked last week, that is the strongest available clue and it is usually omitted.
Relevant versions. Language, framework, key dependencies. Behaviour differs between versions and the model cannot see your lockfile unless you show it.
This FastAPI endpoint returns HTTP 500 when the customer record does not exist. It should return 404 with a JSON body whose “detail” field reads “Customer not found”.
Relevant files:
- app/routes/customers.py
- app/services/customers.py
- tests/test_customers.py
The traceback:
[paste the actual traceback]
This worked before we moved lookup into the service layer last week.
Do not change the database schema. Explain the root cause before modifying any code.
Compare that with “why doesn’t this work?”. The second version is not politer or more detailed for its own sake — every line removes an assumption the model would otherwise have to make.
Bounding what you paste
Log output is the most common way context gets flooded, and it is easy to bound before it reaches the model rather than after.
journalctl -u nginx --since "1 hour ago" -p err --no-pager | tail -100Three bounds in one command: time, severity, volume. Each narrows before the data becomes context rather than after.
The same applies to test output — a single failing test rather than the whole
suite — and to diffs, where git diff -- src/parser.py beats the full branch
diff when you know where the problem is.
Making absent context present
The highest-value context is often the kind that exists nowhere in your codebase.
Intent. Why this code exists, what it is for, what the constraints were. If the model can only see what the code does, it will optimise for that and cheerfully break a requirement nobody wrote down.
Environment. Which distribution, which package manager, which Python. The
Linux lesson covers what happens when this is
missing: confident advice using apt on a Fedora host, or chmod fixes for a
problem that is actually SELinux.
Constraints you take for granted. “We cannot add dependencies.” “This runs on a machine with 512 MB.” “The database is read-only from this service.” Each of these is obvious to you and entirely invisible in the code.
History. “We tried the obvious approach and it deadlocked” saves the model proposing the obvious approach, and saves you the exchange in which you explain why it will not work.
Anything in that list you supply more than twice belongs in an instruction file rather than in every prompt. That is the whole relationship between this lesson and the instructions ones: instructions are context you stopped retyping.
Examples as context
Pointing at existing code conveys conventions more precisely than describing them, and it costs less.
Add a delete_customer handler.
Follow the structure of update_customer in the same file: same
validation approach, same error handling, same logging, same
docstring format.
Describing your error-handling convention takes a paragraph and is still ambiguous. Naming a function that demonstrates it is exact. This works for anything with an established pattern — tests, migrations, API handlers, components.
It also degrades gracefully: if the referenced example is not quite right, the result is visibly modelled on it and easy to correct.
Context in agentic sessions
An agent accumulates context whether you intended it or not: conversation history, every file it read, the output of every command it ran. A session that started focused becomes crowded.
Three consequences.
Constraints decay. The classic symptom is an agent following a rule for twenty turns and then not. That is usually context pressure, not disobedience, and rewriting the rule more forcefully does not fix it.
Output volume matters. A verbose test run can consume a meaningful fraction of
the window on information nobody needs. -q flags earn their place.
Fresh sessions are cheap. When a conversation has drifted, restating the problem in a clean session frequently beats continuing to patch — you carry forward what you learned rather than everything you tried.
In the CLI, /context shows usage and /compact reclaims room with focus
instructions. Those are covered in
Cluster 5’s command reference.
Context engineering as a discipline
“Context engineering” sounds like a rebrand of prompt engineering. It is a genuinely different activity, and the distinction is worth holding.
Prompt engineering asks: how do I phrase the request? Context engineering asks: what does the model need to see in order for any phrasing to work?
The second question has better answers, because it is about assembling evidence rather than finding words. Evidence is objective — a file either was supplied or was not, an error either was pasted or was described. Phrasing is a matter of degree and it hits a ceiling fast.
In practice the discipline is three habits.
Ask what is missing before asking again. When an answer is wrong, the first question is not “how should I have phrased that” but “what did it not have”.
Supply evidence, not descriptions. The traceback rather than the summary. The function rather than the account of what the function does. The failing test rather than the assertion that a test fails.
Move recurring context into files. Anything you supply twice is a candidate; anything you supply weekly is overdue. That transition — from retyping to configuration — is the point at which people stop finding Copilot frustrating, and it is available to anyone who notices they are repeating themselves.
A worked comparison
The same problem, asked two ways, to make the difference concrete.
The tests are failing. Can you fix them?
Everything is absent. Which tests, what failure, whether the tests or the code are wrong, what “fixed” means. A model answering this must guess at all four, and its most likely guess — edit whatever makes the assertion pass — is the outcome you least want.
tests/test_parser.py::test_handles_empty_input is failing:
[paste the actual failure output]
The test is correct: parse("") should raise ValueError. The implementation returns None instead.
Fix the implementation, not the test. Do not change the function signature.
Then run the full suite and show me the real output.
Same problem. The second version names the test, supplies the failure, resolves the ambiguity about which side is wrong, states the constraint, and defines the check. What remains for the model is the part it is genuinely good at.
Notice that the second version is not more elaborately worded. It is the same plain English carrying more information — which is the entire distinction this lesson is about.
What should never be context
Everything you paste is sent for processing. That is not a reason for anxiety; it is a reason for a habit.
For agentic sessions specifically, the CLI’s --secret-env-vars strips named
environment variables from what commands see and redacts them from output, which
is worth setting before a debugging session that will print environment state.
Diagnosing a context problem
When output is wrong, these questions separate a context failure from the other kinds, in the order worth asking.
Did it reference something that does not exist here? An API, a file, a convention that is not yours. That is the signature of a model working from training data because it could not see your code. Name the files.
Did it ignore something you thought was obvious? Obvious to you, invisible to it. Check whether the thing was actually supplied — the open file in your editor is not necessarily in scope on every surface.
Did it contradict an instruction file? Check the file is loaded and that the surface supports that mechanism. The support matrix is narrower than people expect, and a rule in an unsupported mechanism was never in force.
Did it start well and drift? Context pressure in a long session.
Was it confidently wrong about a fact? Frequently an assumption filling an absent piece of context. Ask what it assumed — models answer that question honestly and it is diagnostic.
Common mistakes
Pasting everything. The instinct that more is safer. It dilutes signal, consumes the window, and buries the detail that mattered.
Describing instead of showing. “It throws an error” versus the traceback. The summary loses exactly the part you did not understand well enough to summarise.
Assuming automatic context. Relying on the open file being in scope works until you change surface or write a prompt someone else runs.
Supplying the same context repeatedly. That is what instruction files are for, and retyping it means it applies only when you remember.
Forgetting to say a view is filtered. A model shown errors only will conclude there were only errors.
Pasting production output unreviewed. Tracebacks and logs carry credentials more often than anyone expects.
Next
Team coding standards is the capstone — turning the context you keep resupplying into files a team owns.
Custom instructions is where recurring context belongs, and the pillar puts context alongside the other four levers that determine output.
Put this into practice
5-minute exercise
Fix a bad suggestion with context instead of a better prompt
- Find a request where Copilot produces something that does not fit your codebase.
- Do not reword the prompt.
- Open the type definitions, interface or schema the answer should respect.
- Ask again, unchanged.
How you know it worked The answer improved without the prompt changing. That is the whole argument for context discipline, and it is more convincing once you have seen it.
Sources
Every version-sensitive claim on this page was checked against first-party documentation. Only sources actually used are listed.
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.