This documentation is also published as Markdown for efficient machine reading: the whole site is indexed at /llms.txt, and every page has a clean Markdown copy under /_llms/. These are generated from the same source and cost far fewer tokens to read than this rendered HTML.

Skip to main content

May 1, 2026

Catch broken links before your readers do

By Phil Scott

A broken link works in every check you run while writing, then fails for a reader weeks later. Pennington already caught broken links at build time; now it catches them continuously and shows you where.

One audit pipeline, two surfaces

The new piece is a build auditor. An auditor is a check that runs against your content: a broken-link verifier, a content-overlap detector, a translation completeness pass. Pennington runs them through one AuditRunner that primes a cache at startup and re-runs on every file change.

The findings go two places from that single source:

  • The build report — every finding collected, with a non-zero exit code if anything is an error. This is the CI gate.
  • The dev overlay — the same finding, attached to the page that contains it, live in the browser as you write.

So a broken link doesn't wait for a build. Introduce one, save, and the overlay on that page points it out. The diagnostic code behind the overlay is in the request-scoped diagnostics reference.

Two kinds of check

Auditors come in two kinds. Structural auditors — content overlap, translation coverage, unresolved cross-references — work from the content model. Rendered auditors need the finished HTML: broken-link verification has to follow links against real routes, so it runs after the pipeline and dispatches each route through the live renderer.

That split keeps the system open. A new check is a new auditor, and it picks up both surfaces — the report and the overlay — without extra wiring. Broken links and content overlap are the first two; an accessibility pass is a likely next one.