feat(skills): /site-create pipeline (phases 0-4 — phases 5-6 deferred)

This commit is contained in:
Parfii-bot 2026-04-21 21:08:14 +08:00
parent fd81aae515
commit 5d5362db3e
6 changed files with 594 additions and 0 deletions

131
skills/site-create/SKILL.md Normal file
View file

@ -0,0 +1,131 @@
---
name: site-create
description: End-to-end site pipeline — intake → design → sections → WYSIWYD mock-render loop → parallel audits → preview → deploy. Pure-click (≥8 AskUserQuestion blocks). The mock-render verify gate HARD-BLOCKS deploy of unlocked sections.
argument-hint: <optional one-line project intent>
---
# /site-create — 7-Phase Website Pipeline (index)
You convert a free-text product description into a deployed website through
seven strictly-ordered phases. Every decision is a click; only the intake
description (Phase 0) and per-section iteration edits (Phase 3) are typed.
This `SKILL.md` is the INDEX. Each phase lives in its own file and is
executed in order. Never skip a phase. Never re-order phases.
---
## Pipeline overview
| Phase | File | Purpose | AskUserQuestion |
|---|---|---|---|
| 0 | [phase-0-intake.md](phase-0-intake.md) | 7-question intake batch | 2× AskUserQuestion (4+3) |
| 1 | [phase-1-design.md](phase-1-design.md) | Invoke `/frontend-design`, emit `tokens.css` | 1× AskUserQuestion |
| 2 | [phase-2-sections.md](phase-2-sections.md) | Multi-select sections; variant per section | 2× AskUserQuestion |
| 3 | [phase-3-wysiwyd.md](phase-3-wysiwyd.md) | Per-section generate → mock-render → approve loop | N× (1 per section) |
| 4 | [phase-4-audit.md](phase-4-audit.md) | Parallel a11y / seo / responsive / perf | 1× (apply fixes?) |
| 5 | [phase-5-preview.md](phase-5-preview.md) | Preview deploy URL | 1× (proceed?) |
| 6 | [phase-6-deploy.md](phase-6-deploy.md) | Production deploy via `/web-deploy` | 1× (confirm) |
**Minimum AskUserQuestion count across a complete pipeline: 8+** — pure-click
contract. Only Phase 0 description and per-section iteration prompts are
free-text.
---
## WYSIWYD invariant (LOAD-BEARING)
> **Every section the user approved in the screenshot IS the file that gets
> deployed. Byte-for-byte. No "approximately like this".**
Enforced by the `mock-render` Rust primitive (`_primitives/_rust/mock-render/`):
- `mock-render lock` — freezes source SHA-256 after user-approved screenshot.
- `mock-render verify` — asserts source unchanged before any later write.
- `mock-render status` — lists sections, lock state, drift check.
**Hard block:** Phase 6 (deploy) refuses to run if any locked section shows
drift in `mock-render status`. The pipeline stops and loops the user back
to Phase 3 for that section.
The companion `hooks/site-wysiwyd-check.sh` (PostToolUse Edit|Write) gives a
stderr advisory whenever an edit touches a section file while a
`.keisei/dev-server.pid` exists — catches drift in the moment, not at
deploy time.
---
## Variables the pipeline produces
| Name | Set in | Meaning |
|---|---|---|
| `DESC` | Phase 0 | User's product/project intent (1-3 sentences) |
| `STACK` | Phase 0 | Astro 6 / Next 16 / SvelteKit / static |
| `STYLE` | Phase 0 | Premium / dark-tech / editorial / brutalist archetype |
| `MOTION` | Phase 0 | none / subtle / rich / experimental |
| `DEPLOY` | Phase 0 | Cloudflare Pages / Vercel / local |
| `TOKENS` | Phase 1 | CSS custom properties file written to `src/tokens.css` |
| `SECTIONS` | Phase 2 | Ordered list `[{name, variant}]` |
| `LOCKED` | Phase 3 | Set of sections that passed user approval |
| `AUDIT` | Phase 4 | `{a11y, seo, responsive, perf}` findings |
| `PREVIEW_URL` | Phase 5 | Short-lived preview URL |
| `PROD_URL` | Phase 6 | Final deploy URL |
---
## Final report (emit after Phase 6)
```
=== /SITE-CREATE REPORT ===
Intake: <first 80 chars of DESC>...
Stack: <STACK>
Style: <STYLE> / motion: <MOTION>
Sections: <N locked / M total>
- Nav locked sha256:6a48ca7...
- Hero locked sha256:b37e2d1...
- ...
WYSIWYD: <clean | drifted:X sections BLOCKED>
Audits: a11y=<pass/N-findings> seo=<..> resp=<..> perf=<LCP Xs>
Preview: <PREVIEW_URL>
Prod: <PROD_URL or "pending user confirm">
Next action: <verify on mobile / share URL / iterate section X>
```
---
## Rules (enforced at every phase)
- **Pure-click contract.** Only `DESC` (Phase 0) and per-section iteration
prompts (Phase 3) are typed. Every other decision is an `AskUserQuestion`.
Count them in the final report.
- **WYSIWYD hard block.** Phase 6 refuses to run if `mock-render status`
shows any drift. See Phase 3.5 for the invariant algorithm.
- **NO DOWNGRADE (RULE -1).** Any phase that fails returns 2-3 constructive
paths, never "can't be done".
- **NO HALLUCINATION (RULE 0.4).** Every section name / variant / hook
referenced must exist on disk or in the block recipe. Phase 3 verifies
before any lock.
- **Plan Mode First (RULE 0.5).** This skill IS the plan; each phase file
has its own verify-criterion. No Edit/Write to project source before the
corresponding phase's confirm click.
- **Constructor Pattern (RULE ZERO).** One file per section (Phase 3).
Generated `sections/*.astro` (or `.tsx`) never exceeds 200 LOC — split
into sub-sections on the fly.
- **Surgical Changes.** Never edit adjacent sections when iterating one.
Orphan imports in the edited section are cleaned; neighbours are not
touched.
---
## References
- [phase-0-intake.md](phase-0-intake.md) · [phase-1-design.md](phase-1-design.md) · [phase-2-sections.md](phase-2-sections.md) · [phase-3-wysiwyd.md](phase-3-wysiwyd.md) · [phase-4-audit.md](phase-4-audit.md) · [phase-5-preview.md](phase-5-preview.md) · [phase-6-deploy.md](phase-6-deploy.md)
- `skills/frontend-design/SKILL.md` — archetype philosophy (Phase 1)
- `skills/site-builder/SKILL.md` — hub-level WYSIWYD reference
- `skills/site-teardown/SKILL.md` — optional Phase 0 alt (clone a reference site)
- `skills/a11y-audit`, `skills/seo-audit`, `skills/responsive-audit`, `skills/perf-audit` — Phase 4 parallel fan-out
- `skills/web-deploy/SKILL.md` — Phase 6 deploy
- `_primitives/_rust/mock-render/` — WYSIWYD enforcer
- `_primitives/live-preview.sh` — dev-server lifecycle
- `_primitives/design-scrape.sh` — optional reference-site scrape (Phase 0 alt)
- `hooks/site-wysiwyd-check.sh` — PostToolUse drift advisory

View file

@ -0,0 +1,84 @@
# Phase 0 — Intake
> Goal: convert free-text product intent into 6 locked decisions that drive
> the rest of the pipeline. 2 AskUserQuestion calls (4 + 3 questions).
> **Verify criterion:** `DESC`, `STACK`, `STYLE`, `MOTION`, `DEPLOY`, `BRAND`,
> `FORM` all set.
---
## 0.a — Description (only free-text in the skill aside from Phase-3 iteration)
Prompt the user for ONE paragraph describing the product/project.
Capture 1-3 sentences into `DESC`. If the invocation already came with an
argument (`/site-create <text>`), skip this and use it.
---
## 0.b — First AskUserQuestion (4 questions)
Send exactly 4 questions in one `AskUserQuestion` call (the UI cap is 4):
1. **Site archetype?** (single-select, stored as `TYPE`)
- SaaS landing (one page)
- Multi-page marketing (/ + /about + /pricing + /contact + /blog)
- Portfolio / personal
- Docs site
2. **Framework?** (single-select, stored as `STACK`)
- Astro 6 (recommended for content/marketing)
- Next.js 16 (recommended for SaaS / app-like)
- SvelteKit (Runes, compiles small)
- Static HTML (single index.html)
3. **Visual archetype?** (single-select, stored as `STYLE`)
- Premium minimalist (Apple / Linear / Anthropic)
- Dark / moody tech (Vercel / Raycast)
- Editorial / long-form
- Brutalist / anti-design
4. **Motion tier?** (single-select, stored as `MOTION`)
- None (instant, print-like)
- Subtle (fade-up, stagger — 2026 conversion default)
- Rich (scroll-linked reveals, micro-interactions)
- Experimental (3D / shaders / pin-scrub; Awwwards-tier only)
---
## 0.c — Second AskUserQuestion (3 questions)
Send exactly 3 questions in a second `AskUserQuestion` call:
1. **Deploy target?** (stored as `DEPLOY`)
- Cloudflare Pages (recommended)
- Vercel (best Next integration)
- Local only (skip deploy for now)
2. **Brand assets?** (stored as `BRAND`)
- I'll provide (logo path + colors next)
- Generate with AI (skill will fan out to an external image generator)
- Minimal (text logo + neutral palette)
3. **Include a contact form?** (stored as `FORM`)
- Yes (wire via `/form-builder`)
- No
---
## 0.d — Branch: reference-site clone?
If `STYLE` needs guidance, offer an OPTIONAL detour (1 extra
AskUserQuestion, skip if the user answered "I know the style already"):
- Clone a reference — invoke `/site-teardown <url>` first, feed extracted
tokens into Phase 1.
- Start fresh — proceed directly to Phase 1.
---
## 0.e — Verify criterion
All of `DESC`, `TYPE`, `STACK`, `STYLE`, `MOTION`, `DEPLOY`, `BRAND`, `FORM`
must be populated. If any is missing, loop back to the relevant question.
Emit a single-line confirmation: `Intake locked: <TYPE> / <STACK> / <STYLE> / <MOTION> / deploy:<DEPLOY>`. Proceed to Phase 1.

View file

@ -0,0 +1,94 @@
# Phase 1 — Design (tokens + typography)
> Goal: produce `src/tokens.css` and a typography choice aligned with the
> Phase-0 `STYLE` archetype. 1 AskUserQuestion.
> **Verify criterion:** `src/tokens.css` written, passes `cssparser` (or a
> quick `curl`+ file inspection), fonts declared.
---
## 1.a — Invoke /frontend-design
Delegate to the `frontend-design` skill with the Phase-0 archetype:
```
/frontend-design archetype=<STYLE-derived> differentiator=<one-line from DESC>
```
Map `STYLE` → archetype:
| Phase-0 STYLE | frontend-design archetype |
|---|---|
| Premium minimalist | minimal |
| Dark / moody tech | retro-futuristic OR swiss (dark skin) |
| Editorial / long-form | editorial |
| Brutalist / anti-design | brutalist |
The sub-skill produces design tokens (color + type + spacing) in OKLCH form.
---
## 1.b — Brand asset wiring
Depending on `BRAND` from Phase 0:
- **I'll provide** — ask free-text once for the logo path + 2-3 hex colors.
Convert hex to OKLCH before writing into tokens.
- **Generate with AI** — fan out to an external image-gen service via
`keiagent`/`fal.ai` (skill-agnostic; the generator is not part of this
pipeline's required deps). Save to `public/brand/logo.svg` (or .png).
- **Minimal** — emit a text-only logo placeholder; no image asset.
---
## 1.c — Write `src/tokens.css`
Shape:
```css
:root {
/* Color (OKLCH — one --brand-hue controls the whole palette) */
--brand-hue: <from frontend-design>;
--color-bg: oklch(<L> <C> var(--brand-hue));
--color-fg: oklch(<L> <C> var(--brand-hue));
--color-accent: oklch(<L> <C> calc(var(--brand-hue) + 30));
--color-muted: oklch(<L> <C> var(--brand-hue));
--color-border: oklch(<L> <C> var(--brand-hue));
/* Type */
--font-display: "<display>", serif;
--font-body: "<body>", sans-serif;
/* Space + radius */
--space-section: clamp(4rem, 8vw, 8rem);
--radius-card: 0.75rem;
}
@media (prefers-color-scheme: dark) {
:root { /* dark-mode overrides */ }
}
```
If `STACK = Astro 6` or `Next.js 16`, also emit `src/styles/tokens.css` and
import it from the root layout.
---
## 1.d — One AskUserQuestion: confirm direction
Send a single `AskUserQuestion` with the rendered token preview
(swatch block + font-pair line) and 3 options:
- Looks good — proceed to Phase 2
- Adjust palette — loop back to 1.a with a "more muted" / "more saturated" hint
- Swap typography — loop back to 1.a with a "different fonts" hint
---
## 1.e — Checkpoint commit
```
checkpoint: phase-1 design tokens + typography
```
Proceed to Phase 2.

View file

@ -0,0 +1,68 @@
# Phase 2 — Section Selection
> Goal: user picks which sections the site contains, in what order, and which
> variant per section. 2 AskUserQuestion calls.
> **Verify criterion:** `SECTIONS = [{name, variant}, ...]` populated and
> non-empty.
---
## 2.a — Default section list per archetype
From Phase-0 `TYPE`:
| TYPE | Default sections (in order) |
|---|---|
| SaaS landing | Nav, Hero, LogoBar, Features, Testimonials, Pricing, FAQ, CTA, Footer |
| Multi-page marketing | Nav, Hero, Features, CTA, Footer + routes /about, /pricing, /contact |
| Portfolio | Nav, Hero, CaseGrid, About, Contact, Footer |
| Docs site | NavSidebar, Content, TOC, Footer-minimal |
---
## 2.b — First AskUserQuestion: pick sections (multi-select)
Send an `AskUserQuestion` with `multiSelect: true`. Pre-check the defaults
from 2.a; user can add or remove freely. The label for each option carries
a one-line description.
Include under "available" the full set from the block library (approx):
```
Nav, NavSidebar, Hero, Hero-split, Hero-centered, LogoBar, Features,
Features-bento, Features-alternating, Pricing, Pricing-simple, Pricing-tiered,
Testimonials, Testimonials-grid, Testimonials-carousel, CTA, CTA-split,
FAQ, FAQ-accordion, CaseGrid, Contact, Contact-form, Footer, Footer-minimal
```
Store the user's selection (ordered) as `SECTIONS` (names only for now).
---
## 2.c — Second AskUserQuestion: variant per section
For sections that have multiple variants (e.g. Hero-split vs Hero-centered),
send a SECOND `AskUserQuestion` with 3-5 questions (batched — UI max is 4;
use two calls if >4 sections have variants).
Each question: "Variant for <section>?" with A / B / C options. Default
pre-selected is usually the most conservative variant.
Store into `SECTIONS` as `[{name, variant}, ...]`.
---
## 2.d — Verify criterion
- `SECTIONS` is a non-empty ordered list
- Every `{name}` maps to a known block recipe (if a block library is
installed) OR is one of the default archetype sections
- Every variant is `A`, `B`, or `C`
If any section lacks a known recipe, fall back to a plain skeleton (tokens
only, no fancy variant).
Emit a confirmation line:
`Sections locked: N × {name/variant} — starting WYSIWYD loop`.
Proceed to Phase 3.

View file

@ -0,0 +1,133 @@
# Phase 3 — WYSIWYD Block-by-Block Build (CORE LOOP)
> Goal: for each section in `SECTIONS`, generate the source file, render a
> mock, get user approval, then **lock** via `mock-render` so the
> source-SHA is frozen.
>
> This phase enforces the LOAD-BEARING invariant: the screenshot the user
> approves IS the file that gets deployed. Byte-for-byte.
> **Verify criterion per section:** `site-state.json` has `locked: true` +
> matching `sha256` for that section.
---
## 3.0 — One-time setup (first section only)
Start the dev server via the `live-preview.sh` primitive:
```bash
$HOME/.claude/agents/_primitives/live-preview.sh start <project-root>
```
This writes `.keisei/dev-server.pid` — the WYSIWYD PostToolUse hook
(`hooks/site-wysiwyd-check.sh`) uses this file to decide whether to run
drift checks on subsequent Edit/Write operations.
Wait for the port to respond (max 30s poll). If it never comes up, fall
back to printing the dev-server log tail and ask the user whether to
abort or retry.
Create a helper preview route `<project-root>/src/pages/_block-preview.astro`
that takes `?block=<Name>` and renders only that section. This isolates
sections for per-section screenshots without bleed-through.
---
## 3.1 — For each section in SECTIONS: generate
Write `<project-root>/src/sections/<Name>.astro` (or `<Name>.tsx` for Next /
`<Name>.svelte` for SvelteKit):
- Props: none (sections are concrete, not generic)
- Tokens: only CSS custom properties from `src/tokens.css`
- No hardcoded hex / pixel / font values
- Copy: use Phase-0 `DESC`-derived placeholders; first section includes the
product name from `DESC`
- Motion: match `MOTION` tier from Phase 0 (none / subtle / rich / experimental)
- File stays < 200 LOC (Constructor Pattern) split into sub-components if
it grows
---
## 3.2 — Render mock
```bash
$HOME/.claude/agents/_primitives/_rust/target/release/mock-render screenshot \
"http://localhost:4321/_block-preview?block=<Name>" \
--out "<project-root>/mocks/<Name>.png" \
--viewport 1440x900
```
If Playwright is not installed, the primitive fails with a clear error —
prompt user to `npx playwright install chromium` and retry.
---
## 3.3 — Show + approve (1 AskUserQuestion per section)
Display `mocks/<Name>.png` inline. Ask:
- **Approve** — lock and move on
- **Iterate** — free-text what to change (single free-text moment inside
the skill, allowed per Phase-3 exception)
- **Switch variant** (A / B / C) — regenerate 3.1 with different variant
- **Swap block** — pick a different block for this slot, re-loop 3.1
---
## 3.4 — Act on approval
### Approve
```bash
$HOME/.claude/agents/_primitives/_rust/target/release/mock-render lock \
--project <project-root> \
--section src/sections/<Name>.astro \
--screenshot mocks/<Name>.png
```
This writes into `<project-root>/site-state.json`:
```json
{
"sections": {
"<Name>": { "path": "src/sections/<Name>.astro", "sha256": "...", "locked": true, "screenshot": "mocks/<Name>.png" }
}
}
```
Commit: `feat(site): lock <Name> section`. Move to next section in `SECTIONS`.
### Iterate / Switch variant / Swap block
Loop back to 3.1 (with the free-text change, the new variant, or the new
block). Do NOT touch any other section's file.
---
## 3.5 — WYSIWYD verify before any cross-section edit
If a later phase (e.g. audit) would edit a locked section, you MUST first:
```bash
$HOME/.claude/agents/_primitives/_rust/target/release/mock-render verify \
--project <project-root> \
--section src/sections/<Name>.astro
```
- Exit 0: unchanged since lock — proceed.
- Exit 2: **DRIFT** — stop. Re-render, re-approve via 3.3 loop, re-lock.
This is the hard block that guarantees Phase-6 deploy never ships a section
the user did not approve.
---
## 3.6 — Verify criterion (completion of Phase 3)
All `SECTIONS[i]` must have `locked: true` in `site-state.json`.
Run `mock-render status` and confirm 0 `DRIFT` rows. Emit:
`Phase 3 done: N sections locked, 0 drift. Proceeding to audits.`
Proceed to Phase 4.

View file

@ -0,0 +1,84 @@
# Phase 4 — Parallel Audit (a11y / seo / responsive / perf)
> Goal: run 4 audit skills in parallel against the locked site; collect
> findings grouped by severity; get user approval per fix.
> **Verify criterion:** all 4 audits ran; findings surfaced or confirmed
> zero; any applied fix passed `mock-render verify` first.
---
## 4.a — Fan-out parallel
Run the 4 audit skills concurrently (tool fan-out is allowed for audits —
they are read-only and independent):
```
/a11y-audit scan src/
/seo-audit <project-root>
/responsive-audit src/pages/index.astro
/perf-audit src/
```
Each returns a findings list with severity (`critical / important / nice`)
and, where possible, a file+line + suggested patch.
Merge the 4 result streams into a single aggregated list.
---
## 4.b — Group + present findings
Group findings by severity. For each, show:
- Severity (critical / important / nice)
- Category (a11y / seo / responsive / perf)
- File + line
- Description (1 sentence)
- Proposed fix (1 sentence)
- Affected section(s) (map file path → section name)
---
## 4.c — One AskUserQuestion: apply fixes?
Three options:
- **Apply all non-layout fixes automatically** — tweak meta tags, alt
attributes, `fetchpriority`, preload hints, other non-visual edits.
Per-fix algorithm in 4.d below.
- **Review each fix individually** — loop per finding, ask approve/skip.
- **Skip audit fixes** — proceed to Phase 5 with findings in the report.
---
## 4.d — Per-fix algorithm (applies to any chosen fix)
For EVERY fix the skill is about to write:
1. Determine the affected section file (if any).
2. Run `mock-render verify --section <file>` first.
- Exit 0 → proceed to step 3.
- Exit 2 → STOP. Report drift to user; loop back to Phase 3.3 for that
section (re-render, re-approve, re-lock) before attempting the fix.
3. If the fix is non-layout (meta tag, alt, preload, `loading="lazy"`,
`decoding="async"`, `aria-*`) → apply directly.
4. If the fix alters layout (CSS classes that move content, new DOM nodes,
removed sections) → do NOT apply silently. Flag it back to the user:
> "Fix #N changes layout. Re-approval via Phase 3.3 needed. Proceed?"
5. After EVERY applied fix, re-run `mock-render lock` on the affected
section so the frozen hash matches the new source.
6. Commit: `fix(site): <audit-category> — <short description>`.
---
## 4.e — Verify criterion
- All 4 audit skills completed.
- Findings list fully walked (either applied, individually approved/skipped,
or deferred per 4.c choice).
- `mock-render status` shows 0 drift rows.
Emit:
`Phase 4 done: <a11y-findings> a11y / <seo> seo / <resp> responsive / <perf> perf. Proceeding to preview.`
Proceed to Phase 5.