Progressive disclosure
Setting up your AGENTS.md well means designing it around progressive disclosure, just-in-time context loading, and retrieval on demand, so the agent only ever carries the context it actually needs, right when it needs it.
Why does this matter?
The problem: if an agent loads every rule file upfront, it burns a huge chunk of its context window before it has done any work, and the model has to wade through mostly irrelevant instructions to find what matters for the task at hand. That costs tokens, money, and accuracy.
Progressive disclosure
Keep the always-loaded prompt small on purpose. Only a handful of rules stay resident on every cold start; everything else waits until it is actually needed. In practice, this means writing a short summary or index that always loads, with the fuller detail kept in separate files that are pulled in only when relevant.
How you set that up depends on the host. Most hosts, Claude Code, Cursor, and plain markdown-based setups alike, support a small always-loaded entry file, commonly named something like AGENTS.md or a host-specific equivalent, that stays short by design and simply points at where the fuller detail lives.
Just-in-time context loading
Detail is fetched at the exact moment a condition is met, not stuffed in eagerly at session start. In practice, this means attaching a clear condition to each piece of detailed context, so it is only loaded once that condition is actually triggered, rather than every single time.
How you trigger that load depends on the host too. Hosts with a hook primitive, like Claude Code, can fire the load automatically off a tool call. Hosts without one rely on the agent reading a condition-to-file table in the always-loaded entry file and following it itself when a condition matches.
Retrieval on demand
A deterministic lookup from a condition to the exact piece of content needed, a lighter, non-hallucinating cousin of RAG. In practice, this means keying content off explicit, matchable conditions rather than a fuzzy search, so the right piece of context is found by a direct match, not a guess.
This works the same regardless of host, since it is just a table: one row per condition, pointing at exactly one file. No embeddings, no vector database, no similarity search, just a direct lookup any agent can follow.
.agents/rules/*.md is never preloaded into context. AGENTS.md carries only two small things on every cold start: a five-item Always block, and a Read before you act trigger index — one row per rule file, stating the condition, not the content. The measured effect on a real project: fixed always-loaded context drops from roughly 47k to 4.5k tokens.
This is: Just-in-time context loading
reads AGENTS.md only"] --> B["Always block
5 turn-level rules
~always paid"] A --> C["Trigger index
condition to file table
rows, not content"] C -. "no trigger fired yet" .-> D[".agents/rules/*.md
stays unread"] C == "editing auth / SQL / secrets" ==> E["workflow-security.md
read now, applied now"] C == "writing {{LANG}} code" ==> F["best-practices.md
read now, applied now"] C -. "opted-in, once per session" .-> G["workflow-testing.md /
workflow-metrics.md
read once, applied continuously"] style A fill:#27272a,stroke:#a78bfa,stroke-width:1.5px,color:#e4e4e7 style B fill:#3f2d63,stroke:#a78bfa,stroke-width:1.5px,color:#ede9fe style C fill:#3f2d63,stroke:#a78bfa,stroke-width:1.5px,color:#ede9fe style D fill:#18181b,stroke:#52525b,stroke-width:1px,color:#a1a1aa,stroke-dasharray: 4 3 style E fill:#4c1d95,stroke:#e879f9,stroke-width:1.5px,color:#f5d0fe style F fill:#4c1d95,stroke:#e879f9,stroke-width:1.5px,color:#f5d0fe style G fill:#4c1d95,stroke:#e879f9,stroke-width:1.5px,color:#f5d0fe
Reactive rules
Security, UI components, layered architecture, frontend, changes. Fire only when that specific surface is touched — read then, applied then, forgotten after. Equivalent to retrieval on demand rather than keeping the document in the prompt at all times.
Proactive-discipline rules
Testing, metrics, telemetry. Read once when opted in, then the discipline applies to every relevant change for the rest of the session — closer to a system instruction cached for the session than a one-shot retrieval.
Hooks & triggers
Rules only help if the agent can not talk its way out of them, which is what tool-call interception is for: catching every edit before it lands and injecting the right rule right then, instead of hoping the model remembers on its own.
Why does this matter?
The problem: a rule sitting in a text file is only a suggestion, and a busy agent under time pressure can simply forget it or talk itself past it. Nothing forces the rule to actually apply at the moment it is needed.
Tool-call interception
A hook inspects every action before it is allowed to land, acting as middleware that cannot be reasoned with, talked out of, or skipped. In practice, this means wiring a check into the point right before an edit or write happens, rather than relying on an instruction the agent has to remember and choose to follow.
How you wire that in depends on the host. In Claude Code, you register a PreToolUse hook, a small script that runs before every Edit or Write and can inspect or block the call. In Cursor, there is no hook primitive, so you get the closest equivalent with an always-apply rule file, one marked to load on every single message, so the rule is present before the edit rather than triggered by it. Hosts with neither option, such as Aider, Codex, Continue, Windsurf or Copilot, have to fall back to a clear, always-loaded index of conditions and rules, backed up by a check at commit time.
The trigger index is self-enforcing on hosts that support it. Claude Code registers rule-reminder.sh as a PreToolUse hook: before every Edit or Write, it reads the target path off stdin, matches it against a case ladder mirroring the trigger index, and injects a one-line reminder naming the rule — deduplicated per session so a long sweep costs one reminder per rule, not one per file. Cursor gets the same rows a different way: an always-apply .mdc file the host injects on every message. Hosts with no hook primitive fall back to the trigger index text alone plus a pre-commit sweep.
This is: Tool-call interception / middleware, grounded by pattern-matching not a model call
Why pattern match, not a model call
The hook is a plain bash script with a case statement, not another LLM call. Zero latency, zero cost, and it cannot hallucinate a wrong rule — it can only miss an un-listed path.
Pre-facto vs post-facto
The hook fires before the edit lands. A second mechanism, check_consulted_rules.sh, runs at commit time as a pre-commit check over the same case ladder — a safety net, not the primary control.
Graceful degradation
Aider, Codex, Continue, Windsurf and Copilot have no hook primitive. Doctor mode silently skips the hook-smoke-test check on those hosts — the trigger index text is the whole mechanism there.
Persistent memory: prompts, ADRs, and TODOs
A chat window forgets everything the moment it closes, so any decision or deferred task that matters later has to be written down somewhere the next session will actually read, not just remembered and hoped for.
Why does this matter?
The problem: an agent's context window is temporary. Decisions made, reasons given, and work deliberately set aside all disappear once the session ends, so the next session either repeats the same debate or forgets the deferred work entirely.
External / long-term memory
State that needs to survive past one session gets written to a plain file outside the chat, and read back before acting, rather than trusted to the model's memory. It does not matter what you call these files, what matters is that they are durable, checked into version control, and actually read before related work starts.
In this project that takes the shape of three logs. Architecture decision records, one file per significant decision, capturing the context, the decision, and its consequences. TODOs, one file per deferred task, capturing why it was deferred and what should trigger revisiting it. And prompt files, one file per task, capturing what was actually asked. Every interaction is a prompt, but they are smartly grouped: while the back-and-forth stays on the same task, it keeps amending that one task's prompt file; the moment the conversation moves to a new task, a fresh prompt file is started for it. Neither ADRs nor TODOs are auto-deleted, removal requires citing the specific change that closes it out, and git history is the permanent archive either way.
Because these files live in the repository, not in one person's chat history, the whole team benefits from them, not just whoever made the original decision. Any engineer, human or agent, can read the reasoning and trade-offs behind a past choice instead of re-litigating it from scratch. And because the prompt log preserves what was actually asked, task by task, nobody has to re-teach the agent the same context twice, or burn hours reverse-engineering why something was built the way it was — the history reads it back for them.
Two append-mostly logs under .docs/ carry state across sessions that would otherwise live only in a chat window and vanish. Neither is auto-swept — removal requires citing the specific change that closes the entry, and when in doubt the file stays. Git history is the only archive.
This is: External memory / long-term memory store, read back before acting
per task, not per turn"] --> P2["Write .docs/prompts/<slug>.md
What was actually asked"] end subgraph ADR["Architecture Decision Records"] direction TB A1["New dependency,
module or pattern"] --> A2["Write .docs/adrs/<n>.md
Context / Decision / Consequences"] A2 --> A3["Index in adrs/README.md"] end subgraph TODO["TODOs"] direction TB T1["User defers work
'skip this for now'"] --> T2["Write .docs/todos/<slug>.md
Context / Deferred because / Revisit when"] T2 --> T3{"Revisit when
trigger fired?"} T3 -- no --> T2 T3 -- "yes, cite the commit" --> T4["git rm in the closing commit"] end P2 -.->|"read before repeating a task"| R["Next agent session"] A3 -.->|"read before structural changes"| R T2 -.->|"read before related work"| R style A2 fill:#3f2d63,stroke:#a78bfa,stroke-width:1.5px,color:#ede9fe style P2 fill:#3f2d63,stroke:#a78bfa,stroke-width:1.5px,color:#ede9fe style T2 fill:#3f2d63,stroke:#a78bfa,stroke-width:1.5px,color:#ede9fe style R fill:#4c1d95,stroke:#e879f9,stroke-width:1.5px,color:#f5d0fe style T4 fill:#18181b,stroke:#52525b,stroke-width:1px,color:#a1a1aa
Prompts: what was actually asked
One file per task, amended as the task continues rather than duplicated per turn. It answers what ran on day N the way ADRs answer why the project looks like this — a task-scoped log, not a turn-scoped transcript.
ADRs: why, not just what
Short by design — Context and Decision usually a paragraph each, Consequences a bulleted list. Readable in under a minute. The point isn't documentation for its own sake, it's giving a future agent session the trade-off it would otherwise have to re-derive or guess at.
TODOs: deferral with a trigger, not a wish
Every entry needs a concrete Revisit when condition — a date, a merged PR, "next commit that touches this subsystem." A todo without a re-check condition is just guilt with a filename.
The big picture
The full run from the architecture overview, redrawn as one image and tinted by which concept bucket each stage belongs to — the same four ideas from the sections above, now shown as boundaries rather than separate diagrams. Built as a plain SVG rather than a flowchart render, specifically so it holds up as a single shareable image.
One picture, four concept boundaries
Progressive disclosure
Originally a UX-design term (show only what's needed, when it's needed). Repurposed here for context window management: keep the always-loaded prompt small, pull in rule detail on demand — AGENTS.md and the trigger index carry the whole always-on cost, while the dozens of rule files underneath it stay unread until a trigger actually matches. That is what keeps a 5,000-line framework from ever showing up as a 5,000-line prompt.
Hooks & triggers
A hook sits between "agent decides to act" and "action actually runs," able to inspect or augment it — tool-call interception, in framework terms. Here it's a plain pattern match against the file path or tool name, not a model call, so it can't hallucinate a wrong rule, only miss an un-listed path. On hosts without hook support, the trigger table in AGENTS.md is the fallback enforcement.
Persistent memory
State that outlives a single context window by living outside it — plain files under .docs/ read back by a future session, rather than a specialized vector or graph memory store. ADRs capture the "why" behind a decision; TODOs capture the "not yet, and here's when to revisit" — both are the agent's only way to remember anything past the end of the current run.
File lifecycle & grounding
Canon, Mixed, Sacred and New-each-run are deterministic write rules, not model judgment calls — every file the bootstrap touches falls into exactly one bucket, and the bucket decides whether it gets overwritten, diffed and asked about, or left alone forever. Doctor mode audits for the same grounding principle in a read-only pass that ends in a report, never a write.
Concept glossary
None of these mechanics are novel research — the bootstrap's contribution is wiring known context-engineering patterns into one coherent, file-based system. Here's the mapping from what the bootstrap calls things to the terms you'd search for elsewhere.
Progressive disclosure
Originally a UX-design term (show only what's needed, when it's needed). Repurposed in context-engineering for context window management: keep the always-loaded prompt small, pull in detail on demand.
Just-in-time context loading
Content is fetched and injected at the moment a condition is met, not eagerly at session start. The opposite is eager loading — stuffing everything possibly relevant into the system prompt up front.
Retrieval on demand
A lighter-weight cousin of retrieval-augmented generation: instead of a vector search over a corpus, retrieval is a deterministic path-to-file lookup — cheaper and non-hallucinating, at the cost of only covering cases the trigger table anticipated.
Tool-call interception
A hook sits in the path between "agent decides to call a tool" and "tool actually runs," able to inspect, augment or block. Common in agent frameworks under names like middleware, guardrails, or pre-execution hooks.
External / long-term memory
State that outlives a single context window by living outside it — here, plain files read back by a future session — rather than a specialized vector or graph memory store. Same goal as agent-memory research, low-tech implementation.
Grounding
Every reminder the hook emits is grounded in a literal file path match, not a model's judgment call — trading recall (it only knows the paths it was told about) for precision (it never invents a rule that doesn't exist).
What to implement, if you want this yourself
If you're building your own version of this, these are the concepts you'd actually need to apply. Each one on the right is a real, nameable technique from AI and context-engineering practice — and each bootstrap feature on the left is what it looks like once that concept is built and wired in.