---
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

1. Parse the user's ask into a sitemap (list of pages by slug + purpose)
2. Load brand context if named (hand to `reframe-brand`, then return)
3. Write `.reframe/SITE.md` — master plan: sitemap, brand slug, tone, frozen DESIGN SYSTEM block, done/pending table
4. Write `.reframe/next-prompt.md` — first page's brief (run through `reframe-enhance` first if raw)
5. Hand to `reframe-design` to actually generate the first page
6. After generation — update metadata.json + SITE.md (done), write next page's brief to baton

### Mid-turn — baton has a pending page

1. Read `.reframe/next-prompt.md` → get current page slug + brief
2. Read `.reframe/SITE.md` → get frozen brand + DESIGN SYSTEM + already-generated pages
3. Run `reframe-enhance` to verify brief is structured (or re-structure it)
4. Hand to `reframe-design` with brief + brand context + cross-nav (slugs of done pages)
5. After compile — update metadata.json (slug → sessionId), mark page done in SITE.md
6. Write next page's brief to baton, OR set `status: complete` if last page

### Final turn — baton says complete

1. Read every scene's nav; verify every `href` resolves to an existing slug
2. Run `reframe_export format=site` to produce the single-file site bundle
3. Optional: run `reframe-critic` per page to catch cross-page drift
4. 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`
```markdown
# <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`
```markdown
slug: pricing
status: pending

## brief
<structured brief from reframe-enhance — DESIGN SYSTEM + AUDIENCE + PAGE STRUCTURE + MUST-HAVES + NICE-TO-HAVES>
```

### `.reframe/metadata.json`
```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:

1. Name the drift ("nav labels varied", "spacing scale collapsed", "brand purple → indigo")
2. Detection (diff across pages / per-scene metric)
3. Fix (which turn to re-run / which op to apply)
4. Add the row

Each smell = a site that holds together next time.
