Documentation as Context
READMEs, type annotations, and inline docs that serve as agent navigation aids
Overview
Structure tells an agent where to look. Names tell it what files contain. But documentation tells the agent why things work the way they do, how components connect, and what constraints must be respected. In this lesson, we explore the four layers of documentation that serve as navigation aids for AI agents: README files, type annotations, docstrings, and inline comments. Each layer operates at a different scope, and together they form a context stack that lets agents work confidently without guessing.
The Documentation Context Stack
An agent builds its understanding of your code layer by layer, starting broad and narrowing down. Each documentation layer answers different questions.
The documentation context stack from broad to narrow: CLAUDE.md / Root README (project purpose, architecture, conventions), Directory README.md (module purpose, API surface, patterns), Type Annotations (function contracts, data shapes), Docstrings / JSDoc (behavior, constraints, edge cases), and Inline Comments (why non-obvious decisions were made).
The agent reads these layers in order: it starts with the project-level CLAUDE.md, drills into directory READMEs as it navigates, reads type signatures when it opens files, scans docstrings for functions it plans to call or modify, and finally reads inline comments when it needs to understand specific implementation decisions.
Documentation is not just for humans who read code. It is machine-readable context that directly determines agent accuracy.
Layer 1: Directory-Level READMEs
A README.md in each feature directory gives the agent a briefing before it dives into the code. This is especially valuable for modules with complex internal structure or non-obvious patterns.
This README answers the five questions every agent asks when entering a module:
- What does this module do? (Purpose)
- What can I use from it? (Public API)
- How is it structured internally? (Key Patterns)
- What should I avoid? (Do NOT section)
- Where are the tricky parts? (implicit in patterns and constraints)
The "Do NOT" section is particularly powerful. Agents follow instructions well, and explicit prohibitions prevent the most common mistakes.
Layer 2: Type Annotations
Type annotations are the most efficient form of documentation for agents. Unlike prose comments, types are machine-verifiable, always up to date (the compiler enforces them), and convey precise information about function contracts.
Consider what an agent learns from this function signature alone:
Without reading a single line of the implementation, the agent knows:
- The function takes a structured input with required and optional fields
- It accepts behavioral options as a second parameter
- It returns a promise containing an order, an invoice, and a delivery estimate
- The
customerIdis a string, not a number - The
couponCodeis optional (the?suffix) - The function is async
This is context for free. The type system communicates the contract, and the agent can write calling code correctly without reading the function body.
Typing in Dynamic Languages
In languages without a static type system, type hints serve the same purpose:
Python type hints, Go type signatures, and Rust's type system all serve the same agent-context purpose: they tell the agent what a function expects and returns without requiring it to read the implementation.
Rule of thumb: If your language supports types, use them everywhere. Every untyped function is a function the agent must read fully to understand.
Layer 3: Docstrings and JSDoc
Types tell the agent what a function accepts and returns. Docstrings tell it why, when, and what to watch out for.
This docstring tells the agent critical things that types alone cannot convey:
- The order must be in "completed" status (a precondition)
- Partial refunds are supported (a capability)
- The amount is in cents (a unit convention)
- Three specific error types can be thrown (the failure modes)
- There is a concrete usage example (a template to follow)
When to Write Docstrings
Not every function needs a docstring. Focus on:
- Public API functions that other modules call
- Functions with preconditions (the order must be in a certain state)
- Functions with non-obvious side effects (sends an email, writes to a queue)
- Functions where the name alone is insufficient (complex business logic)
Skip docstrings for trivial getters, simple utility functions, and private helpers whose purpose is clear from the name and types.
Layer 4: Inline Comments
Inline comments are the most granular form of documentation. They explain why a specific line or block of code exists, not what it does (the code itself shows that).
Each comment in this example explains a decision that the agent would not be able to infer from the code alone:
- Why there is a minimum weight (carrier requirement)
- Why Alaska/Hawaii use a different zone (business decision)
- Why the rate is calculated before checking the free shipping threshold (downstream dependency)
Without these comments, an agent modifying this function might "optimize" away the minimum weight, apply the correct zone for Alaska, or move the free shipping check earlier -- all technically reasonable changes that would introduce bugs.
Comments to Avoid
Not all comments help agents. Some actively mislead:
The best inline comment answers a question that starts with "why" -- not "what."
Connecting the Layers
The documentation stack works best when each layer complements the others without duplicating them. Here is how information should flow:
How documentation layers connect without duplicating: README covers module purpose, public API, key patterns, and prohibitions. Types cover input shapes, output shapes, optional vs required, and generic constraints. Docstrings cover preconditions, side effects, error conditions, and usage examples. Inline comments cover business decisions, external constraints, non-obvious dependencies, and historical context. Each layer feeds into the next.
- README tells the agent what a module is and how to use it (broad scope)
- Types tell the agent what a function expects and returns (function scope)
- Docstrings tell the agent about behavior, preconditions, and errors (function scope, semantic depth)
- Comments tell the agent why specific implementation choices were made (line scope)
No layer should repeat information from another. The README should not list every function parameter (that is what types and docstrings are for). Docstrings should not explain business decisions (that is what inline comments are for). Each layer adds unique context at its appropriate scope.
The Documentation Checklist
Use this checklist to evaluate your project's documentation coverage:
- Every feature directory has a README.md with purpose, public API, patterns, and prohibitions
- All public functions have type annotations for parameters and return values
- Functions with preconditions, side effects, or non-obvious behavior have docstrings
- Non-obvious implementation decisions have inline comments explaining "why"
- No comments restate what the code already says
- No commented-out code blocks remain in production files
- Type annotations cover all function signatures, not just some
- The CLAUDE.md references documentation conventions so the agent follows them when writing new code
Summary
Documentation is not separate from your code -- it is context that agents consume to work accurately. The four layers -- README files, type annotations, docstrings, and inline comments -- operate at decreasing scope and increasing specificity. Type annotations are the highest-leverage investment because they are machine-verifiable and always current. Directory READMEs provide module-level briefings that save agents from exploring blindly. Docstrings capture behavior that types cannot express. Inline comments preserve the "why" behind non-obvious decisions. Together, these layers give agents the context they need to write correct, convention-following code. In the next lesson, we will apply these principles to the unique challenges of monorepos and large codebases.