← All articles

Open-sourcing build-websites-tools: the build-time gates behind every Site Clinic site

John Liddy ·

Developer reviewing build pipeline output on a laptop screen
Pexels / Pixabay · Pexels License

Last Saturday a site we own had two production deploys fail in a row with the same message: gate-ada: command not found. The Vercel dashboard kept serving the last good build. To anyone visiting the domain, everything looked fine. Internally, two days of changes were stranded.

The root cause was a vendoring mistake. The gates that enforce WCAG 2.1 AA, Google indexing rules, and a few AI-discoverability invariants on every Site Clinic-built site were being consumed from a sibling-path dependency that worked locally and silently failed in CI. We had documented the footgun. We had not built the system that prevents the footgun from recurring.

This week we did. The system that came out of it is now public.

What we open-sourced

build-websites-tools is a small npm package that ships four build-time enforcement gates. Each one runs at prebuild. A failing gate fails the build. A failing build does not deploy.

  1. gate-ada: WCAG 2.1 AA via axe-core. Every route in gate.config.json is loaded in a real browser (or jsdom on cloud hosts without Chromium) and any critical, serious, or moderate violation fails the build.
  2. gate-seo: Google indexing rules at build time. HTTP 200 on every route, no <meta robots noindex>, no X-Robots-Tag: noindex, canonical matches request path, sitemap and routes are consistent, valid robots.txt, structural meta in range (title 10 to 70 chars, description 50 to 160 chars), single h1, heading hierarchy, image alt text, JSON-LD presence, internal-link canonicality. It blocks the exact failure modes Search Console flags as "Excluded by noindex," "Page with redirect," and "Discovered, currently not indexed."
  3. gate-ai-instrumentation: runtime check that the AI Instrumentation Contract surfaces are live. Per-bot robots.txt rules, llms.txt served with a Markdown heading, AI ingestion endpoint reachable, homepage JSON-LD baseline (Organization or WebSite).
  4. gate-ai-instrumentation-source: static check for the same AI Instrumentation Contract, no running server needed. Catches refactors that silently drop a surface before they ever launch a dev server. This is the gate that would have prevented the contamination case where a route handler is rewritten and quietly loses its AI policy block.

The four compose. The source gate catches contract drift at commit time. The runtime gate validates the live build. The SEO gate catches Google-visible regressions. The accessibility gate catches accessibility regressions. The fix path for any failure is the same: read the named violation, fix the source, commit. There is no bypass flag. The hostile path is "do not ship a site that violates the standard," not "tell us about it after."

What changed when we shipped it

Every Site Clinic-built site now consumes the package directly from GitHub. One line in package.json:

```bash npm install --save-dev "github:drjliddy-max/build-websites-tools#v0.3.1" ```

That replaces the vendored copy each consuming site used to carry. Vendoring was the source of the drift class: one site had a missing test file, another had a stale regex that false-failed on route-handler robots, a third was missing an enforcement we added six weeks ago. The same fix had to be copied into each repo by hand. We did not copy carefully enough.

Pin-by-tag closes that class. npm outdated tells us when a new tag exists. Re-vendor passes disappear from the operator runbook. The 2-deploy failure on baby-web that opened this post was the first thing the fix closed.

The vendored pattern was always a workaround. The real fix is the dependency model the rest of the JavaScript ecosystem already uses. We were carrying our QA layer the long way around for what turned out to be a non-reason.

What is free, what is paid

The gates are free. Always. MIT-licensed, no signup, no API key. Anyone running a Next.js or JavaScript site at prebuild can drop them in and get the same enforcement we use on every site we ship.

What Site Clinic adds on top is the ongoing surface. Build-time enforcement runs once per deploy and exits. It does not watch the site after launch. It does not tell you when Search Console flags a new exclusion three weeks from now. It does not aggregate accessibility, SEO, and AI-citation data across multiple sites you own. It does not alert you when a runtime regression slips past the gates that were green at build time.

That is the Site Clinic subscription. Runtime monitoring. AI-citation tracking. Audit reports. Alerts when production drifts from what the gates verified. Pre-wired site builds where the gates, monitoring, and the brand layer are wired in for you. The gates demonstrate the methodology; the subscription closes the loop.

How to use it today

Two files. That is the whole consumption surface.

In your package.json:

```json { "devDependencies": { "build-websites-tools": "github:drjliddy-max/build-websites-tools#v0.3.1" }, "scripts": { "gate:ada": "gate-ada", "gate:seo": "gate-seo", "gate:ai-instrumentation": "gate-ai-instrumentation", "gate:ai-instrumentation-source": "gate-ai-instrumentation-source", "gate:all": "npm run gate:ada && npm run gate:seo && npm run gate:ai-instrumentation-source && npm run gate:ai-instrumentation", "prebuild": "npm run gate:all" } } ```

And a gate.config.json at the repo root listing your routes and base URL. The repository ships three templates you can copy and adjust: marketing site, marketing plus blog, marketing plus authenticated app. Each template already lists the five doctrine-required pages (/, /privacy, /terms, /accessibility, /contact). The gate enforces those five with no opt-out flag. The check exists because a portfolio site previously shipped without /privacy, /terms, or /accessibility and the gate is the prevention.

If you are working through an AI coding agent, the repo ships an AGENTS.md with a standardized onboarding playbook so Claude Code, Codex, Cursor, or any agent can wire the gates into a new or existing site without human handholding. The llms.txt at the repo root gives LLMs a clean ingestion summary.

Where this goes

The gates will keep growing. The next surfaces under consideration: structured-data validity (Google Rich Results Test parity at build time), Core Web Vitals budgets, sitemap freshness checks, and a per-site vendor-drift gate that detects when shared tooling has moved forward and the consumer has not. Each addition has to clear the same bar: a real production regression class that affected multiple owned sites, deterministic enough to enforce with a rule, and worth failing a build over.

If you ship websites at all, give it a look. The repo lives at github.com/drjliddy-max/build-websites-tools. If the four gates close a failure mode you have been losing time to, we did the work right.