I built doclink-auditor to catch broken Markdown links before documentation changes land. It scans a documentation tree, validates relative file links, checks GitHub-style heading anchors, reports unresolved reference links, and can optionally probe remote HTTP links with bounded concurrency.
Broken docs links usually slip in during refactors: files move, headings get renamed, and reference definitions stop matching the text that points at them. I wanted a small CLI that works in local repositories and CI without pulling in a browser, crawler, or large dependency chain.
npm install -g doclink-auditorOr run it directly from a checkout:
node src/cli.js --root .doclink-auditor --root docs
doclink-auditor --root . --format json
doclink-auditor --root . --check-http --timeout 8000 --concurrency 4| Option | Default | What I use it for |
|---|---|---|
--root <path> |
current directory | Directory to scan recursively |
--format text|json |
text |
Human-readable output or machine-readable CI output |
--check-http |
off | Probe http:// and https:// links |
--timeout <ms> |
5000 |
HTTP request timeout |
--concurrency <n> |
5 |
Maximum remote link checks at once |
--ignore <list> |
.git,node_modules,dist,coverage |
Comma-separated directory names or relative paths to skip |
--include <list> |
.md,.markdown |
Comma-separated file extensions to scan |
- Missing relative files such as
../guides/setup.md - Missing heading anchors such as
README.md#configuration - Duplicate heading slugs using GitHub-style
heading,heading-1,heading-2anchors - Missing reference link definitions such as
[install guide][install] - Optional HTTP status failures, with
401and403reported as warnings because protected endpoints can still be valid documentation targets
I keep the CI path intentionally small:
npm run ciThat command syntax-checks every JavaScript file and runs the Node.js test suite.
doclink-auditor scanned 4 files and 17 links.
Errors:
- docs/intro.md:12:8 missing-local-target ../api/reference.md
I could not find the linked file.
Warnings:
- docs/integrations.md:31:3 remote-forbidden https://example.com/private
The remote server returned 403, so I treated it as protected rather than broken.
MIT