documentation drift detector · no network · nothing executed

Docs don't break loudly — they drift. A renamed flag, a moved file, an example that imports a function you deleted last quarter. devdoctor reads your markdown, reads your code, and reports every place they disagree.

$ npx @sajurjyabora/devdoctor check-docs
github ↗

▼ the rest of this page is a terminal session

$devdoctor check-docs ../dotenv # 120M downloads a week


check-docs · ../dotenvreal output
devdoctor · check-docs ../dotenv
Broken internal links (2)
─────────────────────────────────────────────
BROKEN README.md:67
anchor "#how-do-i-use-dotenv-with-import"
doesn't match any heading in this file
BROKEN README-es.md:65
anchor "#como-uso-dotenv-con-import" — the same
link, in the Spanish translation
─────────────────────────────────────────────
2 issues (2 broken) · 6 markdown files · 0.5s
$

That's dotenv — 120 million downloads a week. The "Import with ES6" link near the top of its README points at a FAQ heading that no longer exists. Open the README and click it yourself; that's the whole verification. devdoctor found it — and its Spanish twin — in half a second.

$cat WHY.md # the case for a doc doctor


  • Your README is your onboarding.

    The first command a new user ever runs comes out of it. When that command fails, they don't file an issue — they close the tab. devdoctor makes sure the quick start actually starts.

    working install instructions, always
  • Code review can't see drift.

    The pull request that renames a flag never touches the README, so nothing in review flags the contradiction. Drift only surfaces when a stranger follows your instructions — devdoctor surfaces it before they do.

    catches what review structurally can't
  • Trust compounds.

    Docs that stay true get read. Docs that lie once get ignored forever. A CI gate keeps every example, link, and version honest without anyone having to remember to check.

    documentation people actually believe

$devdoctor check-docs # five detectors · zero config


  • BROKEN
    Internal links that go nowhere link target CONTRIBUTING.md doesn't exist — files, sections, and #anchors are checked against real headings.
  • BROKEN
    CLI drift flag --minify isn't defined by the CLI — documented commands are diffed against your actual commander, yargs, click, or argparse definitions.
  • BROKEN
    Code blocks that don't parse JS and TS blocks go through Babel, Python through your local interpreter. Parsed, never run.
  • STALE
    Version numbers frozen in time docs say 2.0.0, package.json says 3.1.0 — prose claims, install pins, and badges are checked against your manifests.
  • BROKEN
    Dead imports in examples import { destroyWidget } — no such export in the source. → did you mean "resizeWidget"?

$devdoctor --help # how to use it


Usage
  devdoctor check-docs [path] [options]

Options
  --json      findings as machine-readable JSON
  --quiet     print only the summary line
  --no-color  plain output for dumb terminals

Exit codes
  0 docs are clean   1 drift found   2 usage error
  1. Run it once, from anywhere.
    npx @sajurjyabora/devdoctor check-docs at your repo root. No install, no config file, no account.

  2. Read the report.
    Every finding carries a file and line number, a severity, and — when devdoctor can guess — a did-you-mean.

  3. Fix the BROKEN, judge the STALE.
    A stale version is sometimes intentional. A broken link never is.

  4. Add the CI gate below.
    From then on, the pull request that causes drift is the one that fails.

$cat .github/workflows/devdoctor.yml # drifted docs fail the build


Exit code 0 when docs are clean, 1 when they've drifted. Paste this once and your README stays true from now on.

name: docs
on: [push, pull_request]

jobs:
  check-docs:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: 20 }
      - run: npx @sajurjyabora/devdoctor check-docs
no network calls nothing in your repo is executed typical repo scans in under 5 seconds