You ask your agent to add a feature. It writes clean, confident code — using a library version you ripped out six months ago, a folder layout you abandoned, and an auth pattern you've never used in this repo. The code compiles. It's also wrong in every way that matters.
Your first instinct is to blame the model. "It hallucinated." Maybe. But more often the model did exactly what it should have given what it knew — and what it knew was a vague paragraph you typed into a chat box while distracted.
Here's the uncomfortable thesis: most of the time your agent isn't dumb. Your context is.
Why this matters now
For years the hard part of building software was writing the code. That's quietly stopped being true. Agents now produce working code faster than most of us can review it. The bottleneck moved upstream — to describing intent. Telling the agent what we want, what the constraints are, and what "good" looks like in this codebase.
And we are bad at this. We treat the instructions, rules, and project knowledge we feed agents as throwaway chat. We paste a prompt, get a result, and lose the prompt forever. We'd never treat our actual source code that way — we version it, review it, and test it. Patrick Debois (the guy who accidentally coined "DevOps") has been making this exact argument: context is the new code, and it deserves the same engineering rigor. He calls the emerging discipline the Context Development Lifecycle — generate it, evaluate it, distribute it, observe it in production, just like software.
I think the frame is genuinely useful. It's also early — more a direction than a paved road. So let me skip the theory and give you the parts you can actually do tomorrow.
1. Get knowledge out of your head and into files
The single highest-leverage move: stop holding project knowledge in your head and your chat history, and put it in versioned files the agent reads automatically.
Most agent tools support a project instruction file — CLAUDE.md, agent.md, .cursorrules, whatever yours calls it. Treat it like a real artifact. Commit it. Review it in PRs. Let it accumulate the hard-won facts a new teammate would need:
# agent.md
## Stack
- Node 20, TypeScript strict mode. No `any`.
- Postgres via Drizzle. We do NOT use the ORM's migration tool —
migrations live in `/migrations` and run via `npm run db:migrate`.
## Conventions
- API handlers return `Result<T>`, never throw across boundaries.
- Tests use Vitest. Co-locate as `*.test.ts` next to the source.
## Don't
- Don't add new dependencies without asking.
- Don't touch `/legacy` — it's frozen and being deleted.
Notice these aren't clever prompts. They're facts — the same things you'd tell a human on day one. The win is that you write them once and every future session starts informed instead of guessing.
2. Layer your rules — each doing one job
Don't cram everything into one giant file. Split context by scope, the way you split config.
- Global rules (apply to everything you do): your personal preferences. "Explain trade-offs, don't just agree." "Prefer standard library over new deps." These follow you across projects.
- Project rules (this repo only): the stack, the conventions, the landmines. These follow the code.
Keeping them separate matters because they change at different rates and for different reasons. Your personal style is stable; a project's architecture shifts. When you mix them, you end up editing your universal preferences every time one repo does something weird — and that weirdness leaks into every other project. One file, one job.
3. Feed facts, not vibes
Hallucination drops sharply when you give the agent something checkable instead of asking it to recall.
"Use the latest React Router" invites the model to average over every version it ever saw in training. "We're on React Router 7, data routers only, here are the three patterns we use: [paste]" gives it ground truth. The more specific and current the source, the less room there is to invent.
Concretely:
- Pin versions explicitly. "React 19," not "React."
- Paste the actual API or doc snippet for anything fast-moving, instead of trusting recall.
- Point at real files: "follow the pattern in
src/handlers/users.ts" beats describing the pattern in prose.
A checkable source beats a confident memory every time.
4. Treat context as a finite resource
This one trips up almost everyone. The context window is not infinite, and — more importantly — bigger isn't better. Stuffing in your whole codebase doesn't make the agent smarter; past a point it makes it worse. Relevant signal gets buried, the model loses the thread, and output quality quietly degrades.
Watch for the tells: answers that drift from your conventions, repeated questions about things you already established, confident edits to the wrong file. That's usually not the model getting dumber — it's the context getting noisy.
What to actually do:
- Notice degradation. When a long session starts producing worse results, that's a signal, not a fluke.
- Compact and restart. Summarize what matters — decisions made, current state — into a fresh, clean session. Most tools have a compaction step; use it deliberately instead of letting a session sprawl for hours.
- Don't pre-stuff. Add context when it's needed for the task at hand, not "just in case." A focused window beats a full one.
Think of attention as a budget. Spend it on what's relevant to this task.
5. Tell the agent about your environments
Your code doesn't run in one place. It runs locally, in CI/integration, and in production — and those differ in ways that bite. Different env vars, different feature flags, a real database versus a mock, secrets that exist in one place and not another.
The agent knows none of this unless you write it down. So write it down:
## Environments
- local: uses Docker Postgres, MOCK_PAYMENTS=true, seeded test data.
- staging: real Stripe test keys, mirrors prod schema.
- prod: real keys. NEVER run destructive scripts here.
Migrations are gated behind manual approval.
That last line alone can save you from an agent cheerfully running a "cleanup" against production because nobody told it production was special.
6. Fix the seed, not the fruit
This is the habit that makes everything above compound.
When the agent gets something wrong, you can fix the output — edit the code, move on. That fixes this fruit. The bad seed is still in the ground, and tomorrow it grows the same wrong thing again.
The higher-leverage move is to fix the instruction. Agent used the wrong test framework? Don't just rewrite the test — add "we use Vitest, not Jest" to agent.md. Agent keeps reaching for a deprecated helper? Add it to the "don't" list. Each correction becomes permanent, and the same mistake stops recurring across every future session.
It's slower in the moment and dramatically faster over a month. You're not fixing outputs anymore; you're improving the thing that generates outputs.
The honest caveat
None of this is a settled standard. There's no npm test for your context files yet, no agreed-on linter for instructions, no CI gate that fails when your agent.md drifts from reality. The Context Development Lifecycle is a useful lens, not a finished toolchain — the tooling is being invented in real time, and some of today's best practice will look quaint in a year.
But you don't need the mature toolchain to capture most of the value. Versioned instruction files, layered rules, checkable facts, a respected context window, and the discipline to fix the seed instead of the fruit — that's all available today, and it's the difference between an agent that fights you and one that feels like it actually knows your project.
Your agent is probably better than your context is letting it be.
One question for you
What's the single most valuable line currently living in your agent instruction file — the one fact that stopped a recurring mistake cold? Drop it in the comments; I want to steal the good ones.
This builds on Patrick Debois's Context Development Lifecycle — his write-up Optimizing Context for AI Coding Agents is the fuller version of the idea.
Top comments (0)