The Problem
Agency RealityAgencies rebuild the same marketing pattern for clients, then get pulled back for copy tweaks, FAQ answers, and page reorders. A CMS adds login theater and layout drift. Handing clients the full React theme invites breakage.
The Split
Three Layers| Layer | Owner | What lives there |
|---|---|---|
| Theme | Agency | React layout, sections, CSS, defineSection |
| Content | Site owner | Name, nav, page copy, section props (TOON/JSON) |
| Agent surface | Generated | AGENTS.md, schemas, Cursor skills |
The theme is locked after handoff. Content is the only mutable surface for maintenance.
Contracts
Source of TruthEvery section is a contract — one definition drives validation, render, and agent docs:
defineSection({
type: "hero",
description: "…",
props: z.object({…}),
component: Hero,
example: { type: "hero", … },
guidance?: "…",
})
- Validates content against the Zod schema
- Renders the matching React component at build time
- Syncs agent docs so an LLM knows allowed types and props
You do not maintain a separate CMS schema or a hand-written agent guide.
Plain static HTML. No runtime CMS. Host the folder anywhere.
Commands
Sync · Doctor · Build| Command | Role |
|---|---|
| sync | Regenerate agent files from theme contracts |
| validate / doctor | Check content, routes, images, contracts |
| build | Sync → doctor → static HTML |
| watch | On change: sync, validate, rebuild |
Builds refuse to publish when doctor reports errors — broken props, duplicate routes, missing local images, and similar.
TOON
Prefer DenseContent may be TOON (preferred) or JSON. TOON is denser — fewer tokens for LLM edits — while remaining human-readable. Validation does not care which format you use.