[KongchangAI]
· 9 min read· 4,928 words

Agents Aren't Amnesiac — They Just Can't Find the Doc Entrance: Documentation Layering for Large Projects

Agents Aren't Amnesiac — They Just Can't Find the Doc Entrance: Documentation Layering for Large Projects

Agents aren't amnesiac — they lack a path from entry to spec; docs should become an L0–L3 routing system for Agents.

Based on seven months of AI-collaborative development on an enterprise payment system, this article rebuts the complaint that "Agents always forget." Agents never had cross-session memory — each session is a newcomer entering via the entry file. The fix is not the Agent but the entry: documentation's primary reader is now the Agent, and the doc system is a routing system for it. The piece traces six real symptoms to two unmade distinctions (resident vs. on-demand, current fact vs. history), proposes three principles and the L0–L3 model, and lists three ways it will inevitably break.

Agents Aren't Amnesiac original

This is the first article in the series "Documentation Layering for Large Projects, For Agents." The material comes from seven months of AI-collaborative development on an enterprise payment approval system: the author worked in rotation with Claude Code, Codex, and Kimi, jointly producing code, tests, and documentation. The series discusses only the documentation leg; testing methodology is a separate topic.

Two releases, one spec that was written long ago

On September 16, an enterprise payment approval system tagged two version releases on the same day. Neither version had a changelog, and neither had handoff notes.

A commit two days later did three things at once: it added a standalone "release freeze" spec (freeze = lock the version, run the full test suite, tag, produce a delivery package), it added an "operation → required reading" table to the entry file, and it backfilled the release documentation that those two versions had skipped. The note above the table embedded the lesson into the Agent's entry rules: "Released a version without reading the full-suite test definition, and skipped the release documentation."

What's really notable is this: the definition of "full suite" wasn't new that day. The spec already existed. "A full run always includes the following six test suites, none may be omitted" had long been in the project's testing spec; the documentation homepage had mentioned the "six-suite full-run discipline"; and the change plans for two earlier freeze releases had also required six-suite test evidence.

The spec itself was sufficient. What was missing was the path from the entry file to the spec. Before the incident, the entry file was 410 lines, and the only text about releases was a tagging rule buried in the Git branch conventions — the terms "full suite" and "release freeze" never appeared. Starting from the entry point, there was no thread leading a freeze release to that testing spec.

So the complaint "Agents always forget" blames the wrong party. Agents don't lose their memory — they never had cross-session memory to begin with. Every session is a newcomer walking in through the entry point, and the problem is that the entry point doesn't take it where it needs to go. The entire series has just one thesis: in projects where Agents write most of the code, the primary reader of documentation is the Agent, and the documentation system is a routing system that serves that Agent.

The primary reader of documentation has changed

First, the scale. Over seven months, the project accumulated 3,614 commits, of which 1,373 touched documentation or entry files, and at least 547 carried Agent attribution markers (a lower bound, counted by attribution lines). As of October 14, the documentation tree had 832 Markdown files, 51 structured change packages, and 301 early single-file plans.

Who is reading all this documentation? At the start of each session, the Agent automatically loads the entry file; before starting work, it follows the entry to the spec; upon entering a module, it opens that module's plan and handoff records. The author's position is: documentation is now written first and foremost for the Agent. What humans read are the summaries the Agent produces at decision points, not the entire documentation tree from top to bottom.

This thesis has to be grounded in the Agent's properties. The whole mechanism is derived from the table below, and every principle in the series will note which property it corresponds to.

Agent propertyRequirement for documentationCorresponding mechanism
No cross-session memoryEvery session enters through the entry point; the entry must be a routing tableL0 + "operation → required reading" table
Limited and costly contextTokens are the first-order cost; drill down on demandL0–L3 layering, thin indexes
Executes literal text, doesn't infer intentStatus, replacement, and scope must be written explicitly; "you may refer to" must become "required reading before action"State machine, Replaced by, required-reading table
Can grep, glob, run scriptsNames must be pattern-matchable, metadata parseable, rules checkableID scheme, metadata blocks, doc-lint
Is also the primary authorConventions maintained by good faith inevitably drift; must be machine-enforcedHook / CI checks
Multiple Agents present at onceSingle entry point; experience accrues in the repo, not in individual memoryA single AGENTS.md entry

The last two rows deserve separate elaboration. "Is also the primary author" means: the Agent that writes a spec may, in the next session, be the very Agent that violates it — so any convention a machine can check will eventually become a check. "Multiple Agents present at once" means Claude Code, Codex, and Kimi take turns at the wheel, and experience that lives only in one Agent's individual memory is gone the moment a different Agent takes over.

Code, tests, documentation: three legs

Code, tests, and documentation are equally necessary; remove one and the other two can't stand. Agents write code, tests prove the code correct, and documentation tells the Agent how to write and where to write results back. The three interlock: the routing table points the Agent to the testing spec, the case index points tests back to requirements, and doc-lint is "the test suite for documentation." In the incident at the start, the tests and the testing spec were both present — all that was missing was that one hop inside the documentation system.

Three corollaries

Corollary one: the human's role shifts from reader to arbiter. If the Agent is the primary author, humans don't need to read or maintain documentation daily; they appear only at decision points: approving plans, making tradeoffs, accepting freeze releases, confirming deliverables. What humans read are the summaries, diffs, and session notes the Agent prepares for that decision. Decision quality therefore depends on what the Agent brings to the table — a spec it hasn't read won't appear in the summary or checklist.

Corollary two: deliverables are not engineering documentation. User manuals, changelogs, and deployment handoff notes are read by business stakeholders and operations — they are product deliverables. The Agent is responsible for maintaining them, but they don't enter the Agent's routing system, or they'll just burn context for nothing. The routing table only records "after which operation must this be updated." The cost of missing that line is real: on July 7 an approval flow went live, and the user manual wasn't updated until July 15 — for eight days, the process list in the manual was wrong.

Corollary three: one document serves one reader. A document that tries to serve both humans and Agents will inevitably grow fat. The project's plan index was supposed to answer only "where is the documentation for this change," but it got written as a progress board — the "next step" column averaged 98 characters and peaked at 1,128. Every time the Agent opened the index it had to swallow a whole page of progress narrative first. The index is for the Agent; if humans want progress, have the Agent summarize on the spot, or use a script to generate a view.

Six symptoms

"Agents always forget" is a vague complaint. Unpacked, it's six different failures, every one of which occurred in this project.

Symptom one: not knowing which doc to read, so not reading at all. The freeze incident at the start is typical. The spec was there; the path wasn't. An Agent won't search the entire repo just because "there ought to be a spec"; if the entry has no path, it starts from common sense.

Symptom two: reading an outdated plan and treating it as current fact. At the top of the documentation model spec, the "AI quick path" says: when a document shows it has been superseded, jump first to the new document specified by Replaced by. Yet of the 51 change packages, 35 didn't write Replaced by, and 16 didn't even have a Stable ID. The rule was there; the field wasn't, and the rule spun in place. For an Agent that executes literally, no "superseded" equals "still valid." Status itself was also unreliable: the spec defined 8 states, but the index actually used 9 spellings.

Symptom three: reading too much, drowning in history. The entry file grew to 457 lines, mixed with a great deal of incident narrative. The roadmap's top accumulated 34 date banners, effectively becoming a second changelog. To start a small task, the Agent had to load hundreds of lines of irrelevant story first, diluting the constraints that actually mattered.

Symptom four: cases can't be traced back to requirements. The case index claimed to be the "single source of truth," but was in reality 28 segments of narrative written in batches, plus two hand-synced derived views — 909 lines across three files. To look up "which requirement does this case correspond to," the Agent could only read the narrative and guess.

Symptom five: work gets done, nothing gets written back. 18 completed change packages had no implementation.md. How it was actually done and where it deviated from the plan existed only in that session. The next Agent could read the plan but couldn't tell that the plan hadn't been followed.

Symptom six: each Agent reads its own entry. Before September 3, the entry file was called CLAUDE.md, following Claude Code's convention, which other tools don't necessarily load. Another batch of project-level experience lived in one Agent's individual memory, invisible to other Agents. One repo, three Agents, three sets of "project rules."

Lay the symptoms alongside the Agent properties and the answer is no longer mysterious: not knowing which doc to read corresponds to "no cross-session memory"; treating an outdated plan as truth corresponds to "executes literally, doesn't infer"; drowning in history corresponds to "limited and costly context"; failing to find a requirement-linkage field is "can grep but has no relational field to grep"; not writing back corresponds to "is also the primary author"; and each reading its own entry corresponds to "multiple Agents present at once."

grep and glob are the two most basic file-retrieval primitives. grep (Global Regular Expression Print) searches by content: given a regex or a literal, it scans file contents and returns matching lines. glob searches by path: it matches filenames and directory structure using wildcard patterns like **/*.md or docs/**/plan-*.md. For an Agent, these two are almost the only reliable sensors when probing an unknown repo — it has no ability to "remember where that doc is," only to locate things by name pattern and text content. This also explains why the documentation system must make names pattern-matchable and metadata parseable: if a document is called "Some Thoughts on Freezing (Final Draft)," globs can't catch it; if status is written in prose, grep can't judge it either. The recurring "ID scheme," "metadata blocks," and "doc-lint" in this article are all essentially about reshaping the documentation repo into a form where grep and glob work effectively. Without these fields, the Agent isn't unwilling to search — it simply has nothing to grab onto.

Root cause: the entry file became an encyclopedia

Digging to the bottom of the six symptoms, there are two distinctions that were never made.

The first distinction: resident vs. on-demand. The entry file loads every session; it's the most expensive spot in the documentation system, and every line is paid for in every session. Before cleanup, the entry stuffed in 9 "code review checklist" items and 7 "rule hardening" markers, plus the incident stories behind them. A session that only changes button copy still has to load the code review checklist and the database migration pitfalls. Yet the routing that truly belonged there — "read this before freezing" — was absent.

The second distinction: current fact vs. history. Current fact answers "what is true now" and is trustworthy; history answers "why was it that way then" and needs verification. In this project the two were mixed together: the project overview was frozen at September 3, and several version releases afterward didn't update it; in the refactor track's roadmap, 8 headings were marked ✅ while the body text said "not started." A human reading a contradiction will ask about it; an Agent will pick one of the sentences and believe it.

If neither distinction is made, the result is: the entry file became an encyclopedia, not a routing table. An encyclopedia answers "what is it," a routing table answers "where should I go read." An encyclopedic entry grows longer with conscientiousness, and the longer it grows the harder it is to find the critical line. The incident at the start is exactly what happens when the encyclopedia never recorded the relevant fact and the routing table simply didn't exist.

Entry file (AGENTS.md / CLAUDE.md) is the project-level configuration file conventionally used by Agent tools. Take Claude Code's CLAUDE.md: it is automatically read into context at the start of every session, as that session's "project notes"; Codex, Kimi, and other tools each have their own equivalent files (such as AGENTS.md), and their loading rules are not interoperable. This has two direct consequences. First, entry content is paid for every session: every line written in consumes every session's context budget, and the cost scales linearly with the number of sessions. Second, the entry is the only thing the Agent is guaranteed to read: no matter how important the L1 spec or L2 plan is, if the entry doesn't point to it, the Agent may never read it. So the entry should be positioned as "routing table + a small number of hard rules," not a knowledge warehouse. When a repo contains entry files for multiple tools, one must be chosen as the single source of truth (usually AGENTS.md), with the rest doing nothing but a one-line forward — otherwise you get the "one repo, three Agents, three sets of project rules" split described in this article.

Three principles

Working backward from the root cause, the model stands on three principles, each restatable in a single sentence, with the corresponding Agent property in parentheses.

Principle one: the entry only routes, it doesn't carry content. (Corresponds to "no cross-session memory.") The entry is the only thing the Agent is guaranteed to read. Apart from a few hard rules, its job is to tell the Agent "for this kind of work, read that document," not to move document content into itself. Content moved in will go stale, will bloat, and will eventually drown the routing itself.

Principle two: the resident layer keeps only rules that would be too late to discover after the fact, each with a one-line rationale; everything else drills down on demand. (Corresponds to "limited and costly context"; the rationale half corresponds to "executes literally, doesn't infer.") To decide whether something is resident, ask only one thing: if the Agent doesn't read it this session, will it cause damage before anyone notices? If yes, keep it resident; if no, push it below L1 and let the routing table point to it when needed. The rationale cannot be omitted — a command without a rationale gets discarded the moment the wording doesn't match; with a rationale, the Agent can infer the correct action in edge cases the rule doesn't cover. Full incidents sink to L2 / L3; the entry keeps only links.

Principle three: keep current fact and history separate; write status and replacement as fields. (Corresponds to "executes literally, doesn't infer.") Humans can hear in the tone that "this seems outdated"; Agents can't. Whether a document is valid and what superseded it must be a parseable field, not a narrative requiring inference. Written as fields, it also lets the Agent grep and scripts check.

The model: four layers, L0–L3

Three principles applied to documentation structure yields four layers:

LayerContentWhen to readConstraint
L0 residentHard rules in the entry file + routing tableAuto-loaded every sessionMust be short
L1 by work typeSpecs (dev / testing / database / freeze / manual / deployment)Before starting work, read only the one the routing table specifiesShared layer + project layer
L2 by module / changePlan packages, long-term tracks, handoff docsWhen entering that moduleCarries status and replacement links
L3 evidenceFreeze test reports, audit outputs, other execution reportsDrill down when evidence is neededNever used as an entry

L0 resident holds two kinds of content: rules that would be too late to discover after the fact (one rule, one rationale, one link), and a routing table telling the Agent which L1 document to open for each kind of work. It loads every time, and its only constraint is to stay short. When multiple Agents share a repo, L0 can only have one: the single entry file AGENTS.md, with the entry files other tools require doing nothing but forwarding.

L1 by work type: development, testing, database, freeze, user manual, deployment — one spec per work type. Before starting, read only the one the routing table specifies. L1 splits into shared and project layers; the project layer declares which shared spec it inherits, and writes only this project's fill-ins, current state, exceptions, and pitfalls.

L2 by module / change: a change's plan package, a long-term track, a handoff document, read only when entering that module. L2 naturally goes stale, so it must carry status and replacement links.

L3 evidence: freeze test reports, audit outputs, incident reports, drilled into only when evidence is needed. L3 is never used as an entry — a rule that lives only in some report's conclusion takes effect only when someone happens to read it.

The skeleton of an L0 entry file looks roughly like this (only the key parts kept):


**Stable ID** means a stable identifier that never changes over a document's lifetime, of the form `<T>-YYYYMMDD-NNN`, e.g. `D-20261014-001`. It is decoupled from filename, title, and path: rename the doc, move the directory, rewrite the title — the ID doesn't change. This is especially critical for Agents — an Agent that executes literally can't "guess that these two files are actually before-and-after versions of the same document" the way a human can; what it needs is an anchor it can reference precisely and grep. The Stable ID supports three things: first, `Replaces` / `Replaced by` fields can point to a definite object, forming a traversable chain of supersession; second, references between change packages, plans, and reports won't break because of file moves; third, scripts and doc-lint can validate reference integrity and catch dangling links or duplicate numbering. The reason "16 change packages don't even have a Stable ID" is a problem is precisely that, without IDs, these documents become islands that cannot be stably addressed from the machine's perspective.
# AGENTS.md — the only entry (loaded every session; keep it short)

## Hard rules (always in effect)
- <one-line rule>. Rationale: <one line>. Details: <L1 link>

## Operation → required reading
| Operation | Required spec | One-line key point |
|---|---|---|
| Freeze / package / tag / say "full suite green" | <freeze spec> | <one line on the full-suite definition> |
| DB schema / cross-environment data changes | <project database spec> | <the single most important constraint> |

## Layered reading
L0 = this file, always in effect. L1 = the table above, addressed by work type; before starting, read only the matching row.
L2 = a module's plan / track / handoff; read when entering that module. L3 = evidence; drill down when needed.
When unsure which document to read, read the table above first, then look for the next-level index at the top of the matching spec.

Every L2 document carries a parseable metadata block at the top — this is where principle three lands:

> Status: approved
> Stable ID: <T>-YYYYMMDD-NNN
> Replaces: none
> Replaced by: none

Status can only take values from a fixed vocabulary; free invention is not allowed. When a document is superseded, Replaced by is filled with the new document's Stable ID, and the Agent jumps as soon as it reads it.

How the model was forced out by incidents

I must be honest: the four-layer model wasn't designed from the start — it's the shape that only became visible in hindsight, after incident upon incident over seven months.

On March 4, the project initialized, and the entry file CLAUDE.md was 128 lines. The "plan-driven development" rule added that day later became the most important: write a plan first, start coding only after confirmation, backfill the actual execution record when done, keep the roadmap current. After that, documentation grew along with the development cadence; the early single-file plans now number 301, of which 218 have backfilled "actual execution records."

On May 26 the entry file was 302 lines; on August 20, 406 lines. A large part of the growth was incident narrative: hit a pitfall, add a section to the entry describing what happened and how to avoid it next time. Each section is reasonable on its own; together, the entry file became an ever-thicker incident manual.

September 3 was the first turning point. A documentation architecture reorganization touched 235 files, consolidated test material scattered in four places into one, grouped plans into three categories, made AGENTS.md the single entry with CLAUDE.md only forwarding. This eased "each reading its own entry" and "where things should go," but didn't answer "which document to read."

On September 18, after the freeze incident at the start, the "operation → required reading" table appeared for the first time, and the entry file began to look like routing. On September 29, a database migration numbering collision — two same-numbered migrations had already been run in production — and after the reorganization a rule was set: "before taking a number, check all parallel branches and worktrees." On September 30, a same-named old package was mistakenly deployed, and from then on package names had to include hours-minutes-seconds. On October 13 and 14, browser automation (MCP) actions were twice treated as acceptance; "MCP locates only, does not accept" was written into the rules and added to the routing table.

On October 14, the routing table evolved into the layered-reading principle of L0 / L1 / L2 — the predecessor of this article's model — and the entry file was 457 lines. The same day, the project kicked off a dedicated documentation governance change (ID D-20261014-001), and this series started simultaneously.

Laid out in order, the pattern is unmistakable: almost every rule added later stands behind an incident. This system was forced out by incidents. The series is written in the hope that the next project won't have to pay for it in incidents.

How this model will break

None of the following are hypothetical — every one was a real state of the project before cleanup.

Failure one: L0 bloat

Entry file line count: 128 → 302 → 406 → 457. Note the last stretch: after becoming the single entry on September 3 and adding the routing table on September 18, it kept growing.

The reason is plain: after each incident, the easiest thing was to add a section to the entry file — that's how the review checklist and "rule hardening" markers piled up. Each section is correct on its own, but L0's cost is multiplicative: lines × sessions. Worse, a bloated L0 drowns its own routing table, and the incident at the start replays inside the very file that holds the routing table. One detail: a heading in the entry file says "four pitfalls" while listing 5 items below it — that such an inconsistency could persist in a file loaded every session shows it had bloated to the point where no one was checking line by line.

Fix direction: keep each L0 entry to one rule, one rationale, one link; sink incidents; the entry-layer links need machine checks. How to write a routing table without it growing into an entry file is the topic of the second article.

Failure two: blurred layer boundaries

Without a custodian, the four layers leak into each other.

  • L1 mixed in templates and project adaptations. The documentation model spec itself is 1,123 lines, cramming shared spec, project adaptation, and about 460 lines of templates into one L1 document, violating the very "shared → project" layering that document defines.
  • L2 long-term tracks swallowed short-term plans. The refactor track was supposed to be just topic navigation, but held 145 single-file plans and a 2,613-line roadmap with status markers. The "heading ✅, body not started" contradiction lives here.
  • L2 and L3 weren't separated. The date banners atop the roadmap record release history version after version — they belong to execution records and L3 reports, yet they're stacked at the top of a "current fact" document. The same set of freeze numbers repeats in four places — index banners, index rows, release docs, roadmap — and miss updating one, and the Agent sees four versions of "fact."

The most stinging is the first: the spec that defines layering doesn't itself obey layering.

Failure three: Agents writing docs also forget

Most of the bloating and boundary-crossing above was written by some Agent following the spec. In the moment of writing, it obeyed the rules it read; it doesn't remember a convention set by another session last week, and won't go back to check whether the whole system is consistent. As a reader it "forgets," and as an author it "forgets" too. Layering maintained by good faith inevitably drifts — this is the topic of the fourth article: writing back is part of the change, conventions are machine-enforced and humans only arbitrate, the entry layer has zero tolerance, and deeper layers have a baseline that can only go down, never up.

doc-lint borrows the concept from the code world's lint tools (e.g., ESLint). Its idea is to translate "documentation conventions" from human conscientiousness into executable checks: whether status fields come from a fixed vocabulary, whether the ID that Replaced by points to exists, whether the L0 entry line count exceeds a threshold, whether every operation has a corresponding entry in the routing table, whether Stable IDs are unique and well-formed. doc-lint can hook into CI or commit hooks to catch violations before merge. It's especially important in Agent collaboration because the reader and author of documentation are often different sessions of the same Agent: the Agent that wrote the spec may violate it in its next session, and it neither remembers the convention nor reviews the whole. Every convention a machine can check should eventually become a check, so the layer baseline "can only go down, never up"; humans keep only the arbitration duties that are hard for machines to formalize, such as judging whether a boundary belongs to L1 or L2. Without doc-lint, all layering principles degrade to good-faith maintenance and inevitably drift.

Summary

  1. Agents aren't amnesiac; they never had cross-session memory. Every session is a newcomer walking in through the entry. Fix the entry, not the Agent.
  2. The primary reader of documentation is the Agent; humans shift from reader to arbiter; deliverables are counted separately; one document serves one reader.
  3. The entry only routes, it doesn't carry content; the resident layer holds only rules that would be too late to discover after the fact; keep current fact and history separate; write status and replacement as fields.
  4. The four-layer model: L0 resident (must be short), L1 by work type (read only one), L2 by module / change (carries status and replacement), L3 evidence (never an entry).
  5. The system was forced out by incidents, and will break on its own: L0 bloat, blurred boundaries, and Agents writing docs forgetting just as much.

Series:

  1. Agents Aren't Amnesiac — They Just Can't Find the Doc Entrance: Documentation Layering for Large Projects (1) (this article)
  2. Letting Agents Read Only What They Should: Documentation Routing (2)
  3. Giving Every Document a Unique Position: Documentation Addressing (3)
  4. Keeping Documentation from Rotting: Documentation Lifecycle in the Age of Agents (4)

One-line Summary

Agents aren't amnesiac — they lack a path from the entry to the spec; documentation should be restructured for Agents as an L0–L3 routing system.

Paragraph Summary

Drawing on seven months of AI-collaborative development on an enterprise payment approval system, this article rebuts the popular complaint that "Agents always forget." The author points out that Agents never had cross-session memory to begin with — every session is a newcomer entering through the entry file — so the problem isn't the Agent but the entry file failing to take it where it needs to go. The whole article revolves around one thesis: in projects where Agents write most of the code, the primary reader of documentation is the Agent, and the documentation system is a routing system serving it. Starting from six real symptoms (not reading docs, treating outdated plans as truth, drowning in history, cases not traceable, nothing written back, each reading its own entry), the article traces back to two distinctions never made — resident vs. on-demand, current fact vs. history — and then proposes three principles and the four-layer L0–L3 model, candidly admitting every layer was forced out by incidents, and finally listing the three ways it will inevitably break.

#Agent documentation#AI collaboration#documentation layering#routing table#AGENTS.md#doc-lint#context engineering#LLM coding workflow
Share:

Related articles