Prompt: the instruction text you write (the wording).
Context: everything the model is shown for one call: the instructions, the tool definitions, the conversation so far, tool results, retrieved passages, notes, and the current question.
Context window: the largest context a model accepts, counted in tokens. A request over the limit is refused; a request under it is still read imperfectly.
Context engineering: deciding, at every step, what goes into the context, in what shape and in what order. It is a program, not a paragraph.
Prompt engineering asks "how should I phrase this?". Context engineering asks "of everything I have, what does this step need?". For a one-shot question the two are the same. For an agent they come apart, because the agent's store of things (logs, files, past messages, notes) quickly becomes far larger than any window, and the choice is made again at every step with different needs.
A useful way to hold it: the agent has a store (everything that exists) and a window (what the model sees now). The assembler is the function between them.
The assembler is a pipeline you can test stage by stage. Pinned items go in first and are never removed; the question's tokens come off the budget before anything else.
What competes for the window
An agent's window holds items of different kinds, and they do not deserve equal treatment.
Kind
Example
Written by
Treat as
Rules
"Never delete the backup bucket."
developer
pinned: always in, always first
Tool definitions
names, arguments, descriptions
developer
pinned, or chosen per step
History
earlier user and assistant turns
user, model
candidates: recent ones usually matter most
Tool results
logs, search results, file contents
outside world
candidates, often long, mostly noise, untrusted
Retrieved text
passages found by search
store
candidates, untrusted
Notes
what the agent wrote to itself earlier
the agent
candidates, trusted more than tool results
The question
the current goal or message
user
always in, last
Two things follow. First, the rules must not compete. If a rule can be pushed out by a long log, the agent will break it exactly when the logs are long, which is when it is working hardest. Second, trust differs by kind. Text a tool returned can say anything, so the assembler must wrap it in a way that cannot be mistaken for a rule (section 7).
The store and the questions
To measure anything we need a store with known answers. world.py builds a 60-step session:
Step 0 is a pinned system item holding a rule: never delete the bucket backup-prod-7.
Most steps add a tool log of 14 to 31 lines of build and deploy noise ("health check staging ok after 48 ms").
At eight steps, one hidden line states a fact: config: staging.deploy_key = ZK-4471. At three later steps, a log says config update: and changes one of those facts. The older item and the newer one share a key (staging.deploy_key), which is how the assembler knows the first is out of date.
Every seventh step is a short user message.
In the last 20 steps the user asks one question per step: a fact lookup (half of them in plain words, "What is the staging deploy key?"; half vague, "Which key deploys staging?", "Where does staging run?") or the rule ("Which bucket must never be deleted?").
That is 14,146 tokens in total by my counter, 61 items. Five seeds give 100 questions. Because values are made unmistakable (a code like ZK-4471, or a number with a unit like 458x), "is the answer in the window" can be settled by looking for the string, and a test confirms each answer appears in exactly one item.
Why a made-up world
Real logs do not come with answers marked. A generated world lets me know what the right context is, so I can score an assembler against it. The price is that the world is simpler than yours: the facts are on single lines, the questions repeat, and the noise has no cleverly relevant-looking lines beyond the shared environment names. Hard exercise 1 asks you to rebuild the test with your own logs.
Four ways to fill the window
assemble.py implements four policies, each a different answer to "what do I keep?". The budget is a number of tokens; every policy except the first stays under it.
keep_all: send everything that has happened. Simple, and what most first agents do.
recent: a sliding window. Pinned items first, then the newest items until the budget runs out. It stops at the first item that does not fit, as a real sliding window does.
relevant: pinned items first, then items by relevance to the question, best first, skipping any that do not fit. Relevance is word overlap, weighted so that rare words count for more; an item is as relevant as its best line, not the sum over its lines, because summing rewards length and a long log always mentions the environment somewhere.
curated: relevant, plus two moves. Supersede: drop any item whose key was later replaced. Trim: shrink each long item to its 120 most relevant tokens, keeping those lines in their original order and marking how many were cut.
The chosen items are put back in time order, wrapped, and followed by the question. The order is chosen separately (section 6).
The budget accounting has two details that matter.
The wrapper costs tokens. Each item is wrapped in a header and footer so the model can tell where one item ends. In this session the wrapper adds 15 tokens per item, 14,146 raw tokens becoming 15,064 wrapped (6.5 percent more). A budget that ignores this is exceeded every time. A planted defect that counts the body only is caught by the first test that checks the budget.
The question is paid for first. The question's own tokens come off the budget before items are chosen, so the finished context really is at most the budget.
Budget, pinned, supersede, trim
Budget: the number of tokens you allow this step. It is a design choice, usually well below the window limit, because cost and quality both worsen as the context grows.
Pinned: an item that must always be present. Pinned items are paid for first; if they alone exceed the budget, they are still kept and the context is flagged as over budget, because breaking a rule silently is worse than overspending.
Supersede: replacing a fact with its newer version instead of showing both.
Trim: shortening one item by keeping its useful lines.