Write and Select — Two Pillars of Context
LangChain's four-pillar taxonomy gives context engineering its working vocabulary - this part walks the first two pillars in depth, authoring what the agent wakes up knowing and choosing what a task actually needs.
If part 3 convinced you the model is a stateless function, one question is left standing over everything: what, exactly, should go into the window? Asked baldly, it is paralysing — “everything relevant, nothing irrelevant” is a koan, not a method. What turns it into a method is a taxonomy, and the cleanest one I know comes from LangChain: Lance Martin's write-up Context Engineering for Agents sorts the discipline's strategies into four buckets — write, select, compress, isolate. The taxonomy is theirs, and I use it because two years of practice have not shown me a better carving. Everything I hang on it below — the examples, the failures, the opinions — is mine. This part takes the first two pillars; part 5 takes the rest.
The two pillars in this part answer different tenses of the same question. Writing context is about every future task: what should any agent, on any day, wake up already knowing? Selecting context is about this task, now: of everything available, what does this piece of work actually need in the window?
Write — what the agent wakes up knowing
Writing context is the authoring of persistent information that reaches the agent before it starts work. It is the most literal form of the “write it down or lose it” habit from part 3, industrialised: instead of correcting the agent in conversation, you correct the environment, once, in prose it will re-read forever.
The flagship artefact is the repository instruction file — CLAUDE.md, AGENTS.md and their relatives. Here is a trimmed version of the one from an invoicing API I will call Meridian (the project is invented; the rules are the kind I actually write):
# Meridian — agent notes
- .NET 9, EF Core. Migrations via `dotnet ef` only; never edit the
model snapshot by hand.
- Money is `decimal` end to end. Introducing `double` anywhere in a
money path is a defect, not a style choice.
- Public API contracts live in /contracts and change only alongside a
version bump. If a task seems to need a contract change, stop and ask.
- Prefer extending an existing endpoint class over adding a parallel
one; we have had three "temporary" duplicates become permanent.
- Rounding rules for proration live in docs/decisions/0007-rounding.md.
Read it before touching anything in /src/Billing/Proration.
Read it slowly, because each line demonstrates a different move. The first two are hard constraints — must and must not, stated as law. The third is an escalation boundary: a line the agent should not cross alone. The fourth is a preference with its reason attached, and the reason is doing real work — agents, like new hires, follow rules better when the rule carries its scar. The fifth is the most interesting move: it does not inline the rounding rules, it points at them. The file teaches the agent where knowledge lives rather than duplicating the knowledge — writing and selecting cooperating in a single line.
Two properties separate instruction files that work from the ones that rot. First, they encode constraints and conventions, not implementations — a file that says what must be true stays current; a file that narrates how every module works is stale by the next commit. Part 9 of this series is entirely about that distinction, so one sentence here will do. Second, they are ruthlessly ranked: the most load-bearing lines come first, because you are writing for a reader that weighs everything and skims nothing — every sentence you add dilutes the ones already there.
Writing context also scales down the tree. A root file cannot hold what a large codebase knows, and it should not try. The pattern that works is distribution: a short map at the root, and deeper, narrower notes placed at the directory level where they apply — /src/Billing/CLAUDE.md carrying the proration folklore that would be noise to an agent working in /src/Auth. The agent working in a given corner receives the corner's knowledge and is spared everyone else's. The industry has settled on calling this progressive disclosure, and it is the writing pillar's answer to the finite-budget constraint from part 3: author everything, but stage its delivery so no single window pays for all of it.
The final thing worth writing is memory — decisions and facts that outlive sessions. When an agent in Meridian learns that a particular supplier's invoices arrive with negative line items and why we accept them, that belongs in a decisions file, not in the transcript where it will die. The test I apply: if I would be annoyed to explain it to the agent twice, it gets written; if I would be annoyed to read it in every window, it gets written somewhere selectable rather than somewhere always-on.
Select — what this task actually needs
Which brings us to the second pillar, because authored context is only potential energy. Selection is the act of deciding, per task, what actually enters the window — and, just as importantly, what stays out.
Consider a concrete run: a bug report says Meridian's proration is off by a penny for mid-month upgrades on annual plans. What does the fixing agent need? The proration module. The failing reproduction test. The rounding decision record. The invoice model it touches. That is more or less the whole list — and everything else in the repository, all the auth code and deployment scripts and the other forty endpoint classes, is not neutral filler but active harm: tokens spent on it are budget stolen from the material that matters, and every irrelevant file is another chance for the model to pattern-match its way somewhere wrong. Selection has a positive half — get the right things in — and a negative half, noise reduction, and practitioners consistently underrate the negative half.
The selection toolbox, roughly in order of how often I reach for each:
- Deterministic inclusion — when you already know what the task needs, put it in the window directly. Name the files in the request; let the harness inject the decision record whenever
/src/Billingis touched. Dex Horthy's 12-factor agents makes a factor of this pre-fetching: if the model will predictably need the schema, include it up front instead of spending a tool-call round trip discovering it. - Agentic retrieval — let the agent search and read its way to what it needs, with grep and file reads. This is how coding agents mostly work today, and it turns selection into something you shape rather than perform: the navigable structure, the file naming, the short map at the root all decide how well the agent selects for itself.
- Semantic retrieval — embeddings and similarity search pulling in relevant passages (classic RAG). Powerful for large document corpora; in codebases I treat it as the fallback for when structure and search fail, because similarity is a guess about relevance, and the two other methods deal in certainties.
- Exclusion — the deliberate no-list. The generated client in
/src/Clientsthat pattern-matches beautifully and misleads completely; the deprecated/legacytree that answers every search with the old way of doing things. Telling an agent what not to read is selection too, and often the highest-value line in the instruction file.
The failure modes of selection are symmetrical, and I have committed both. Under-selection starves the model: the agent guessing at the rounding rules because nobody surfaced the decision record produces confident, plausible, wrong proration — and part 3 explained why it cannot know what it was never shown. Over-selection drowns it: my early instinct, burned by starvation, was to shovel everything adjacent into the window, and the result was an agent that read like a distracted junior — technically informed of everything, attending to nothing. The corrective habit is to ask Karpathy's question from part 3 of every candidate token: is this the right information for the next step — not for the project, not for some future step, this one?
The two pillars discipline each other
It should be clear by now that write and select are not independent chapters but a coupled system. Writing without selection produces the thousand-line instruction file that no window can afford and no model can weigh — everything documented, nothing prioritised. Selection without writing produces the brilliant retrieval pipeline over a repository where the crucial knowledge was never written down anywhere retrievable. The pillars fail jointly, and they are built jointly: every artefact you write should be authored with a thought for how it will be selected — short, titled, placed where the relevant task will trip over it — and every selection failure you notice is usually an instruction to go and write something.
So the rule I teach, and the one-line summary of this part: write for every future task; select for this one. Get both halves right and the window starts each run small, dense and true.
But two pillars only cover the input side of the story. Long runs generate context as they go — transcripts swell, tool results pile up, and even perfectly selected windows outgrow their budget. What then? Next, the other two pillars: compress and isolate.