Skip to main content

Overview

Context engineering is the practice of designing what an AI coding agent reads: which information occupies its context window at each point in a session, and which is deliberately kept out. It differs from prompt engineering in scope. Prompt engineering shapes a single instruction — the wording, the structure, and the examples inside one request. Context engineering covers the whole session: the instruction files loaded before anything is typed, the tool definitions, the files the agent opens, the output of the commands it runs, and the conversation history that accumulates as the work proceeds. The distinction matters because most of what an agent reads is not written by a human. However carefully a single request is worded, it is a small part of what the window holds; the rest is the instruction files, the files the agent opened, the command output, and the conversation history. Wording alone does not reach that material, and designing it is what context engineering covers. One goal runs through all of it: hold the information the work needs, in the amount it needs, and no more. Both directions hurt — too little and the agent fills the gap by guessing, too much and what actually matters gets buried. This page explains why a crowded context lowers output quality, what occupies the context, how to design the parts that persist across sessions, and how to run a session so that what remains stays relevant.

Why context degrades output

The context window is the total amount of text a model can consider at one time. Everything the agent has read in the session — instructions, files, command output, its own previous replies — occupies part of it, and the limit is fixed. Two separate problems follow from that limit. Capacity. When a session exceeds the window, the earliest material has to be dropped or summarized. A constraint stated at the start of a long session may no longer be present by the time the agent writes the code that violates it. Attention. Well before the limit is reached, quality drops as volume grows. The model weighs every token in the window, so the more unnecessary material is mixed in, the less attention reaches what actually matters. A precise instruction surrounded by a thousand lines of unrelated source becomes one clue among many. Irrelevant history is not neutral — it steers the output. Failed attempts, abandoned approaches, and corrected mistakes stay readable to the model and keep influencing what it produces. This is why correcting an agent repeatedly within one session yields diminishing returns: each correction adds the failed attempt to the context alongside the fix.
A larger context window raises the capacity limit; it does not remove the attention problem. Being able to load an entire repository does not make loading it a good idea.

What is in the context

Everything in the window arrives one of two ways. Separating them is the basis for the rest of this page, because the two are designed with different methods.

Persistent context

Custom instruction files, the system prompt, and the definitions of the available tools and skills. Loaded at the start of every session, so it is designed ahead of time by editing files.

Dynamic context

Files the agent opens, the output of the commands and tools it runs, and the conversation history. It enters while the work proceeds, so it is designed by scoping the task and running the session.
Persistent context is loaded on every session, whether or not the task needs it. That is what makes its size a design concern: a rule only a few tasks need still occupies the window during every unrelated task. Dynamic context is where volume actually grows. A single failing test run or a wide search can add more text than the entire instruction file, and unlike persistent context it accumulates rather than staying constant.

Designing persistent context

Persistent context is carried mainly by a custom instruction file — a file checked into the repository that the agent reads at the start of every session. Different tools read different filenames (AGENTS.md, CLAUDE.md, and .cursorrules among them), but the design question is the same in every case: what earns a place in every session? Of the other two kinds of persistent context, the system prompt is usually not yours to edit. How many tool and skill definitions to connect is covered in MCP, so this section designs the instruction file.

What belongs in the file

The test is whether the agent would get it wrong without being told, and whether that matters on most tasks. Content that meets both conditions belongs in the file.
  • Commands. Build, typecheck, lint, and how to run a single test. The agent cannot infer which invocation the project settled on.
  • Conventions that differ from the default. A rule the agent would otherwise break because the common practice elsewhere is different, including repository conventions such as branch naming and commit message format.
  • Architectural constraints. Which layer a call has to go through, which library is the chosen one, what must not be introduced.
  • Environment quirks. Setup that fails silently or in a misleading way if it is done the obvious way.
Leave out three kinds of content:
  • What the agent can read from the code. Restating what a file already shows adds volume without adding information, and it goes stale without anyone noticing.
  • Knowledge needed for one specific task. It occupies every unrelated session in exchange for being useful in a few.
  • General programming advice. Instructions such as “write readable code” do not change the output and consume attention.
Check the file into git so the whole team shares one definition of the conventions, and so changes to it go through review like any other change.

Where to place a rule

Instruction files are usually read at several levels: the repository root (shared by the team and committed), a subdirectory (rules that apply only to that part of the tree), and a personal file (an individual’s preferences, not committed). Put each rule at the narrowest level where it holds. A rule that concerns only the frontend directory does not need to occupy the context during backend work, and a personal preference does not belong in a file the team shares.

Keeping the file from growing

Instruction files grow unless something pushes back: every incident suggests a new rule, and nothing suggests deleting one. Past a certain length, adherence drops — individual rules get lost among the others, and the file competes with the task for attention. Two habits keep it bounded:
  • Delete rules the codebase now enforces mechanically. A convention checked by a linter or a type definition does not also need a line in the instruction file, because the check catches the violation regardless.
  • Move conditional knowledge into a skill. A rule that begins with “when working on X” is not needed in every session. A skill is loaded on demand, so the knowledge stays available without occupying the window until the task calls for it.
When you are unsure whether a rule is being followed, shorten the file before adding emphasis to the rule. Adherence usually improves more from removing competing content than from restating the rule more forcefully.

Managing the session

Dynamic context is designed by controlling what enters the window, and by deciding when to reset a session rather than continue it.

Match the session to the unit of work

Treat a session as a unit of context. Work that rests on a shared understanding belongs in one session, where the agent still sees what it already established; work that does not share that understanding belongs in a new one, where it inherits no noise. Running unrelated tasks in one session is the common failure. What the first task loaded — the files it opened, the output it produced, the decisions it settled — is still in the window while the second one runs. The model reads it too when it builds its answer, so it is more than dead weight: it carries patterns from unrelated work into the current request. The criterion for drawing the boundary is the one already used to size a task. A unit of work that is independent enough to revert on its own and small enough to review on its own is also self-contained enough to run in one session; see Task Breakdown for how to find those boundaries. The same split decides what can be handed to a separate agent.

Know when to reset

Three signals indicate that a session should be reset rather than pushed further:
  • The same problem has been corrected twice without converging. The context now holds the failed attempts next to the corrections, and both keep steering the output.
  • The task has changed to something the accumulated history does not serve.
  • The agent contradicts a constraint that was stated earlier in the session, which suggests the constraint is no longer being considered, or is no longer there.
A reset costs nothing if the conclusions are carried over. Write down what the session established — the decision reached, the approach that failed and why, the files that turned out to matter — and open the new session with that summary instead of the raw history. A short handoff is a compressed form of everything the previous session read.

Summarize instead of accumulating

Many agents can compact a session by replacing the accumulated history with a summary and continuing from it. This buys room, and it discards detail in the process. Treat a compaction as a checkpoint rather than a transparent operation. Confirm that the constraints that matter survived it, and restate the ones that did not.

Offload bulky work

Exploration produces far more text than its conclusion needs. Searching a codebase to find where something is implemented may read thousands of lines to produce a one-paragraph answer, and those lines are of no use afterwards. Run that work in a subagent, which holds the raw material in its own window and returns only the result. The main session receives the conclusion without the volume that produced it. The same reasoning applies to external data. Issues, library documentation, and design data should enter the window when the work needs them, not in advance in case they turn out to be relevant. The retrieval path itself does not matter: an MCP server, a direct API call, and a page fetched from the web all serve equally here. What matters is that the agent pulls the data at the point of use instead of receiving it pasted in up front.

Vibe Coding

How these principles apply when a human and an agent work interactively on one task at a time.

Agentic Workflow

How they apply when implementation is delegated to agents that run on their own in parallel.

Subagents

The concrete mechanism for keeping bulky exploration out of the main context window.