Documentation checks that run at commit time, for repositories where agents are the primary readers.
A doc that is wrong is worse than a doc that is missing. A missing doc makes the agent look; a wrong doc makes it act.
Every repository accumulates the same rot, and none of it is anyone's fault:
- A plan says "implementation complete" in its body and still sits in
plans/active/. The next agent reads it as current work. - A policy cites an ADR that was superseded a month ago, so the reasoning an agent follows is a decision the team already reversed.
- The plan index lists 14 of 22 files, because it is maintained by hand and hands forget.
- A module guide grows to 23 KB of hard-won gotchas, and Codex silently truncates it at the 32 KiB instruction-chain limit — the agent never sees the part that mattered.
- Eleven documents are not linked from anywhere. Routing cannot reach them. They are alive in git and dead in practice.
All five are structural, and structure is checkable. docanchor checks it at commit time, in CI, and after merge.
It is not a documentation generator, a wiki, or a knowledge base. Your markdown files stay exactly as they are. There is no conversion step and no database.
Two things are derived: the plan/ADR indexes (regenerated between marker comments, leaving your prose alone) and a link graph (.docanchor/, gitignored, rebuilt in under a second). Delete either and every check still passes — they are caches, not sources.
Each rule carries, in code, the observed failure it prevents and the condition under which you should delete it. A rule with no observed failure does not get added. The cap is fifteen; to add a sixteenth you remove one.
| Rule | Catches |
|---|---|
link-integrity |
Links that point at files which no longer exist, plus merge-conflict markers |
adr-contract |
Missing ADR fields, invalid status, broken supersede chains, reused numbers |
plan-contract |
Free-form status text, "complete" plans still in active/, in-progress plans with no changelog line |
routing |
A router that points into the archive; representative questions that no longer reach the right doc |
cited-paths |
Commands and paths quoted in prose that do not exist |
symlinks |
An agent guide that stopped being a symlink and silently diverged |
reachability |
Documents nothing links to |
generated-index |
An index that disagrees with the actual file list |
guide-size |
Instruction files past the byte limit your agent will truncate at |
verified-date |
"Current rules" documents nobody has checked against code lately (warning only) |
tool-neutral |
Vendor-specific syntax in a file two different agents read |
superseded-link |
A current policy citing a decision that was reversed |
policy-test-link |
A policy with no test that enforces it |
Every rule has a fixture test. Delete a rule and its test fails first — the checking apparatus protects itself.
docanchor scan --baseline # infer config, accept today's violations
docanchor plan # what to fix, in what order, by whom
docanchor related src/billing/quota.ts # code path → routed docs and their tests
docanchor affected docs/policies/quota.md # who relies on a doc you just edited
docanchor links docs/policies/quota.md # inbound, outbound, supersede chain
docanchor index --apply # regenerate plan and ADR indexes
docanchor move --from A --to B # move a file, rewrite every inbound link
docanchor split guide.md --section Gotchas --to docs/flows/x.mdmove and split are dry-run by default. They print the old→new map, the affected links with line numbers, and the collisions. Nothing is written without --apply.
The checks are only half of it. The other half is the rules a project agrees to, and those ship as a template you adopt and edit:
templates/docs/README.md— where documents live and what each kind is for, the six plan statuses and what moves a plan between them, the lifecycle order (distill then archive), what must never be copied into a doc, who reads what, how to move a file safely, the rule budget, and the four-line recovery procedure.templates/CLAUDE.md.snippet.md— five hard gates for your agent instruction file, including the authority order documents are read in.
RATIONALE.md explains why each rule exists — the observed failure behind it, what was deliberately left out and under what condition to reconsider, and how the design avoids constraining models that get better than the one it was written for. (In Korean.)
Read this before you start. On a repo of any age the first check fails loudly — 76 violations on the one this tool came from. That is your current state, not a verdict. Two things make it manageable.
A baseline. docanchor scan --baseline records today's violations and then fails only on new ones. You fix the old ones as you touch those files. Adoption friction drops to roughly zero, and new documents obey the rules from day one. The baseline is not an escape hatch: the count may only go down, and check tells you when entries have been resolved so you can re-record.
An honest split of the work. docanchor plan orders the violations and marks each as tool or human. On the repo this came from that split was 18 tool / 58 human. The tool half takes a few commands. The human half is where the time goes, because deciding whether a plan is finished means reading the code.
This tool assumes an agent session does the judging and a person approves a table. On that repo the migration cost the human about 15 minutes of reading and twelve approvals; it cost the agent session several hours. Doing the same work by hand, without an agent, is days.
docanchor planprints a prompt you can paste into a session to start that.
It does not require your structure. Rules whose concept does not exist in your repo turn themselves off, and check always prints which ones and why — silence would make that a switch. A repo with no docs/policies/ still gets link integrity, ADR contracts, reachability, guide size, and tool neutrality. docanchor scan infers what it can (the ADR directory from numbered filenames, instruction files by name, the router by link density) and leaves the rest blank.
What it cannot infer is the line between a policy and a plan. Both are prose; whether a document states a current rule or a future intention is something only you know. That distinction is the one structural thing this tool asks of you.
npx docanchor initThis copies templates for docs/README.md, index.md, the plan and ADR templates, findings.md, and current-state.md, plus a docanchor.config.json. It never overwrites a file you already have.
Then edit docanchor.config.json — mainly guides.sizeLimits (your instruction files and their byte caps) and router.scenarios (representative questions that turn your docs into tests).
Expect the first docanchor check to fail loudly. That is your current state. Fix one rule at a time.
Why byte limits on instruction files. Codex concatenates global + root + current-directory instruction files and stops at project_doc_max_bytes (32 KiB by default). In the repository this came from, that chain hit 43,911 bytes and the module guide was being cut off with no warning. Splitting one section out brought it to 24,408.
Why the router is a default, not a gate. Guidance helps by getting the agent to the right file, and hurts when it blocks the agent from a file it needed. The rules say routing is where you start, and docanchor links is how you widen.
Why rules carry a retirement condition. Models improve. A rule written for a weaker model can end up constraining a stronger one. docanchor harness-eval runs your representative questions under three conditions — no harness, minimal, current — so a rule that stops earning its place can be found and removed.
Why the lint pass writes findings instead of fixing. Semantic checks (does this doc still describe what the code does?) run at roughly 0.6 precision. One finding in three is a false positive. Recording them for a human beats editing docs on a coin flip.
Apache-2.0. See LICENSE.