| name | reframe-site-loop |
| description | Use when the user asks for multiple pages, a full site, a sitemap, a group like "home + pricing + about + 404", or resumes a partial site (baton on disk). Not for single-scene work. Runs a one-page-per-turn baton pattern via `.reframe/next-prompt.md` + `.reframe/SITE.md`, freezes brand on turn 1, and wires cross-page nav with real slugs. |
| allowed-tools | ["mcp__reframe__*","Read","Write","Edit"] |
| bus-context-types | ["site-intent"] |
| bus-result-kinds | ["design-result"] |
| bus-streaming | true |
reframe-site-loop
You are a site architect running a baton. N pages generated in one turn never look like N pages generated by the same designer in a week of iteration — context erodes, consistency drifts, nav wiring breaks. The baton pattern forces one page per turn. Each turn has one working page + frozen site context (brand, nav, SITE.md). Between turns the user can inspect, say "redo the hero on pricing", change direction, walk away and resume tomorrow.
The engine is deterministic; the designer is not. The baton is how you make multi-page generation deterministic at the site level — same SITE.md + same turn-by-turn execution = same site.
Sensitive surfaces
Where sites split apart across pages:
- Brand drift — page 1 extracted Stripe, page 3 "remixed" and lost 2 OpenType features. Brand must freeze on turn 1.
- Nav drift — page 1's nav has "Features / Pricing / Docs", page 4's has "Product / Plans / Documentation". Nav must carry verbatim from SITE.md.
- Spacing / type scale drift — hero h1 is 64px on home, 56px on pricing with same hierarchy level. DESIGN SYSTEM must be frozen.
- Slug-to-sessionId drift — baton lists
pricing but the in-memory session is pricing-v2 from a regeneration. metadata.json must be the bridge.
- Hidden incompleteness — user says "finalize" on turn 5, but one page's nav still points to
#. Finalize pass must verify every <a href> resolves to an existing scene slug.
- Multi-page attempts in one turn — a user pushing "just generate all 4" destroys quality. Hold the line: one page per turn, even if user insists.
Smell table — site regressions
| Smell | Why it breaks | Detection | Fix |
|---|
| Different nav items across pages | Not a single site anymore | Diff nav text across all compiled scenes | Regenerate outliers with SITE.md's canonical nav |
Brand brandFidelity drops between pages | Brand not truly frozen | Compare brandFidelity per scene | Re-read DESIGN.md on affected page, re-compile |
<a href="#"> in any nav | Dead link | Grep href="#" in all compiled scenes | Re-compile with real slugs, update SITE.md mapping |
| H1 font-size varies across pages at same hierarchy | Type scale wasn't frozen | Compare h1 fontSize per scene | Freeze via defineTokens once, apply across scenes |
| Two pages claim to be "home" | Slug collision | Check SITE.md + metadata.json for dup slugs | Rename one, update all references |
Baton says status: complete but scenes missing | SITE.md out of sync with disk | Cross-check SITE.md table vs .reframe/scenes/*.scene.json | Re-scan scenes, update SITE.md |
| Colors drift ("stripe purple" on home → "indigo" on pricing) | Tokens not applied on later pages | brandFidelity delta + token audit | autoBindTokens across affected pages |
| Designer replied with 2 pages in one turn | Turn discipline broken | Turn output has 2+ scene IDs | Reject — re-run the first page only; discard second |
Canonical flows
The loop has exactly three states. The baton's status field names which:
First turn — site doesn't exist yet
- Parse the user's ask into a sitemap (list of pages by slug + purpose)
- Load brand context if named (hand to
reframe-brand, then return)
- Write
.reframe/SITE.md — master plan: sitemap, brand slug, tone, frozen DESIGN SYSTEM block, done/pending table
- Write
.reframe/next-prompt.md — first page's brief (run through reframe-enhance first if raw)
- Hand to
reframe-design to actually generate the first page
- After generation — update metadata.json + SITE.md (done), write next page's brief to baton
Mid-turn — baton has a pending page
- Read
.reframe/next-prompt.md → get current page slug + brief
- Read
.reframe/SITE.md → get frozen brand + DESIGN SYSTEM + already-generated pages
- Run
reframe-enhance to verify brief is structured (or re-structure it)
- Hand to
reframe-design with brief + brand context + cross-nav (slugs of done pages)
- After compile — update metadata.json (slug → sessionId), mark page done in SITE.md
- Write next page's brief to baton, OR set
status: complete if last page
Final turn — baton says complete
- Read every scene's nav; verify every
href resolves to an existing slug
- Run
reframe_export format=site to produce the single-file site bundle
- Optional: run
reframe-critic per page to catch cross-page drift
- Summarize: pages built, brand used, export path, any outstanding warnings
Orchestration modes
The baton is mode-agnostic. Pick once per site:
- Manual — user reviews between pages, types "next" to advance
- Agent-chain — Claude Code auto-advances until
status: complete
- CI — GitHub Action reads baton, calls
claude -p, commits, loops
If user hasn't said, ask once: "build all pages now, or one-at-a-time with review?"
Anti-patterns
- Generating multiple pages in one turn. Quality degrades; nav wires break. Absolute rule: one page per turn.
- Regenerating done pages inside the loop. If user says "tweak the hero on home" mid-loop, that's a single-scene edit (
reframe-design), not a loop re-entry.
- Nav with
# placeholders. The reframe_export format=site step depends on real slugs. # kills navigation.
- Forgetting the baton update. Every turn ends with the baton advanced (or
status: complete). A turn that doesn't write the baton is a turn lost.
- Letting brand drift. If brand changes mid-loop, STOP, don't auto-apply — ask user to confirm (usually they want to finish the current brand first).
- Writing raw user intent to next-prompt.md. Baton always carries structured briefs. Run
reframe-enhance first.
Tools to reach for
Write .reframe/SITE.md / .reframe/next-prompt.md / .reframe/metadata.json — the baton files
Read same three on every turn — source of truth lives on disk
reframe_design action=extract brand=<slug> — turn-1 brand freeze
reframe_compile — per-page generation (usually via reframe-design skill)
reframe_edit — surgical nav wiring / token re-application
reframe_inspect — per-page audit + brandFidelity
reframe_export format=site — finalize step
Baton file shapes (minimum viable)
.reframe/SITE.md
# <Site name>
Brand: <slug>
Tone: <one line>
Mode: <manual | agent-chain | ci>
## Design System (frozen turn 1)
<tokens inline: colors, type scale, spacing, radius, shadow>
## Sitemap
| Slug | Purpose | Status | Session |
|---|---|---|---|
| home | brand intro | done | s1 |
| pricing | 3 tiers + enterprise link | pending | - |
| about | company story | pending | - |
| 404 | lost page | pending | - |
## Nav (canonical — all pages must render this verbatim)
- Home → /
- Pricing → /pricing
- About → /about
.reframe/next-prompt.md
slug: pricing
status: pending
## brief
<structured brief from reframe-enhance — DESIGN SYSTEM + AUDIENCE + PAGE STRUCTURE + MUST-HAVES + NICE-TO-HAVES>
.reframe/metadata.json
{
"home": "s1",
"pricing": "s2",
"about": "s3"
}
Gotchas
- Resumability is the point — if anything kills the session (crash, timeout, walk-away), the baton on disk carries the state forward. Don't hold loop state in memory only.
- SITE.md is truth;
metadata.json is cache. On conflict, trust SITE.md and rebuild the cache from scene list.
reframe_export format=site requires every nav href to resolve — run the pre-export nav check before calling it.
- One brand per site. Don't mid-loop swap Stripe → Linear; start a new site.
When NOT to use this skill
- Single-scene work →
reframe-design
- Variants of ONE scene (density × radius × brand grid) →
reframe_edit op=vary inside reframe-design
- User wants to preview / export a site that already exists (no generation) →
reframe_export format=site directly
- User wants to test the Platform UI →
designer-qa
Growing the smell table
When a multi-page generation produces a cross-page regression a future session would repeat:
- Name the drift ("nav labels varied", "spacing scale collapsed", "brand purple → indigo")
- Detection (diff across pages / per-scene metric)
- Fix (which turn to re-run / which op to apply)
- Add the row
Each smell = a site that holds together next time.