On this page
- Why stale docs are worse than no docs
- Why documentation drifts
- Which doc claims can be checked
- Step 1: Run the check locally
- Step 2: Gate pull requests on new drift
- Step 3: Ask what a change will make stale before you make it
- Step 4: Let generated docs refresh from the diff
- What humans still own
- Pitfalls
- FAQ
Stale documentation is documentation that still makes claims the code has stopped honouring, and it costs more than having none. A missing page sends a reader to the source. A stale page sends them down the wrong path with confidence. The fix is to treat every checkable claim in your docs (a path, a link, a command, a function name) as something a tool verifies on each commit, and to let a generated wiki refresh itself from the diff.
Part of the auto wiki guide. For the wider picture see codebase documentation that stays current.
Why stale docs are worse than no docs
A stale doc is trusted, and a trusted wrong answer is more expensive than an honest gap. With no documentation, an engineer reads the code and knows they are reading the code. With a stale page, they follow an auth flow that was replaced last quarter, or run a script that was deleted, and only discover it after the time is spent.
The damage compounds. After a reader is burned two or three times they stop opening the wiki and ask in chat instead, so the docs lose their purpose even where they are still correct. New hires feel it first, because they cannot yet tell which pages are safe.
Why documentation drifts
Drift is a feedback problem, not a discipline problem. Three things cause it.
| Cause | What happens |
|---|---|
| Code has a compiler and tests, docs have neither | A rename breaks the build in seconds. The same rename breaks a doc silently, and nobody finds out until a reader complains. |
| Docs live outside the change | The wiki is a separate tool, so updating it means leaving the editor and the pull request. |
| No signal says a page is old | A stale page looks identical to a fresh one. Nothing fails. |
Scroll the table sideways to see every column.
Each has a mechanical remedy: check docs against the code automatically, keep docs in the repository so they ride the same pull request, and mark pages whose code has moved on.
Which doc claims can be checked
A claim is checkable when the repository itself can settle it. repowise's documentation drift check resolves five kinds of reference against the tree:
| Kind | The claim in the doc | Reported when |
|---|---|---|
path | Names a file or directory | Nothing exists at that path |
link | Links to another document | The target is not there |
anchor | Links to a heading | The heading was renamed or removed |
command | Tells you to run a script or target | The manifest no longer declares it |
symbol | Names a function, class or method | It was defined when the line was written and is defined nowhere now |
Scroll the table sideways to see every column.
The anchor case is the one teams do not expect. Renaming a heading breaks every link into it, and no ordinary toolchain notices.
The symbol kind is deliberately strict. A backticked word in prose is usually just a word, so repowise flags a name only when git blame finds the commit that wrote the line and a source file at that commit defined a symbol of exactly that name. Names that were never symbols are not reported. When git records where the code moved, the finding suggests the new name.
A clean run does not claim your docs are true. It claims the references that could be resolved did resolve. repowise does not judge whether a paragraph is accurate or well written, because a checker that guessed would be wrong often enough that nobody would trust its findings.
Step 1: Run the check locally
repowise doc-drift # everything above the confidence floor
repowise doc-drift --kind anchor # just links into renamed headings
repowise doc-drift --min-confidence 0.9 # the findings worth fixing without a second look
Every finding shows the line as the document wrote it, the heading trail, and what the resolver checked, so you can judge it without opening the file. When the tree says where a reference went (a file became a package, git records a rename, a heading has a close match), the finding carries a likely replacement. It is evidence for you to check. repowise never rewrites your documents.
The same check runs on every repowise init and repowise update. The four file-level kinds take well under a second.
Step 2: Gate pull requests on new drift
The practical CI gate fails a pull request only for drift that the change is answerable for. That avoids a gate that starts red on day one and gets disabled.
repowise doc-drift --check --since auto --format github
--check reads the working tree directly and needs git and nothing else: no index, no model, a few seconds on a large repository. It exits 1 on a finding at or above --fail-on-confidence (default 0.7). With --since auto, a finding counts only if the change edits its document, deletes or renames the file it names, edits the document its anchor points into, edits the manifest that declares its command, or edits or removes the file that defined its symbol. Use fetch-depth: 0 so the merge-base diff works.
To adopt the gate on a repository that already has drift, record a baseline and fail only on new findings:
repowise doc-drift --check --write-baseline .doc-drift-baseline.json
git add .doc-drift-baseline.json
repowise doc-drift --check --baseline .doc-drift-baseline.json # in CI
Output formats cover github annotations on the document line, sarif for GitHub code scanning, gitlab for the merge request Code Quality widget, and markdown for a comment you post yourself. The ready-made workflow is in repowise in CI.
Some references are deliberate, such as an invented path in a tutorial. Mark them in the document, so the decision travels with the text:
<!-- repowise-drift-ignore -->
Create `src/plugins/my_plugin.py` with the following contents.
Use <!-- repowise-drift-ignore-file --> to silence a whole document. Silenced references are counted in the report, not dropped quietly.
Step 3: Ask what a change will make stale before you make it
The drift check also reads in reverse. Before moving or renaming a file, ask which documents talk about it:
get_context(targets=["src/auth.py"], include=["doc_drift"])
That MCP call returns the documents that name the file, where in each, and whether they already carry drift. Agents can read a repository's drift through get_health(include=["doc_drift"]). See the ten MCP tools for the full set.
Step 4: Let generated docs refresh from the diff
Reference checks cover the docs people write. For the docs a tool writes, the answer is to regenerate only what a commit touched. repowise update finds the files changed since the last sync, walks the dependency graph for the pages those changes affect, and re-renders those, typically a handful per commit. It does not rebuild the whole wiki.
Two mechanisms decide what is stale. Model-written pages compare a hash of the rendered prompt with the stored one, so an unchanged prompt reuses the prior page and spends no tokens. Structure-rendered pages fold the subject's own hash with a fingerprint of the renderer, so a template change triggers exactly one regeneration. Each page carries a freshness status of fresh, stale, expired or unknown.
The wiki shows this on the page. A page written for an earlier commit is labelled as an older explanation, with a refresh control beside it.

To keep the index current without thinking about it, install the post-commit hook (repowise init does this by default) or run a file watcher:
repowise hook install # runs repowise update in the background after each commit
repowise watch # updates on save, for uncommitted work
Teams can use a GitHub or GitLab webhook instead, with a polling fallback. When the index is behind, agents are told: MCP responses carry a stale_warning when a file they served has changed. Details are in keeping the index fresh.
What humans still own
Tools can state what code does and how it is structured. They cannot recover why: the trade-off, the incident, the approach you tried and dropped. Keep that in decision records and in the pull request description, and let repowise capture architectural decisions from history alongside the generated pages.
Three habits keep the rest honest:
- Keep docs in the repository as Markdown, so they ride the same branch and review as the code.
- Generate the boilerplate: dependency lists, file trees and architecture views should never be typed by hand.
- Review docs in the pull request. With
--since auto, the reviewer sees drift the change caused, on the line it affects.
Pitfalls
- Treating a clean run as proof. It proves references resolve, not that prose is right. Keep reading the pages that describe behaviour.
- Shallow clones.
symbolchecks and rename suggestions need history, so usefetch-depth: 0. - A gate that fails on old debt. Use a baseline or
--since auto, not a global red build. - Silencing instead of fixing. Reserve the ignore marker for examples that are meant to be invented.
FAQ
- How often should documentation be updated?
- In the same pull request as the code it describes. When that does not happen, a check on every commit should flag the gap, so drift is caught within one merge instead of when a reader hits it.
- How do you detect outdated documentation automatically?
- Resolve the claims the docs make against the repository: paths, links, heading anchors, commands and symbol names.
repowise doc-driftdoes this with no model, reports each finding with the exact line, and can run in CI with--check. Other approaches are compared in best documentation drift detection tools. - Can AI keep all of my documentation up to date?
- AI is good at describing what code does and how it is structured, and a tool can regenerate those pages from each commit. The reasons behind a design still need a human to record them.
- What is documentation drift?
- Documentation drift is the growing gap between what docs claim and what the code now does. It starts the first time a merge renames, moves or removes something a page mentions.
- Does repowise rewrite my docs to fix drift?
- No. It reports findings and, where git shows where something moved, a likely replacement, and you decide whether to apply it. Wiki pages that repowise generates refresh on
repowise update. - Which languages does the wiki cover?
- repowise parses 28 languages to a full AST, with 15 at the Full tier, and builds the dependency graph the wiki is generated from. See the architecture page for how it is built.
