Store your project documentation in your project repository
Documentation is the bridge between code and the people who need to work with it: maintainers, teammates, and your future self.
Good docs reduce onboarding time, cut repetitive back-and-forth, and preserve institutional knowledge. They are both a technical reference and a project memory that captures not only what the system does, but why it ended up this way.
When documentation is missing or stale, maintenance slows down, collaboration gets harder, and teams relearn the same lessons repeatedly.
That is why I recommend writing documentation early and updating it continuously. It keeps your project easier to evolve as the codebase and team grow.
Where should you store your documentation?
I advocate for keeping your documentation within the code repository, as the code repository is the single source of truth for your project.
By storing your documentation close to your code, you reduce the chances that your documentation will become stale. And by storing your documentation close to code, you enable a whole host of other features and tools that can make your life much easier.
Introduction to the Diataxis framework
The Diataxis framework helps you write with clearer intent by splitting documentation into four categories: tutorials, how-to guides, explanations, and reference. Each category serves a different reader need, which helps you avoid mixing beginner guidance with deep design rationale or API facts.
When deciding what to write, start with the reader's immediate goal:
- Tutorials: For newcomers learning the basics
- How-to guides: For users trying to solve specific problems
- Explanations: For those seeking deeper understanding
- Reference: For users needing technical details
When to add documentation
The best time to write documentation is while context is still fresh. That is when details are accurate, tradeoffs are still visible, and examples are less likely to be fabricated from memory.
Documentation also belongs close to the code. Putting docs in the same repository gives you a single source of truth and makes updates part of normal development, not separate "cleanup work."
Here are high-leverage moments to add or update docs:
- Right after implementing a new feature
- When fixing a complex bug (document the root cause and solution)
- During code review, when explaining design decisions
- While writing tests, as test cases often make excellent documentation examples
Code comments as documentation
Code comments are part of your documentation system. They help human readers understand intent, and they also give AI tools better raw material when generating narrative documentation drafts.
The same rules still apply: comments should clarify what the code alone does not make obvious.
Good commenting practices include:
- Explain the "why" rather than the "what"
- Document assumptions and edge cases
- Include examples for complex algorithms
- Reference related documentation or tickets
- Add type hints and docstrings for better AI comprehension
AI assistance in documentation
AI can make documentation work much faster, especially when you make your expectations explicit in repo configuration files. If those instructions live in your project structure, AI output becomes more consistent, and you spend less time fixing missing docs after code is written.
AI Configuration Files
Store your AI instructions in configuration files that are part of your
standard project structure. Prefer a root AGENTS.md as the single
operating manual for coding agents in the repo (see
Building repository memory with AGENTS.md); keep
optional, task-specific skills under .agents/skills/ as in
Start with a sane repository structure.
Agent operating manual (AGENTS.md at the repository root):
# Agent instructions for this repository
## Documentation
- Follow the project's documentation conventions for narrative docs.
- Always add type hints to new or changed Python code.
- Write Sphinx docstrings for public APIs.
- Include docstring examples when behavior is non-obvious.
- Document edge cases and error handling when callers care.
- Add or update tests in `tests/` for user-visible or regression-prone behavior.
Cursor Rules (.cursorrules):
Docstrings should be in Sphinx format.
Testing framework should be pytest.
Type hints should be required.
Always document the "why" not just the "what" in comments.
Include examples for complex algorithms.
Claude Instructions (CLAUDE.md):
# Claude Configuration for Code Documentation
When writing or modifying code:
1. Always include comprehensive docstrings in Sphinx format
2. Add inline comments explaining complex logic
3. Document assumptions and edge cases
4. Include type hints for all function parameters
5. Write accompanying tests with clear test names
6. Explain the reasoning behind design decisions
The Developer's Role
You should always review AI-generated documentation for correctness. AI is excellent for first drafts, but quality control is still your job:
- Verify technical accuracy
- Ensure examples work correctly
- Check that the documentation matches the actual implementation
- Add context that AI might have missed
- Update documentation when requirements change
What AI can and cannot infer
AI is strong at synthesizing what code does. Given relevant modules, tests, and existing docs, it can usually summarize behavior, APIs, and likely drift faster than a human first pass.
What it cannot reliably recover is intent that was never written down. Why a boundary exists, why a simpler design was rejected, what operational constraint shaped an interface, and which tradeoffs were accepted in conversation are often invisible in code.
So prioritize documenting decisions, constraints, and tradeoffs that are not
inferable from reading code alone. Treat these notes as first-class docs;
they preserve institutional knowledge and make later drift audits more useful.
For a broader repository-memory workflow, see
Building repository memory with AGENTS.md.
How Standard Project Structure Supports Documentation
The standard layout from
Start with a sane repository structure
supports documentation by giving docs/ a first-class place from day one.
A minimal structure looks like this:
project/
├── docs/ # Dedicated documentation directory
│ ├── index.md # Main documentation entry point
│ ├── api.md # API reference documentation
│ └── ...
├── README.md # Project overview and quick start
├── mkdocs.yaml # Documentation configuration
└── ...
This structure ensures that:
- Documentation has a dedicated, organized space
- Documentation tools are configured from day one
- The project follows documentation best practices from the start
- AI-generated documentation has a clear place to live
Reference documentation
The fourth Diataxis category, reference, usually includes API documentation. There are many tools for generating and publishing it; choose the stack your team can maintain consistently.
Python-specific tools
- Sphinx: The standard for Python projects
- pdoc: Automatic API documentation generator
- mkdocs: A static site generator that's great for building documentation websites.
Pairs well with
mkdocs-material, which this book is written in. - doctest: A tool for testing code examples in documentation
This e-book is built with mkdocs and mkdocs-material,
which should give you a feel for my preferred tooling.
API Documentation
- Swagger/OpenAPI: For REST API documentation
- GraphQL Schema Documentation: For GraphQL APIs
- TypeDoc: For TypeScript/JavaScript projects
Whatever your organization uses, keep the relevant configuration files in your standard project structure so the workflow stays visible and repeatable.
Automating documentation with CI/CD
Keeping docs in-repo is great for maintainers, but many readers are outside your development tools. CI/CD can bridge that gap by publishing docs automatically to destinations like Confluence whenever docs change.
Here is an example GitHub Actions workflow for md2cf:
name: Publish Docs to Confluence
on:
push:
branches: [main]
paths:
- "docs/**"
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Publish to Confluence
run: |
uvx md2cf \
--space "TEAM" \
--parent "Project Docs" \
--update-existing \
docs/
env:
CONFLUENCE_URL: ${{ secrets.CONFLUENCE_URL }}
CONFLUENCE_TOKEN: ${{ secrets.CONFLUENCE_TOKEN }}
Here are some additional ways you can think about automation:
- Set up pre-commit hooks to check documentation formatting
- Use documentation testing tools to verify code examples (e.g.
doctest) - Configure automated broken link checking using the markdown-link-check GitHub Action.
When you combine clear doc types (Diataxis), in-repo storage, and automated publishing checks, docs become part of the delivery pipeline instead of a side project.
Auditing and improving documentation
Documentation drifts. Code changes; dependencies get upgraded; defaults get tweaked; error handling evolves. Unless you deliberately check for drift, your docs can quietly become an attractive nuisance: they look authoritative, but they are subtly wrong.
When you tell yourself "improve documentation," that is usually too vague to act on. I find it more effective to ask concrete comparison questions: what is implemented vs what is documented. These are exactly the checks AI tools can do quickly when you provide the relevant code and docs.
Here are six questions I routinely ask.
- What's in code that isn't reflected in docs, and should be added? Missing parameters, changed defaults, new side effects, newly supported inputs, and non-obvious invariants.
- What's in docs that isn't reflected in code, and should be removed? Stale claims about features, arguments that no longer exist, or old workflows that were superseded.
- What's in code and docs that contradict each other? Behavior changes that were never written down, or documentation updates that were made without implementation checks.
- What examples no longer work? Imports from old modules, old filenames, or snippets that no longer match the public API.
- What error paths and edge cases are undocumented? Validation rules, exceptions raised, retry behavior, rate limits, and "it depends" branches.
- What's documented but hard to find? Useful information that exists, but is buried, inconsistently named, or not linked from where readers naturally look first.
Copy-paste prompts
Below are prompts you can copy and paste into your AI tool. Where you see a placeholder block, paste the relevant code and docs directly; do not make the model guess.
Find missing documentation (code → docs)
You are auditing documentation drift.
Task: identify what is implemented in the code but missing from the documentation.
Rules:
- Only use evidence from the provided code and documentation.
- Be specific: name parameters, defaults, return values, side effects,
invariants, and error cases.
- Propose concrete text to add to the documentation (1-5 sentences per finding).
Code:
<paste code here>
Documentation:
<paste docstring/README/docs page here>
Find stale documentation (docs → code)
You are auditing documentation drift.
Task: identify what the documentation claims that is not true in the code anymore.
Rules:
- Only use evidence from the provided code and documentation.
- For each stale claim, quote the doc sentence, then point to the
contradicting implementation detail.
- Propose an edit: either delete, rewrite, or mark as deprecated.
Code:
<paste code here>
Documentation:
<paste docstring/README/docs page here>
Find contradictions (code ↔ docs)
You are auditing documentation drift.
Task: find contradictions between code and documentation, then resolve them.
Rules:
- Only use evidence from the provided code and documentation.
- List contradictions as pairs: "Doc says ..." vs "Code does ...".
- For each, propose which should change (docs, code, or both) and why.
Code:
<paste code here>
Documentation:
<paste docstring/README/docs page here>
Check examples for rot (docs examples)
You are auditing documentation drift.
Task: review the documentation and identify code examples
that are likely to fail today.
Rules:
- Only use evidence from the provided documentation and any provided code/API
notes.
- Flag examples that depend on old import paths, old function signatures,
renamed files, or missing setup.
- For each flagged example, propose a corrected version of the example.
Documentation:
<paste docs page(s) here>
Current API notes (optional):
<paste any relevant public interfaces or module exports here>
Find undocumented edge cases (error paths)
You are auditing documentation drift.
Task: identify error handling and edge cases in the code that are not documented.
Rules:
- Only use evidence from the provided code and documentation.
- Focus on user-visible behavior: validation rules, exceptions raised, retries,
warnings, and failure modes.
- Propose a short "Edge cases and errors" section suitable for the existing
documentation.
Code:
<paste code here>
Documentation:
<paste docstring/README/docs page here>
Audit discoverability (docs information architecture)
You are auditing documentation discoverability.
Task: identify important information that is hard to find even if it exists.
Rules:
- Only use evidence from the provided documentation structure and content.
- Suggest link additions and small reorganizations that improve navigation
without rewriting the whole docs set.
- Use Diataxis categories when proposing moves
(tutorial/how-to/explanation/reference).
Documentation index / nav:
<paste mkdocs nav or table of contents here>
Docs pages (key excerpts):
<paste key headings + first paragraphs here>
A downloadable agent skill
If you want these prompts and the workflow packaged as a reusable unit,
this repo includes an Agent Skills format skill you can download and reuse:
skills/docs-audit/SKILL.md.
The skill follows the Agent Skills specification and contains:
- The audit questions
- Copy-paste prompts
- A step-by-step workflow you can run repeatedly