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.
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.
- 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.
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.
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.
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.Related pages
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.