Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
5470ecd
docs(renderers): design for pluggable multi-framework renderers
May 28, 2026
3c6d02d
docs(renderers): add bite-sized implementation plan
May 28, 2026
66816c6
feat(renderers): add renderer manifest JSON schema
May 28, 2026
6f62069
feat(renderers): add renderer-registry list command
May 28, 2026
67441d9
feat(renderers): add renderer-registry resolve command
May 28, 2026
5bb6254
feat(renderers): add renderer-registry detect with priority precedence
May 28, 2026
4519a23
feat(renderers): add validate-renderer (schema + cross-reference checks)
May 28, 2026
b7d6160
refactor(renderers): extract renderer-lib, guard trailing flags, stab…
May 28, 2026
a286cf0
feat(renderers): author nextjs/vite/sveltekit/expo manifests
May 28, 2026
50aa7b4
ci(renderers): wire validate-renderer into verify-all
May 28, 2026
a4582f6
refactor(intake): detect framework via renderer-registry, not hardcod…
May 28, 2026
5695aca
feat(build-spec): add renderer field, deprecate framework.type
May 28, 2026
6085286
refactor(pipeline): dispatch Phase-4 converter via renderer manifest
May 28, 2026
11654c9
refactor(orchestration): exclude phases via manifest.phases.exclude
May 28, 2026
7346767
refactor(tokens): derive token config target from renderer manifest
May 28, 2026
51f67d2
refactor(tdd): select test runner/library from manifest.test
May 28, 2026
577bef7
refactor(pipeline): phase 4.5 skip note reads renderer not outputTarget
May 28, 2026
3bb4e2a
feat(templates): add astro starter (react islands + tailwind + contai…
May 28, 2026
a419577
feat(agents): add astro-converter (hybrid .astro + react islands)
May 28, 2026
ec85dcf
feat(renderers): author astro manifest
May 28, 2026
4c48ae2
test(renderers): add astro hybrid build-spec fixture
May 28, 2026
9e2b5a6
fix(templates,renderers): add user-event dep to astro, document fixtu…
May 28, 2026
bdc590f
feat(setup): add --renderer flag backed by the registry
May 28, 2026
a658878
docs(renderers): document the renderer model and how to add one
May 28, 2026
c05eb49
docs: sync architecture footer for renderer system
May 28, 2026
8e2ace9
docs(renderers): backfill astro into intake/readme/tdd examples
May 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude/AGENT-NAMING-GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

## Naming Convention

All 53 agents use unique, hyphenated names (e.g., `frontend-developer`, `figma-react-converter`). There are no naming conflicts in the current agent set.
All 54 agents use unique, hyphenated names (e.g., `frontend-developer`, `figma-react-converter`). There are no naming conflicts in the current agent set.

Agent files live in `.claude/agents/` as `<agent-name>.md`.

Expand Down
3 changes: 2 additions & 1 deletion .claude/CUSTOM-AGENTS-GUIDE.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Custom Agents Guide

**Last Updated:** 2026-03-25
**Total Agents:** 53
**Total Agents:** 54
**Location:** `.claude/agents/`

Agents are auto-selected by Claude Code based on task context, or you can request one explicitly.
Expand Down Expand Up @@ -41,6 +41,7 @@ Agents are auto-selected by Claude Code based on task context, or you can reques
|-------|---------|-------------|
| figma-react-converter | Figma-to-React conversion pipeline orchestration | Converting Figma designs into React components with Tailwind CSS |
| canva-react-converter | Canva-to-React conversion from screenshots | Converting Canva designs into React components with Tailwind CSS |
| astro-converter | Design-to-Astro hybrid conversion (zero-JS .astro statics + React islands) | Building Astro apps where most components are static and a few are interactive React islands |
| asset-cataloger | Image/asset semantic mapping and validation | Mapping hash-named exports to meaningful names, validating asset usage |

## Testing & QA
Expand Down
178 changes: 178 additions & 0 deletions .claude/agents/astro-converter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
---
name: astro-converter
description: Specialized agent for autonomous design-to-Astro conversion using a hybrid model. Emits zero-JS static .astro components for presentational UI and React islands (.tsx) for interactive components, composed under file-based src/pages/*.astro routes. Pairs with outputTarget "react".
tools: Write, Read, MultiEdit, Bash, Grep, Glob, AskUserQuestion, TaskOutput, Edits, KillShell, Skill, Task, TodoWrite, WebFetch, WebSearch, mcp__figma-desktop__get_design_context, mcp__figma-desktop__get_variable_defs, mcp__figma-desktop__get_screenshot, mcp__figma-desktop__get_metadata, mcp__figma__get_design_context, mcp__figma__get_variable_defs, mcp__figma__get_screenshot, mcp__figma__get_metadata
model: opus
permissionMode: bypassPermissions
---

You are an elite design-to-Astro conversion specialist. You turn a locked design
(Figma, Canva, or screenshot/URL) into a production-ready Astro app using Astro's
**hybrid islands architecture**: presentational components ship as zero-JS
`.astro` files, and only genuinely interactive components become hydrated React
islands (`.tsx`) with the appropriate `client:*` directive.

You are the only net-new converter in the renderer system. You are resolved via
the renderer registry when `build-spec.json` carries `renderer: "astro"`
(`outputTarget: "react"`).

## When to Use

- The build-spec's `renderer` field is `"astro"` (Phase 4 dispatch resolves the
converter from the renderer manifest: `node scripts/renderer-registry.js
resolve astro --json` → `converter: "astro-converter"`).
- A content-heavy, mostly-static site where shipping minimal JavaScript matters
(marketing pages, docs, blogs, landing pages) but a handful of components are
interactive.

## Inputs

1. **`build-spec.json`** — the machine-readable build plan. You read:
- `renderer` (must be `"astro"`) and `outputTarget` (`"react"`).
- `components[]` — each entry's `category`, `props`, `variants`, and the
interactivity signals below.
- `pages[]` — page name, `route`, and the `sections` it composes.
- `businessLogic` — forms, API calls, auth, state management. Any component
touched by business logic is interactive.
2. **Locked design tokens** — `design-tokens.lock.json` (single source of truth).
Translate to `tailwind.config.mjs` `theme.extend.*` exactly as the React
converter does. Zero hardcoded values.
3. **Screenshots** — visual reference for pixel-accurate layout and the
`get_screenshot` fallback when `get_design_context` fails.

## The Island / Static Decision (core rule)

For **each** component in `build-spec.json.components`, classify it:

**Emit a React island (`.tsx`) when ANY of these is true:**
- The component has an `action` field that implies behavior (anything other than
a pure render — e.g. submit, search, toggle, navigate-with-state).
- Its `category` is interactive (e.g. `forms`, controls, menus, modals, tabs,
accordions, carousels, search boxes, anything with local UI state).
- It is referenced by `build-spec.json.businessLogic` (a form field, an API
call trigger, an auth control, or a piece of `stateManagement`).

Islands reuse the **existing React converter patterns** verbatim: TypeScript
functional components, exported props `interface`, `useState`/`useReducer` for
local state, Tailwind utility classes, semantic HTML, accessibility
attributes, zero hardcoded values. The `.tsx` lives under `src/components/`.

**Otherwise emit a static `.astro` component (zero JS):**
- Props typed via the frontmatter `interface Props` (`const { ... } =
Astro.props;`).
- No client-side JavaScript whatsoever — no event handlers, no hooks.
- Tailwind classes in the markup. Slots (`<slot />`) for composition.

When in doubt, prefer static: a component is only an island if it must run in
the browser. Presentational cards, heroes, navs (without interactive menus),
footers, sections, and feature lists are static `.astro`.

## Hydration Directives (`client:*`)

Reference each island from the page with the cheapest correct directive:

| Directive | Use when |
|-----------|----------|
| `client:load` | Above-the-fold interactivity needed immediately (primary CTA, header search). |
| `client:visible` | Below-the-fold islands — hydrate when scrolled into view (default for most islands). |
| `client:idle` | Non-urgent interactivity that can wait for the main thread to be idle. |
| `client:media` | Interactivity only relevant at certain breakpoints (e.g. a mobile-only menu). |

Default to `client:visible`; use `client:load` only for above-the-fold islands.
Never hydrate a static `.astro` component (it has no client directive).

## Pages

- Pages are **file-based** routes: `src/pages/*.astro` (index → `/`, `about` →
`/about`, matching each `build-spec.pages[].route`).
- A page imports both static `.astro` components and React islands and composes
them. Static components render inline; islands carry a `client:*` directive.
- Shared chrome (head, html/body, global layout) lives in a layout component the
pages import.

## Tests (read from `manifest.test`: `runner: vitest`, `containerApi: true`)

Generate a colocated test for every component you emit:

- **React islands (`.tsx`)** → Vitest + `@testing-library/react` (`render`,
`screen`, `userEvent`), exactly like the Vite/Next React path. Assert
rendering, interaction, and accessibility.
- **Static `.astro` components** → Vitest + the **Astro Container API**. Render
with `experimental_AstroContainer` and assert against the returned HTML
string:
```ts
import { experimental_AstroContainer as AstroContainer } from "astro/container";
import { expect, test } from "vitest";
import Hero from "./Hero.astro";

test("renders the title", async () => {
const container = await AstroContainer.create();
const html = await container.renderToString(Hero, {
props: { title: "Welcome" },
});
expect(html).toContain("Welcome");
});
```
- **Page-level interactivity** (multi-step flows that cross component
boundaries) → Playwright E2E in Phase 6 (`e2e-test-generator`), not unit tests.

## Autonomous Workflow

**Phase 1: Discovery (interactive)**
1. Confirm `renderer: "astro"` in the build-spec; resolve the manifest.
2. Extract / load design tokens and write `tailwind.config.mjs`.
3. Classify every component as island vs. static (the rule above). Produce a
table: component → kind (`.astro` | `.tsx`) → `client:*` (islands only).
4. Survey pages and their sections with screenshots.
5. Present the classification + page plan to the user: "Proceed?"

**Phase 2: Execution (autonomous)**
1. Write `tailwind.config.mjs` from locked tokens.
2. Build static `.astro` components (presentational) with `interface Props`.
3. Build React islands (`.tsx`) reusing React converter component/prop patterns.
4. Build the layout component and compose `src/pages/*.astro`, wiring each
island's `client:*` directive (`client:load` above the fold, `client:visible`
below).
5. Generate tests: RTL for islands, Container API for `.astro`.
6. Work through all components without "should I continue?" prompts; log errors
and continue.

**Phase 3: Completion**
1. Summarize: components created (split by island/static), tokens mapped, pages
composed, and any issues.
2. Recommend hydration tuning (e.g. promoting a `client:load` to `client:visible`
if it is below the fold) and follow-up E2E flows.

## Quality Standards

- **Static-first.** Ship zero JS unless interactivity is required. The whole
point of Astro is minimizing client JavaScript.
- **Correct hydration.** Every island has exactly one `client:*` directive;
no static component has one.
- **Zero hardcoded values.** Colors, spacing, typography, radii, shadows all map
to Tailwind tokens from the lockfile.
- **TypeScript native.** Island props via exported `interface`; static props via
frontmatter `interface Props`. No `any`.
- **Accessible & responsive.** WCAG 2.1 AA, semantic HTML, mobile-first Tailwind
breakpoints, keyboard navigation, focus-visible styles.
- **Tested.** Every component has a colocated test (RTL or Container API).

## Key Principles

1. **Hybrid by default** — static `.astro` for presentation, React islands for
interaction.
2. **Signals drive the split** — `action` / interactive `category` /
`businessLogic` → island; otherwise static.
3. **Cheapest correct hydration** — prefer `client:visible`; `client:load` only
above the fold.
4. **Reuse React patterns for islands** — islands are ordinary React converter
output.
5. **Fully autonomous** — work through all components after Phase 1 approval.
6. **Production ready** — accessible, responsive, token-driven, tested.

---

**Agent Version:** 1.0.0
**Created:** 2026-05-28
**Model:** Opus (for hybrid island/static interpretation)
**Execution Mode:** Autonomous with Phase 1 classification review
43 changes: 32 additions & 11 deletions .claude/commands/build-from-canva.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ Use `TodoWrite` to create a master checklist. Update each item as phases complet
[ ] Phase 1: Intake — canva-intake skill → build-spec.json
[ ] Phase 2: Token Inference — canva-token-inference skill → lockfile + tailwind config (requires user confirmation)
[ ] Phase 3: TDD Scaffold — tdd-from-figma skill → failing tests (RED)
[ ] Phase 4: Component Build — canva-react-converter agent → tests pass (GREEN)
[ ] Phase 4: Component Build — converter agent (per resolved renderer manifest) → tests pass (GREEN)
[ ] Phase 4.5: Storybook — generate-stories.sh → auto-generated stories
[ ] Phase 5: Visual Verification — pixel-diff loop (max N iterations, against Canva screenshots)
[ ] Phase 5.5: Dark Mode — check-dark-mode.sh → dark mode visual verification
Expand Down Expand Up @@ -104,18 +104,28 @@ Identical to `/build-from-figma` Phase 3.

After Phase 3 completes (TDD scaffold with failing tests confirmed), hand off remaining phases to the parallel orchestration skill.

**Read `renderer` from `build-spec.json` and resolve its manifest before dispatching:**

```bash
node scripts/renderer-registry.js resolve <renderer> --json
```

The manifest drives both converter dispatch (`manifest.converter`) and phase exclusion (`manifest.phases.exclude`).

**Invoke the `parallel-orchestration` skill with:**
- Phases to run: `["component-build", "storybook", "visual-diff", "dark-mode", "e2e-tests", "cross-browser", "quality-gate", "responsive", "report"]`
- Drop any phase listed in `manifest.phases.exclude`
- Context:
- Build spec: `.claude/plans/build-spec.json`
- Lockfile: `src/styles/design-tokens.lock.json`
- Test files: `src/components/**/*.test.tsx`
- Pipeline source: `"canva"`
- Renderer manifest: from `renderer-registry.js resolve <renderer> --json`
- Reference screenshots: `.claude/visual-qa/screenshots/canva/`
- Config: `.claude/pipeline.config.json` → `orchestration` section

The parallel orchestration skill will:
1. Start `component-build` first (dispatches `canva-react-converter` agent)
1. Start `component-build` first (dispatches the converter named in the resolved manifest, see Phase 4)
2. After build completes, fan out independent phases in parallel (max 3 concurrent)
3. Run `e2e-tests` after `visual-diff` completes
4. Run `report` after both `quality-gate` and `e2e-tests` complete
Expand All @@ -126,19 +136,30 @@ The parallel orchestration skill will:

The individual phase descriptions below serve as reference for what each phase does. The parallel orchestration skill dispatches the same agents, skills, and scripts — it only changes the execution order.

## Phase 4: Component Build
## Phase 4: Component Build (Renderer-Driven)

Read `renderer` from `build-spec.json`, resolve its manifest, and dispatch the converter it names:

```bash
node scripts/renderer-registry.js resolve <renderer> --json
```

**Converter selection:**
- If `manifest.language === "react"`, prefer the source-appropriate React converter. For the Canva pipeline that is `canva-react-converter` (it builds React components from Canva screenshots). The shipped React manifests (nextjs, vite) set `converter` to the generic `figma-react-converter`; for the Canva source, use `canva-react-converter` instead.
- Otherwise dispatch `manifest.converter` directly (e.g. `react-native-converter` for expo, and the future `vue-converter` / `svelte-converter`).

Dispatch the `canva-react-converter` agent.
The component extension, directory, page-routing convention, and test command come from `manifest.component` and `manifest.commands.test`.

**Input:** build-spec.json, lockfile, existing test files, Canva screenshots
**Output:** `src/components/**/*.tsx`, page files
**Input:** build-spec.json, resolved renderer manifest, lockfile, existing test files, Canva screenshots
**Output:** Component and page files for the renderer's framework (React: `src/components/**/*.tsx`)

This phase:
1. Reads build-spec.json — verifies `source` is `"canva"`
2. References lockfile for all token values (no approximating)
3. Uses Canva screenshots for layout/structure decisions
4. Generates components that satisfy the test files from Phase 3
5. Runs `pnpm vitest run` after each component batch to confirm GREEN
1. Reads build-spec.json — verifies `source` is `"canva"` and reads `renderer`
2. Resolves the manifest and dispatches the converter (see selection rule above)
3. References lockfile for all token values (no approximating)
4. Uses Canva screenshots for layout/structure decisions
5. Generates components (at `manifest.component.dir` with `manifest.component.ext`) that satisfy the test files from Phase 3
6. Runs `manifest.commands.test` after each component batch to confirm GREEN

**Critical rule:** If tests fail, fix the component — never modify the test files.

Expand Down
36 changes: 28 additions & 8 deletions .claude/commands/build-from-figma.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,18 +115,28 @@ Process components in dependency order: UI primitives → Layout → Sections

After Phase 3 completes (TDD scaffold with failing tests confirmed), hand off remaining phases to the parallel orchestration skill.

**Read `renderer` from `build-spec.json` and resolve its manifest before dispatching:**

```bash
node scripts/renderer-registry.js resolve <renderer> --json
```

The manifest drives both converter dispatch (`manifest.converter`) and phase exclusion (`manifest.phases.exclude`).

**Invoke the `parallel-orchestration` skill with:**
- Phases to run: `["component-build", "storybook", "visual-diff", "dark-mode", "e2e-tests", "cross-browser", "quality-gate", "responsive", "report"]`
- Drop any phase listed in `manifest.phases.exclude`
- Context:
- Build spec: `.claude/plans/build-spec.json`
- Lockfile: `src/styles/design-tokens.lock.json`
- Test files: `src/components/**/*.test.tsx`
- Pipeline source: `"figma"`
- Renderer manifest: from `renderer-registry.js resolve <renderer> --json`
- Figma screenshots: `.claude/visual-qa/screenshots/figma/`
- Config: `.claude/pipeline.config.json` → `orchestration` section

The parallel orchestration skill will:
1. Start `component-build` first (all other phases depend on it)
1. Start `component-build` first (dispatches the converter named in the resolved manifest, see Phase 4 — all other phases depend on it)
2. After build completes, fan out independent phases in parallel (max 3 concurrent)
3. Run `e2e-tests` after `visual-diff` completes
4. Run `report` after both `quality-gate` and `e2e-tests` complete
Expand All @@ -137,18 +147,28 @@ The parallel orchestration skill will:

The individual phase descriptions below serve as reference for what each phase does. The parallel orchestration skill dispatches the same agents, skills, and scripts — it only changes the execution order.

## Phase 4: Component Build
## Phase 4: Component Build (Renderer-Driven)

Read `renderer` from `build-spec.json`, resolve its manifest, and dispatch the converter it names:

```bash
node scripts/renderer-registry.js resolve <renderer> --json
```

**Converter selection:**
- If `manifest.language === "react"`, prefer the source-appropriate React builder. For the Figma pipeline that is `figma-react-converter`, driven by the `figma-to-react-workflow` skill (which detects build-spec.json and lockfile automatically). The shipped React manifests (nextjs, vite) already name `figma-react-converter` as their `converter`.
- Otherwise dispatch `manifest.converter` directly (e.g. `react-native-converter` for expo, and the future `vue-converter` / `svelte-converter`).

Invoke the `figma-to-react-workflow` skill (which detects build-spec.json and lockfile automatically).
The component extension, directory, page-routing convention, and test command come from `manifest.component` and `manifest.commands.test`.

**Input:** build-spec.json, lockfile, existing test files
**Output:** `src/components/**/*.tsx`, page files
**Input:** build-spec.json, resolved renderer manifest, lockfile, existing test files
**Output:** Component and page files for the renderer's framework (React: `src/components/**/*.tsx`)

This phase:
1. Skips discovery (build-spec.json exists)
1. Skips discovery (build-spec.json exists); reads `renderer` and resolves its manifest
2. References lockfile for all token values (no approximating)
3. Generates components that satisfy the test files from Phase 3
4. Runs `pnpm vitest run` after each component batch to confirm GREEN
3. Generates components (at `manifest.component.dir` with `manifest.component.ext`) that satisfy the test files from Phase 3
4. Runs `manifest.commands.test` after each component batch to confirm GREEN

**Critical rule:** If tests fail, fix the component — never modify the test files.

Expand Down
Loading
Loading