Fixing GitHub Copilot Suggestions That Miss Your Codebase Context
You accept a Copilot suggestion, run the code, and immediately notice it used a pattern your team abandoned six months ago. Or it generated a function that duplicates one that already exists three files away. GitHub Copilot is powerful, but its suggestions are only as good as the context it can see β and by default, that context is surprisingly narrow.
The good news: you can systematically fix this. Most developers treat Copilot as a black box and complain when it misses. The ones getting the most out of it are actively shaping what it sees.
What You'll Learn
- How Copilot's context window actually works and what it reads
- Which files to keep open to steer suggestions toward your patterns
- How to write comments and docstrings that act as inline prompts
- How to use
.github/copilot-instructions.mdfor project-wide rules - Common mistakes that cause Copilot to ignore your conventions
Why Copilot Keeps Getting It Wrong
Copilot doesn't read your entire codebase. It reads a sliding context window that includes your current file, a selection of recently opened files, and whatever you've typed immediately above the cursor. That's it. If your core abstractions, base classes, or shared utilities aren't visible in that window, Copilot has no idea they exist.
This is the root cause of most bad suggestions. Copilot isn't being dumb β it's completing code the way any reasonable developer would if they were dropped into a single file with no other context. The fix is deliberate context management, not hope.
How Copilot Actually Reads Your Code
Copilot uses a process sometimes called "prompt stuffing" β it assembles a prompt from multiple sources before sending it to the model. The exact algorithm isn't public, but from observable behavior and GitHub's own documentation, the context includes:
- The current file β everything above and some content below the cursor
- Open editor tabs β recently open files are sampled and included if they fit
- The file path and name β signals the file's purpose and language
- Import statements β Copilot infers available APIs from what's imported
- Copilot Chat conversation history β when using Chat, prior messages persist
Importantly, Copilot does not do a semantic search across your whole repo the way some newer tools do. It doesn't read your README automatically unless you have it open. Understanding this limitation is the first step to working around it.
Use Open Files Strategically
Because open tabs are sampled into context, the files you have open in your editor matter. This is the single fastest fix most developers miss.
Before writing a new service, open the existing service files that follow your team's pattern. Before adding a new database query, open a file with your established query style. Copilot will mirror those patterns because it literally sees them.
# Productive tab layout when adding a new API endpoint:
- routes/users.py (existing route you want to mirror)
- services/user_service.py (service pattern to follow)
- models/user.py (model structure)
- your new file: routes/orders.py <-- cursor here
Keep your "reference" files open even if you're not actively editing them. You don't need to switch to them β just having them in open tabs feeds them into Copilot's prompt assembly.
Close files you don't want influencing suggestions. If you have a legacy file open that uses deprecated patterns, it might pull Copilot toward those patterns.
Write Copilot-Readable Comments and Docstrings
A well-placed comment is one of the most effective context signals you can give Copilot. Think of comments not just as documentation for humans, but as inline prompts for the model.
Be specific about intent, expected inputs, and any constraints. Vague comments produce vague suggestions. Compare these two approaches:
# Bad: too vague
# get user data
# Good: specific enough for Copilot to match your patterns
# Fetch user by ID from PostgreSQL using the async SQLAlchemy session.
# Raises UserNotFoundError if the user does not exist.
# Returns a UserSchema Pydantic model.
async def get_user_by_id(user_id: int, session: AsyncSession) -> UserSchema:
The detailed comment tells Copilot which ORM you use, that the function is async, which error type to raise, and what return type to use. It will complete the body in a way that matches all of those constraints. You can also mention your team's specific conventions directly:
# Following our repository pattern: use self._session, not the global session.
# Log errors via self._logger.error() before raising.
def delete_order(self, order_id: int) -> None:
Leverage the .github/copilot-instructions.md File
GitHub Copilot supports a repository-level instruction file at .github/copilot-instructions.md. This file is automatically picked up by Copilot Chat and β depending on your editor version β inline completions too. It's the closest thing to project-wide custom instructions.
Use this file to declare your stack, conventions, and patterns once, rather than repeating them in every comment. A solid instructions file might include:
# Project Conventions for Copilot
## Stack
- Backend: Python 3.12, FastAPI, SQLAlchemy 2.x (async), Pydantic v2
- Database: PostgreSQL 16
- Testing: pytest with pytest-asyncio; all tests must be async
## Naming
- Services are suffixed with `_service.py` and contain business logic only
- Routers are suffixed with `_router.py` and contain no business logic
- Database models live in `models/` and are prefixed with `Db` (e.g., DbUser)
## Patterns
- Always use the async repository pattern; never call session directly from a router
- Raise domain-specific exceptions from services, not HTTPException
- All new endpoints must have a corresponding pytest test in tests/routers/
This file does real work in Copilot Chat β when you ask it to generate a new endpoint, it will consult these instructions and produce output that actually follows your structure. Treat it like a short onboarding guide for an AI pair-programmer joining your team.
If you're interested in how AI assistants can be guided through structured instructions more broadly, the approach is similar to how you'd configure a tool like Claude Code for daily software engineering workflows β the principle of giving the model explicit, written context applies across tools.
Use Inline Prompts to Anchor Suggestions
Copilot Chat's inline mode (activated with Ctrl+I / Cmd+I in VS Code) lets you describe exactly what you want in natural language before it generates. This is far more reliable than hoping inline completions pick up enough context passively.
When using inline prompts, reference your conventions explicitly. The more specific you are, the better the output:
# Weak inline prompt:
Add a function to get orders for a user
# Strong inline prompt:
Add an async function `get_orders_for_user(user_id: int, session: AsyncSession)`
that queries the DbOrder model, filters by user_id, returns list[OrderSchema],
and raises OrderNotFoundError if no orders exist. Follow the repository pattern
used in services/user_service.py.
Notice the reference to services/user_service.py β if that file is open in a tab, Copilot can look it up and mirror its patterns directly. The combination of a specific prompt plus relevant open files produces results that need much less editing.
Structure Your Project So Copilot Can Follow It
Copilot infers a lot from file names and directory structure. A well-organized project is easier for both human developers and AI tools to navigate. A few structural practices that improve suggestion quality:
Consistent file and function naming
If your service files are consistently named user_service.py, order_service.py, and payment_service.py, Copilot will recognize the pattern and generate code in the same shape when you create invoice_service.py. Inconsistent naming breaks the pattern and produces inconsistent suggestions.
Colocate related files
Keep your model, schema, service, and router for a given domain near each other, or at least with consistent naming. When these are open together, Copilot sees the whole slice of your application and suggests code that wires them up correctly.
Type annotations everywhere
Type hints are one of the richest signals Copilot can read. A function signature with full annotations tells Copilot exactly what types flow in and out. Without them, it guesses β and often guesses wrong. If you're working in Python, TypeScript, or any typed language, annotations directly improve completion accuracy.
# Copilot will complete this much more accurately with full type hints:
async def create_invoice(
user_id: int,
line_items: list[LineItemSchema],
session: AsyncSession
) -> InvoiceSchema:
...
Common Pitfalls That Confuse Copilot
A few patterns reliably cause Copilot to produce off-target suggestions. Watch for these:
- Huge files with mixed concerns. If your file is 1,500 lines and mixes data access, business logic, and HTTP handling, Copilot sees an inconsistent set of patterns and produces inconsistent results. Split the file β it helps Copilot and your codebase.
- Stale or contradictory comments. A comment that says "use the v1 API" in a codebase that has moved to v2 will confuse Copilot. It tries to reconcile both. Keep comments current.
- Generic variable names. Variables like
data,result, orobjgive Copilot nothing to work with. Names likeuser_profile,paginated_orders, orinvoice_line_itemscarry semantic information it can use. - Working in a fresh file with nothing open. Opening a blank file and expecting Copilot to guess your stack is unreliable. At minimum, add your imports first β they tell Copilot exactly what libraries and patterns you're using.
- Ignoring the Chat interface for complex tasks. Inline completions are best for short, predictable tasks. For generating a full class, a test suite, or refactoring a function, use Copilot Chat with a detailed prompt. The two modes have different strengths.
Prompt engineering discipline matters here just as much as in any other AI workflow. If you find yourself constantly editing Copilot's output, that's a signal your prompts and context setup need attention β not that the tool is broken.
Wrapping Up: Next Steps
Copilot's suggestions reflect what it can see. Give it better inputs and you get better outputs β consistently. Here's what to do right now:
- Create or update
.github/copilot-instructions.mdin your repo with your stack, naming conventions, and key patterns. Even 20 lines makes a measurable difference in Chat quality. - Audit your open tabs before starting a feature. Make a habit of opening 2β3 reference files that represent the patterns you want Copilot to follow.
- Add type annotations to your function signatures if you haven't already. This is one of the highest-ROI changes you can make for completion accuracy.
- Switch to inline prompts for anything non-trivial. Use
Cmd+I/Ctrl+Iand write a specific, constraint-rich description instead of waiting for passive completions to guess right. - Refactor files that are too large or mixed. Copilot performs better in focused, single-responsibility files, and so does your team.
Copilot works best when you treat it as a context-sensitive tool rather than a mind reader. The developers getting the most value from it are the ones who invest a few minutes in setup and stay deliberate about what they leave open on their screen.
Frequently Asked Questions
Why does GitHub Copilot suggest outdated patterns even though my codebase has moved on?
Copilot most likely has outdated files open in your editor tabs that it's sampling for context. Close legacy files you don't want it to mirror, keep current reference files open, and update or remove stale comments that reference old patterns.
Does GitHub Copilot read all the files in my repository automatically?
No. Copilot only reads your current file, a sample of recently opened editor tabs, and your import statements β it does not index or search your entire repo. You need to deliberately keep relevant files open to influence its suggestions.
What is the copilot-instructions.md file and how does it help?
It's a Markdown file you create at .github/copilot-instructions.md in your repository. Copilot Chat reads it automatically and uses the contents to follow your project's conventions, stack choices, and coding patterns when generating suggestions.
How can I make GitHub Copilot follow my team's naming conventions?
The most effective approaches are: writing a .github/copilot-instructions.md file that states your naming rules explicitly, keeping existing well-named files open as references, and using specific inline prompts that name the exact functions and types you want Copilot to follow.
Should I use Copilot inline completions or Copilot Chat for generating complex functions?
Use inline completions for short, predictable code β simple functions, boilerplate, or repetitive patterns. For complex tasks like generating a full service class, writing tests, or refactoring, Copilot Chat with a detailed, constraint-specific prompt produces much more accurate and usable results.
π€ Share this article
Sign in to saveRelated Articles
Comments (0)
No comments yet. Be the first!