Context Management: What to Feed, What to Hide

You ask the tool to add a field to your user model, and it invents a User class that does not match the one you already have. The code compiles. It is also wrong. The model never saw your real model, so it built a plausible one from thin air.

That failure is almost never about the model being weak. It is about what was in the context window when it decided. Managing that context is the single highest-impact skill you have with these tools, and it comes down to two moves: feed the files that matter, hide the ones that do not.

The context window is a budget

A model only knows what is in its context window. That window is finite: a fixed number of tokens per request. Your code, the tool’s system prompt, your rules file, the conversation so far, and the model’s own output all compete for the same space.

The tool cannot load your whole repo. A medium backend service is easily hundreds of thousands of tokens of source; a monorepo dwarfs the window many times over. So on every request the tool spends its budget on a slice of your codebase and hopes it picked the right one.

Treat context like a budget you are spending, not a bucket you are filling. Every file you add pushes something else toward the edge. The goal is not maximum context. It is the right context: enough to work from facts, little enough that the signal stays sharp.

flowchart LR
    W["Context window<br/>(fixed budget)"] --> SYS[System prompt<br/>and rules]
    W --> HIST[Conversation<br/>so far]
    W --> CODE[Files you<br/>fed in]
    W --> OUT[Room for the<br/>model's answer]

What to feed

The first article in this track covered why context drives quality. This is the practical version: how you actually get the right files in front of the model.

Feed the files the task genuinely touches. For “add rate limiting to the login endpoint,” that is usually the route handler, the middleware layer it plugs into, one similar feature to copy the pattern from, and maybe the config where limits live. Four files, not forty.

Tools give you direct ways to point at them:

  • @-mentions. Type @file or @folder in your prompt to pin exact files into context. This is the sharpest tool you have; use it when you know where the relevant code is.
  • Open files. Most tools weight files you have open in the editor. Open the two or three files at the heart of the task before you prompt.
  • Let it search, then check. The agent will search the repo on its own. That is fine as a starting point, but read which files it pulled. If it missed the one that actually defines the behavior, add it by hand.

A good habit: name the anchor file and the pattern to copy. “Add rate limiting to @login.py, follow the pattern in @throttle_signup.py” gives the model both the target and a worked example. It will match your conventions instead of inventing new ones.

What to hide

The other half is subtraction, and it is the half people skip. Too much context degrades output as badly as too little. When you bury four relevant files under a 9,000-line lockfile and a vendored SDK, the model’s attention thins out across noise, and the odds it fixates on the wrong thing go up.

Keep these out of context by default:

  • Lockfiles and dependency manifests. package-lock.json, poetry.lock, yarn.lock. Huge, machine-generated, almost never relevant to the task.
  • Generated code. Compiled protobufs, ORM migrations you did not hand-write, dist/ and build/ output. The model should read the source of truth, not the artifact.
  • Vendored and dependency directories. node_modules/, vendor/, .venv/. This is other people’s code; it is not what you are changing.
  • Large data and fixtures. CSVs, seed dumps, image blobs, snapshot files. They eat budget and teach the model nothing about your logic.

Most tools honor a .gitignore, and several support a dedicated ignore file (Cursor’s .cursorignore, for example) so the agent’s indexer and search skip these paths entirely.

# .cursorignore
node_modules/
dist/
*.lock
**/migrations/
fixtures/**/*.csv
Why does more context sometimes make the output worse?

Because the model’s attention is a shared resource, and irrelevant text competes with relevant text for it.

Models handle information best near the start and end of the context window; material buried in a large middle gets attended to less reliably. This is often called the “lost in the middle” effect. If you pad the window with a lockfile and three vendored libraries, the one file that mattered can end up in that soft middle, and the model reasons around it instead of from it. Trimming context is not just about saving tokens. It is about keeping the signal where the model actually looks.

Strategies for large repos

In a big codebase, the default search will drown. It has too many plausible-looking files to choose from, and it cannot tell your live auth module from three abandoned ones. Your job is to narrow the field before the model starts guessing.

Scope by directory. Point the tool at the service or package you are working in, not the repo root. @services/billing/ is a far better starting frame than “the codebase.” A per-directory rules file helps here too; see setting up context for how rules files carry conventions the tool would otherwise miss.

Work feature by feature. Break a big change into slices that each fit one clear context. Do the data model in one pass with the model files loaded. Do the API layer in the next with the handlers loaded. Each pass has a tight, relevant window instead of one bloated attempt at everything.

Start a fresh session when the task changes. A long conversation accumulates stale context: files from the last task, dead ends, abandoned plans. When you switch to unrelated work, clear it. A clean window beats a long one.

flowchart TB
    BIG["Big change:<br/>'add subscriptions'"] --> S1["Slice 1: data model<br/>@models loaded"]
    BIG --> S2["Slice 2: API layer<br/>@handlers loaded"]
    BIG --> S3["Slice 3: tests<br/>@tests loaded"]
    S1 --> R["Small, relevant<br/>context per pass"]
    S2 --> R
    S3 --> R

A concrete example

Say the task is: add an is_verified boolean to the user and gate the dashboard route on it. Two files really matter, models/user.py and routes/dashboard.py, plus one migration to copy the pattern from.

The trimmed version:

Add an is_verified boolean (default false) to the User model
and block the dashboard route for unverified users.

@models/user.py
@routes/dashboard.py
@migrations/0012_add_last_login.py   # copy this migration's shape

Three pinned files, one of them purely as a pattern to imitate. The model sees your real User class, your real route, and the exact migration style your project uses. It writes a change that drops straight into a pull request.

Now the untrimmed failure. You skip the @-mentions and type “add is_verified to the user and gate the dashboard.” The agent searches a large repo, finds two User classes (one live, one in an old legacy/ folder it should have ignored), and picks the legacy one. It also never finds your migration convention, so it writes raw SQL your project does not use. The diff looks reasonable and touches the wrong file with the wrong pattern. Untangling it costs more than the trim would have. That is the trade the whole skill turns on.

Common beginner mistakes

  • Treating context as a bucket, not a budget. Dumping the whole folder in “to be safe” thins the model’s attention and makes output worse, not safer.
  • Never using @-mentions. Leaving file selection entirely to the tool’s search, then being surprised when it edits the wrong User.
  • No ignore file. Letting lockfiles, node_modules/, and generated code flood the index and the search results.
  • One giant prompt for a big feature. Cramming the model, the API, and the tests into a single request instead of slicing it into focused passes.
  • Reusing a stale session. Carrying a bloated conversation from an unrelated task into the current one instead of starting fresh.

Questions you will face in production

“How do I know what the tool actually loaded?” Most tools show the files or context they pulled for a step; read it. If the file that defines the behavior you are changing is not in that list, the model is guessing. Add it with an @-mention and rerun. This one check catches most “it edited the wrong thing” failures before they happen.

“Won’t hiding files make the model miss something it needs?” Rarely, and the fix is cheap. You are hiding categories that are almost never the source of truth: generated artifacts, dependencies, lockfiles. If the model genuinely needs one, pin it for that task. Default to hidden, promote on demand.

“My repo is huge and search is slow and wrong. What first?” An ignore file, then scoping. Cut the vendored and generated paths out of the index so search only ranks real source, then point each request at the directory you are working in. Those two moves fix most large-repo pain.

What to remember

  • The context window is a fixed budget; the tool cannot see your whole repo
  • Output quality tracks which files the model can see, not how many
  • Feed the few files the task touches, via @-mentions and open editors
  • Hide lockfiles, generated code, vendored dirs, and big data with an ignore file
  • Too much context degrades output as much as too little
  • For large repos: scope by directory, work feature by feature, start fresh when the task changes

What to study next

Context gets the right code in front of the model. The next job is judging what comes back out. Read reviewing and trusting AI-written code for how to read a diff you did not write, spot the failure modes trimmed context still lets through, and decide what is safe to merge.

Further reading

Where this article comes from. This is a synthesis of common practice in AI engineering as of 2026, not a citation of any single paper. The sources above are where the mechanics come from. If you find an error or have a better source for a claim, the article gets fixed within a day, send me a note.


Auto-marks when you reach the end. Click to toggle.

If this helped, buy me a coffee

Everything is free. Tips keep me writing the rest.

Buy me a coffee →