name: design-import license: MIT compatibility: "Claude Code 2.1.183+. Requires: claude-design-orchestrator agent. Optional: stitch, 21st-dev-magic, storybook-mcp MCP servers (used transitively via design-to-code)." description: "Imports a Claude Design (claude.ai/design) handoff bundle and scaffolds the proposed components into the project. Accepts a bundle URL or local file, parses and validates the schema, deduplicates components against the existing codebase via component-search, then pipes the survivors through the design-to-code pipeline. Writes provenance metadata so future imports can detect drift between design versions. Use after exporting a handoff bundle from claude.ai/design — this is the entry point that turns a design into code." argument-hint: "<handoff-url | path-to-bundle.json>" tags: [claude-design, handoff, design-import, design-to-code, bundle, scaffold, frontend] context: fork version: 1.0.0 author: OrchestKit user-invocable: true complexity: medium persuasion-type: collaborative effort: high model: sonnet agent: claude-design-orchestrator allowed-tools:
- Read
- Write
- Edit
- Glob
- Grep
- Bash
- WebFetch
- AskUserQuestion
- Agent
- TaskCreate
- TaskUpdate
- TaskList skills:
- design-to-code
- component-search
- design-context-extract
- design-system-tokens
- remember
- memory
metadata:
category: workflow-automation
mcp-server: stitch, 21st-dev-magic, storybook-mcp
triggers:
keywords: ["import claude design", "design handoff", "handoff bundle", "claude.ai/design", "design-import"]
examples:
- "import this Claude Design handoff: https://claude.ai/design/abc123"
- "scaffold the components from this bundle"
- "design-import /tmp/handoff.json" anti-triggers: [export, brainstorm, extract design tokens] paths:
- "src/components/**/*.{tsx,css}"
- ".claude/design-handoffs/**"
- "**/design-tokens"
Design Import
Turn a Claude Design handoff bundle into scaffolded React components, with provenance and dedup against the existing codebase.
/ork:design-import https://claude.ai/design/abc123 # From handoff URL
/ork:design-import /tmp/handoff-bundle.json # From local file
When to use
After exporting a handoff bundle from claude.ai/design. This skill is the entry point — it does NOT open a PR, run tests, or deploy. For the end-to-end flow (import → tests → PR), use /ork:design-ship instead.
Pipeline
Handoff bundle (URL or file)
│
▼
┌──────────────────────────────┐
│ 1. PARSE + VALIDATE │ via claude-design-orchestrator agent
│ - Fetch bundle │ Schema validation
│ - Compute bundle_id (sha) │ Surface deviations
└──────────┬───────────────────┘
│
▼
┌──────────────────────────────┐
│ 2. RECONCILE TOKENS │ Diff bundle tokens vs project tokens
│ - Read project tokens │ Conflicts → AskUserQuestion
│ - Apply additions │ Additions → write to design-tokens.json
└──────────┬───────────────────┘
│
▼
┌──────────────────────────────┐
│ 3. DEDUP COMPONENTS │ For each proposed component:
│ Storybook MCP first │ • exact match → reuse (skip)
│ 21st.dev next │ • similar match → adapt
│ Filesystem grep last │ • no match → scaffold
└──────────┬───────────────────┘
│
▼
┌──────────────────────────────┐
│ 4. SCAFFOLD │ Delegate to design-to-code per component
│ (skipped components │ Use bundle's tsx_scaffold as seed
│ logged but not touched) │ Apply project tokens
└──────────┬───────────────────┘
│
▼
┌──────────────────────────────┐
│ 5. WRITE PROVENANCE │ .claude/design-handoffs/<bundle_id>.json
│ Bundle → files → (PR) │ PR field empty until /ork:design-ship
└──────────┬───────────────────┘
│
▼
Import manifest (stdout)
Argument resolution
ARG = "$1" # First positional argument
if ARG.startswith("http://") or ARG.startswith("https://"):
bundle_source = "url"
bundle_input = ARG
elif Path(ARG).exists():
bundle_source = "file"
bundle_input = ARG
else:
AskUserQuestion(questions=[{
"question": "I couldn't resolve that as a URL or file. What is it?",
"header": "Bundle source",
"options": [
{"label": "Paste handoff URL", "description": "claude.ai/design URL"},
{"label": "Paste file path", "description": "Local handoff JSON"},
{"label": "Cancel", "description": "Abort import"}
],
"multiSelect": False
}])
Phase 1 — Parse + validate
Delegate to the orchestrator agent. The agent fetches, extracts the tarball, reads the README + chats, parses the HTML prototypes, and produces a normalized payload. Do NOT reimplement parsing here — the agent owns the (real, tarball-based) schema.
Agent(
subagent_type="ork:claude-design-orchestrator",
description="Parse and normalize handoff bundle",
prompt=f"""Parse the Claude Design handoff bundle at {bundle_input}.
This is a gzipped tarball (NOT a JSON manifest). Layout:
<project>/README.md ← read first
<project>/chats/*.md ← read all (load-bearing)
<project>/project/*.html ← prototypes (may be absent if incomplete)
Tasks:
1. Fetch the bundle (WebFetch if URL → saved .bin path; Read if local file)
2. Extract: `tar -xzf <bin> -C /tmp/<scratch>/`
3. Read README.md, then every chats/*.md (intent + clarifications live here)
4. Compute bundle_id = sha256(canonical bundle URL or absolute path)
5. If project/ is MISSING → return status="incomplete" with the assistant's
last unanswered question; do NOT crash. Surface "what user should do".
6. If project/ exists → pick primary HTML:
- Prefer the file matching the URL's ?open_file= query param
- Else first alphabetical
7. From the primary HTML, extract:
- Inline `:root { --... }` CSS custom properties as design tokens
- Component sections (named via class/id/data-screen-label)
- Asset references (<link>, <img>) — keep as URLs, do not download
- EDITMODE JSON block (design-time state — capture as ANNOTATION only)
8. Produce normalized output payload (see agent spec)
9. Write provenance to .claude/design-handoffs/<bundle_id>.json:
- bundle_url, bundle_id, fetched_at, status, components: [], pr: null
10. Return the normalized payload as JSON
Surface any deviations from the expected tarball layout explicitly.
Never expect a JSON `components[]` field — that was the old (wrong) shape.
"""
)
Phase 2 — Reconcile tokens
Read the normalized token_diff from the agent's payload.
| Diff field | Action |
|---|---|
added |
Append to project's design-tokens.json (or Tailwind config). No prompt — additions are safe. |
modified |
Show diff. AskUserQuestion: keep project value, accept bundle value, or open editor. |
conflicts |
Block scaffolding. AskUserQuestion to resolve before continuing. |
if token_diff["conflicts"]:
AskUserQuestion(questions=[{
"question": f"Token conflict on {conflict.path}. Project says {conflict.project}, bundle says {conflict.bundle}. Resolve?",
"header": "Token conflict",
"options": [
{"label": "Keep project value", "description": "Bundle adapts to project"},
{"label": "Accept bundle value", "description": "Project adapts to bundle (writes new token)"},
{"label": "Both — namespace bundle's", "description": f"Add as {conflict.path}.imported"}
],
"multiSelect": False
}])
Phase 3 — Dedup components
The agent already ran component-search per component. Read decisions from the normalized payload:
decision |
Behavior |
|---|---|
reuse |
Log "skipped (existing: |
adapt |
Pipe through ork:design-to-code with --adapt-from <existing-path> context |
scaffold |
Pipe through ork:design-to-code with the bundle's tsx_scaffold as seed |
Phase 4 — Scaffold
For each component with decision scaffold or adapt, invoke design-to-code:
for component in payload["components"]:
if component["decision"] in ("scaffold", "adapt"):
# Compose, don't reimplement — design-to-code owns the EXTRACT/MATCH/ADAPT/RENDER pipeline
Agent(
subagent_type="ork:frontend-ui-developer",
description=f"Scaffold {component['name']} from bundle",
prompt=f"""Use the design-to-code skill to scaffold this component.
Source: handoff bundle {payload['bundle_id']}
Component: {component['name']}
Target path: {component['target_path']}
Bundle scaffold seed:
```tsx
{component['tsx_scaffold']}
```
Resolved tokens: {component['tokens_resolved']}
Decision: {component['decision']}
{f"Adapt from: {component['existing_match']}" if component['decision'] == 'adapt' else ''}
Write the component, mirror existing project file structure, use project tokens.
"""
)
Phase 5 — Provenance
Update the provenance file with the actual file paths written:
provenance = Read(payload["provenance_path"])
provenance["components"] = [
{"name": c["name"], "decision": c["decision"], "path": c["target_path"]}
for c in payload["components"]
]
provenance["imported_at"] = now()
Write(payload["provenance_path"], provenance)
Output — import manifest
Print a concise summary (not a wall of JSON):
Imported bundle <bundle_id>
Source: <bundle_url>
Provenance: .claude/design-handoffs/<bundle_id>.json
Components:
✓ PricingCard scaffold src/components/pricing/PricingCard.tsx
↻ Button reuse existing: src/components/ui/Button.tsx
⤳ Hero adapt adapted from: src/components/Hero.tsx
Tokens:
+ 3 new (added to design-tokens.json)
~ 1 modified (user accepted bundle value)
✗ 0 conflicts unresolved
Next: /ork:design-ship <bundle_id> # to open PR
/ork:dogfood # to verify
Hooks
- After completion, the
post-design-importhook auto-runs/ork:dogfood+/ork:expect(non-blocking, see hook for details).
Composition
| Skill | Role |
|---|---|
design-to-code |
Owns the actual scaffold pipeline (EXTRACT/MATCH/ADAPT/RENDER). This skill delegates to it per component. |
component-search |
Used by the orchestrator agent for dedup |
design-context-extract |
Used if bundle is missing design_tokens block |
design-system-tokens |
Token reconciliation reference |
remember / memory |
Provenance + prior-import detection |
NOT this skill's job
| Concern | Owned by |
|---|---|
| Open PR | /ork:design-ship |
| Run tests | post-design-import hook → /ork:dogfood, /ork:expect |
| Generate Storybook stories | /ork:cover (called by /ork:design-ship) |
| Re-prompt Claude Design | Not yet — no public API |
Limitations
- No public Claude Design API yet: bundles are one-shot exports. To iterate, re-export from claude.ai/design and re-import. The reverse-path (drift detection + refinement prompt) is tracked in M124 — Claude Design Drift Sync (Bet B): #1391, #1393, #1394, #1395, #1397.
- Schema is provisional: Claude Design has not published a stable bundle schema. The orchestrator agent adapts to deviations but may need updates as the format stabilizes.
- Asset URLs are referenced, not downloaded: bundle
asset_urlsare kept as-is. If you need them in-repo, run a separate sync step.