The document tree: how I keep an AI-built project on track
A lazy-loaded doc structure that keeps a coding agent aligned with your past decisions across sessions — automatic awareness, without bloating the context window.
The problemAwareness vs. a focused context window
Build with a coding agent across many sessions and you accumulate decisions — product calls, architecture choices, naming conventions. You want every new session to honor them automatically, so its planning, brainstorming, and implementation line up with what earlier sessions already settled, instead of contradicting them or making you re-explain from scratch. Handled well, those decisions become a growing rubric the agent works against.
The obvious move is to pour everything into the one file the agent always reads. It backfires: load every doc into the context window and it turns large and unfocused — the agent carries your whole product spec, architecture, and conventions into a session that only touches one module.
That was the exact tension I hit mid-project:
Loading all the docs automatically makes the context window too big and lose focus — but how do I make the agent aware of a decision on its own, so I don't have to remember (or re-state) it at the start of every prompt?
So here's the question this structure answers:
How do you make a session automatically aware of the right decisions — so it aligns with past sessions and builds on a growing rubric — while loading only the documents it actually needs?
Concretely: if each module has its own doc, working on module A shouldn't drag module B's docs into context. Awareness when it's relevant, silence when it isn't.
The answer is a document tree — one structure that buys both automatic awareness and lazy loading. Everything below is live in two of my projects, guasi and sans_cube (a Bluetooth Rubik's-cube analyzer), and I'll point at the real files as I go.
SetupThe repo is the context
Two facts about coding agents shape everything:
- One root file is auto-loaded every session. (
CLAUDE.md,AGENTS.md— whatever your tool calls it.) It's the one thing you can count on the model reading, so it's prime real estate. - The agent can open any file on demand. It doesn't need everything pre-loaded; it follows a link or a filename and reads what the task needs, when the task needs it.
So the design question is "how do I shape the documents so the agent lands on the truth, and loads only the truth it needs?"
TechniqueAn index that points to a tree
The root file is an index, not an encyclopedia. It holds the stable spine — locked decisions, conventions, the one-paragraph "what this is" — and then points to topic docs that live in their own files:
CLAUDE.md ← auto-loaded. Small. Stable facts + links out.
├─ docs/routes.md ← the URL/route map
├─ docs/product-decisions.md ← identity & policy decisions
├─ docs/brand-and-voice.md ← naming, language, copy voice
├─ docs/deployment.md ← infra & CI/CD
└─ docs/devlog.md ← what shipped, newest first
This buys two things that matter on every single turn:
- Focus, not bloat. The always-loaded root stays small, so a session editing one component isn't wading through the routing table, the brand guide, and the deploy runbook. You save some tokens too — but a doc costs about the same whether it's preloaded or opened on demand, so the real win is signal: the agent's attention stays on the task instead of the whole project.
- Lazy loading. The agent pulls
brand-and-voice.mdonly when it's writing copy,routes.mdonly when it's touching routing. Relevance is decided at read-time, by the task. A bigger project just grows more leaves; the root stays flat.
The root's job is to be a small, trustworthy map. The moment it tries to contain everything, it gets too big to keep correct.
One honest caveat about "automatic." The root file is genuinely auto-loaded, so its stable spine is always in play. A leaf only loads if the agent follows the pointer to it — so the real work is making those pointers clear enough that it reliably does. The tree improves the odds the agent lands on the right doc at the right moment; it doesn't hard-guarantee it.
That tree is guasi's actual CLAUDE.md and docs/ — a live repo whose devlog.md has tracked 35+ versions, keeping the project on track across sessions. The same skeleton shows up in a second project: sans_cube lives in a completely different domain (3D rendering, Web Bluetooth, no backend) yet its root file has the same skeleton — a small "what this is," a "who's working on this," then a docs/ index pointing to ui-architecture.md, storage.md, time-model.md, devlog.md (50+ versions of its own), and a dozen more. Same shape, different leaves. Two repos by one author share conventions by construction, so treat this as a sign rather than proof of generality. Still, the skeleton holding up across two unrelated domains tells me the structure is doing real work.
Two tiersKeep the references current, keep the history
Here's the part most setups miss: not every doc should be kept up to date — and that's on purpose.
There are two kinds of project documents, and conflating them is what poisons the well:
- Maintained docs (the root file + the topic docs it links): these are the source of truth. They must match the code. When a feature changes a decision, its doc changes in the same breath. These are what the agent is told to trust.
- Historical docs (per-milestone specs, plans, and the dev log): these are the record of how we got here. They are allowed to go stale — a spec is a snapshot of the thinking at the time, not a promise about today.
You want both. The fix is to label the tiers explicitly so the agent knows which to trust — the maintained docs are ground truth; the specs are a paper trail, never cited as current. Throw away the history and you lose the why behind decisions; treat the history as current and a six-month-old brainstorm starts dictating today's build.
In guasi this split is written into the root file in so many words: the maintained docs/*.md are "authoritative, kept up to date during development," while everything under docs/superpowers/specs/ and .../plans/ is flagged "allowed to stale — a record of thinking at the time, not the source of truth … don't trust them where they conflict with the code or CLAUDE.md." The agent reads that label and knows which file wins a disagreement.
The dev log is the elegant resolution of the tension: it's append-only history that's also always current, because "newest entry on top" is true forever. You get the development story and today's state from the same file, without either lying.
The core ruleOne fact, one place
The single highest-leverage habit. A fact stated in two documents is a fact that will eventually disagree with itself.
So the root file deliberately does not restate "what version we're on" or "what's next" — the two fastest things to drift. It says instead: current state is the top row of the dev log; the roadmap is todo.md. Each fact has exactly one home, and everything else links to it.
This is literally how guasi's CLAUDE.md is written. Its "Current status" section opens with a note addressed to every future session — "this section does not restate the version/phase, to avoid drift" — and then points at the dev log's top row for what's shipped and todo.md for what's next. The one place most tempting to duplicate is the one place I most refuse to.
DisciplinesWhat keeps it honest
A structure doesn't stay true on its own. A few habits do the real work:
- Close the loop at the end of every session. The whole structure rests on the maintained docs staying true — so keeping them current can't be a chore you remember; it has to be a step the agent runs on its own. My root file instructs every session to finish by updating the relevant
docs/*.mdand appending todocs/devlog.md— folding that session's new decisions and learnings back into the tree before the work counts as done. That's what turns a pile of one-off sessions into the growing rubric: each session leaves the next one a little smarter. - Migrate before you retire. Before demoting milestone specs to "historical," I had an agent audit them for any still-current decision that lived only there, and moved those into the maintained docs first. De-referencing without auditing is how you silently lose real decisions.
- Review with fresh eyes, not the eyes that built it. The agent that wrote the code is primed to think the docs are fine — it remembers the intent, so it reads the intent into the words. A fresh-context reviewer reads what's actually written — and catches the "locked decision" that quietly drifted from the shipped code while the building session wasn't looking.
- Capture conventions so sessions inherit them. Naming, voice, the release flow, "escape user input even when you render it verbatim" — written once, every future session starts knowing them instead of relearning (or violating) them. sans_cube does this per-doc, pinning the rule to the file it governs: "keep
docs/ui-architecture.mdup to date whenever you add a component, remove a component, or change which hooks a component owns." And both projects share one convention word for word — "when you add a newdocs/*.md, add it to this list with a one-line description" — which is the small habit that stops the index itself from rotting as the tree grows new leaves.
TradeoffsWhat it costs
It isn't free. You pay an upkeep tax: a change that touches a decision has to touch the doc that records it, in the same change. The two-tier split takes judgment — label something "historical" too early and you bury a decision that's still live. And this is one project's experience — a case study, not a benchmark.
But the alternative is worse: sessions that are either blind to your past decisions or drowning in all of them at once — and docs that quietly drift from the code until something built on a stale "fact" breaks.
Curious whether the structure actually steers the agent — or how to check it on your own project? I went through the transcripts: How to tell if the document tree is working →
TakeawayThe most important artifact
For agentic coding, your most important artifact might not be the code — it's the small set of documents your agent wakes up to. Give it a tree, not a pile: a small, trustworthy root that lazy-loads the rest; maintained docs that stay true and historical docs that stay honestly historical; every fact in exactly one place.
And every so often, send in an agent that doesn't trust you — and let it tell you where your context is lying.
See it liveguasi's tree, in the open
The cleanest example I can point you at is guasi's own tree:
CLAUDE.md— the auto-loaded root: stable facts, the two-tier labels, and "current state is the dev log's top row."docs/— the lazy-loaded leaves (routes, product decisions, brand & voice, deployment…), each pulled in only when a task needs it.docs/devlog.md— append-only history that's also always current, newest entry on top.
That's the structure, running. Want it in your own repo? sans_doc_tree is a template with the skeleton CLAUDE.md, docs/, and devlog already laid out.