Automated guardrails#
guardrails.gate, guardrails.docs-check and guardrails.skills ship today; guardrails.lint–guardrails.axe are Roadmap (roadmap). The aim: standards enforced by tooling and executable procedure, not memory.
Type & build gate (Required — shipped)#
npm run check = typecheck + guardrails.docs-check + production build (structure.gate). The minimum local gate before every PR. Still to do: wire it into CI.
Documentation integrity check (Required — shipped)#
npm run docs:check runs scripts/check-docs.mjs as part of the gate. It exists because the rulebook is split across modules and cited from checklists, skills and the agent contract — nothing else detects a citation going stale, and renumbering has silently broken references before.
It fails on:
- a
[rule.id]citation that resolves to no declared rule — including a typo inside a real namespace; - a duplicate rule id, a duplicate module id, an unknown tier, or a rulebook module missing its
docs-moduledeclaration; - any surviving
§Nsection reference — the banned syntax that ids replaced; - a relative
.mdlink that doesn't resolve on disk; - a stale rule-link block (a rule moved or a citation changed without
npm run docs:build); - a hex,
pxormsliteral inDESIGN.md— that file records decisions, and a value there is a second copy of something inglobal.css(tokens.design-doc).
Declarations and citations inside fenced code blocks are treated as examples and ignored. docs/learn/ is exempt: it is explicitly non-authoritative.
Every rule carries an id declared beside its heading:
### Client-side scripting
<!--rule: components.scripting | tier: required-->Cite one from anywhere in the repo as [components.scripting]. Tiers are required, default, reference and checklist. Ids survive moves and reordering, which section numbers did not.
Linting (Roadmap)#
eslint + eslint-plugin-astro + @typescript-eslint. Rules worth enforcing:
- ban raw hex/rgba and raw Tailwind neutral classes (
text-gray-*,bg-zinc-*) in components - flag bare global selectors in
is:globalblocks (require a[data-*]namespace) - ban inline
style=andon*=attributes - require
rel="noopener noreferrer"alongsidetarget="_blank"
Formatting (Roadmap)#
prettier + prettier-plugin-astro with a shared .prettierrc committed to the starter.
CI (Roadmap)#
One PR workflow: install → npm run check → eslint → (optional) Lighthouse CI on a preview build. Block merge on failure; assert the perf.budgets budgets so performance can't silently regress.
Accessibility automation (Roadmap)#
axe-core (via Playwright or @axe-core/cli) against key templates in CI, as a backstop to the manual checklist.a11y audit. Automated checks catch a minority of issues; they don't replace keyboard and screen-reader passes.
Agent skills & commands (Required — shipped)#
The repo ships executable forms of this document under .claude/. They are how a standard gets run rather than remembered, and they are part of the client deliverable (principles, principle 10).
| Path | Kind | What it does |
|---|---|---|
.claude/skills/launch/ | Skill | Pre-launch audit — the executable form of checklist.pre-launch. Takes a staging or production mode, then verifies site identity and canonicals, referenced assets, robots and sitemap, built HTML (not source), demo-route leakage, placeholder sweep, env keys and bindings, analytics/consent, legal pages, canvas gating, and a browser pass. Reports BLOCKER / SHOULD FIX / NEEDS HUMAN / NIT / CLEAN, then fixes only with permission and only from a fixed allowlist. |
Rules for authoring and maintaining them:
- The skill is derived from this document, never the reverse. When a rule here changes, update the matching step in the same change. A shipped audit that contradicts the standard is worse than no audit, because it launders a stale rule as a passing check.
- Cite rules by id, never by section number. guardrails.docs-check verifies every id a skill cites still exists, so a rule that moves can't leave a skill pointing at nothing.
- Skills state procedure and severity, not rules. A skill says what to check, in what order, at what severity; the rule itself lives here (principles, no duplication). A skill that restates a rule is a second copy that will drift.
- No client-specific stances in a starter-level skill. Radius, palette and type choices belong in the client's
DESIGN.md(tokens.per-client). A skill that hardcodes one project's stance silently breaks the next build. - No machine-specific absolute paths. A skill shipped in a client repo runs on someone else's machine.
- Never report an unrun check as passed — mark it
NEEDS HUMANwith how to verify. TheCLEANsection is not optional: a report listing only failures gives no coverage signal, and the reader can't distinguish a passed check from a skipped one. - Audit before fixing. Report first, fix only with permission, and keep the auto-fix allowlist narrow — never user-visible copy, legal text, brand artwork or redirect maps.
- Severity discipline.
BLOCKERmeans a visitor experiences something broken, or there is legal/brand exposure. If everything is a blocker, the label stops meaning anything.
Roadmap: an intake skill (runbook phases 1–2) and a standalone accessibility-audit skill (checklist.a11y) are the obvious next two.
Local development notes#
- Runtime-imported dependencies need pre-bundling. A dep imported at runtime inside a
<script>(animation libraries and their plugins, for example) can 504 inastro devon first use. Add it tooptimizeDeps.includein the Vite config. - Verify against a production build whenever dev and the host runtime differ. Routing, adapters and image services can behave differently in dev;
npm run build && npm run previewis the source of truth before you call something broken or fixed.