Why this exists#
Core principles#
These ten principles are the spine of the system; every section below is an elaboration of one of them.
- The starter is the canonical source of truth. When a rule or pattern changes, it changes in the starter first, then propagates to client repos.
- Client sites inherit the starter; proven improvements flow back. Client repos start from a clean baseline and don't each carry their own fixes — a fix proven on a build gets ported back here, then pulled forward (structure.git).
- Pages stay thin and compose sections. A
pages/*.astrofile reads like a table of contents: a<Layout>wrapping a short list of sections (components.composition). - Sections own page-specific content and layout. A
Section*component encapsulates one chunk of a page — its landmark, content, and markup — so the page file stays readable (components.composition). - Reusable UI lives in typed, open components. Primitives (
Button,Card,Field) are fully parameterized (typed props + slots), token-styled, and carry no page-specific content (components). - Semantic tokens only — never raw colors or one-off values. Components reference roles (
bg-intent,text-fg-muted), never hex or raw Tailwind neutrals (text-gray-700). Theme swaps "just work" through the cascade (tokens). - Accessibility, keyboard, focus, and reduced motion are authored from day one — never retrofitted. Native semantics first, ARIA only where native falls short (a11y).
- Content, SEO, schema, redirects, and site identity are centralized. One source of truth each —
site.ts,Seo.astro,lib/schema.ts,_redirects(seo). - Static output is the default; client JS is added only when it earns its cost. Astro ships zero JS by default; interactivity is progressively enhanced and degrades to working HTML when JS fails (components.scripting, perf).
- The production deploy is lean; the repo keeps the full toolbox, docs, and examples. Clients receive the full repo — every component, the showcase, and the docs — because their AI agent uses all of it to build pages. "Lean" applies to the production deploy, not the repo: demo/showcase routes are gated out of the live build, never stripped from the codebase (deploy.static).
One way to do a thing. Where two patterns exist, this doc picks one — consistency beats local cleverness. The runbook (runbook) and checklists (checklists) are derived views of these principles and the starter's actual state: when a principle or the starter changes, update checklists/runbook in the same change so they never drift.
How rules are labeled#
- Required — reviewers gate on it; a violation blocks a PR. A Required rule must be true of the starter, or it appears in conformance with a date.
- Default — the standard choice; deviate only with a stated reason.
- Allowed with reason — permitted when justified and scoped.
- Roadmap — decided but not yet implemented; tracked in roadmap. Never gated on.
Where rules live — no duplication#
A rule is stated once, in exactly one module under docs/rules/. Everything else points at it:
| File | Job |
|---|---|
docs/rules/*.md | the rules themselves — the only place a rule is stated |
docs/workflow.md | the router: task → which modules to read → which verification tier |
docs/checklists/*.md | what a reviewer gates on; cites rules, never restates them |
DESIGN.md | the client's brand decisions and constraints, with their reasoning — never values; those live in global.css (tokens.design-doc) |
AGENTS.md | the vendor-neutral agent contract and entry point; routes, states non-negotiables in one line each |
CLAUDE.md | a pointer to AGENTS.md, nothing more |
.claude/skills/* | executable procedures; state what to check and at what severity, never the rule itself (guardrails.skills) |
A rule written twice drifts twice. If you find yourself explaining a rule outside docs/rules/, link to it instead.