design-import
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseDesign Import
设计导入
Turn a Claude Design handoff bundle into scaffolded React components, with provenance and dedup against the existing codebase.
bash
/ork:design-import https://claude.ai/design/abc123 # From handoff URL
/ork:design-import /tmp/handoff-bundle.json # From local file将Claude Design交付包转换为已搭建的React组件,同时保留来源信息并与现有代码库进行去重。
bash
/ork:design-import https://claude.ai/design/abc123 # 从交付URL导入
/ork:design-import /tmp/handoff-bundle.json # 从本地文件导入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 instead.
/ork:design-ship在从claude.ai/design导出交付包后使用。该技能是入口点——它不会创建PR、运行测试或部署。如需端到端流程(导入→测试→PR),请改用。
/ork:design-shipPipeline
流程
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)交付包(URL或文件)
│
▼
┌──────────────────────────────┐
│ 1. 解析 + 验证 │ 通过claude-design-orchestrator agent完成
│ - 获取交付包 │ 架构验证
│ - 计算bundle_id(sha值) │ 显示偏差
└──────────┬───────────────────┘
│
▼
┌──────────────────────────────┐
│ 2. 协调令牌 │ 对比交付包令牌与项目令牌的差异
│ - 读取项目令牌 │ 冲突→询问用户问题
│ - 应用新增令牌 │ 新增→写入design-tokens.json
└──────────┬───────────────────┘
│
▼
┌──────────────────────────────┐
│ 3. 组件去重 │ 针对每个拟议组件:
│ 优先使用Storybook MCP │ • 完全匹配→复用(跳过)
│ 其次使用21st.dev │ • 相似匹配→适配
│ 最后使用文件系统grep │ • 无匹配→搭建
└──────────┬───────────────────┘
│
▼
┌──────────────────────────────┐
│ 4. 组件搭建 │ 按组件委托给design-to-code流程
│ (已跳过的组件仅记录日志, │ 使用交付包的tsx_scaffold作为种子
│ 不会修改文件) │ 应用项目令牌
└──────────┬───────────────────┘
│
▼
┌──────────────────────────────┐
│ 5. 写入来源信息 │ .claude/design-handoffs/<bundle_id>.json
│ 交付包→文件→(PR) │ PR字段为空,直到执行/ork:design-ship
└──────────┬───────────────────┘
│
▼
导入清单(标准输出)Argument resolution
参数解析
python
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
}])python
ARG = "$1" # 第一个位置参数
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": "无法将其解析为URL或文件。请说明这是什么?",
"header": "交付包来源",
"options": [
{"label": "粘贴交付URL", "description": "claude.ai/design URL"},
{"label": "粘贴文件路径", "description": "本地交付JSON文件"},
{"label": "取消", "description": "终止导入"}
],
"multiSelect": False
}])Phase 1 — Parse + validate
阶段1 — 解析 + 验证
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.
python
Agent(
subagent_type="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.
"""
)委托给编排agent。该agent负责获取、提取tar包、读取README+聊天记录、解析HTML原型,并生成标准化负载。请勿在此处重新实现解析逻辑——该agent负责(真实的、基于tar包的)架构。
python
Agent(
subagent_type="claude-design-orchestrator",
description="解析并标准化交付包",
prompt=f"""解析位于{bundle_input}的Claude Design交付包。
这是一个gzip压缩的tar包(不是JSON清单)。结构:
<project>/README.md ← 优先读取
<project>/chats/*.md ← 全部读取(承载关键信息)
<project>/project/*.html ← 原型(若未完成可能不存在)
任务:
1. 获取交付包(若为URL则用WebFetch→保存为.bin路径;若为本地文件则直接读取)
2. 提取:`tar -xzf <bin> -C /tmp/<scratch>/`
3. 先读取README.md,再读取所有chats/*.md(意图和说明在此)
4. 计算bundle_id = sha256(标准化交付包URL或绝对路径)
5. 若project/缺失→返回status="incomplete",并附带助手未解答的最后一个问题;请勿崩溃。告知用户“应采取的操作”。
6. 若project/存在→选择主HTML文件:
- 优先匹配URL中?open_file=查询参数对应的文件
- 否则选择按字母排序的第一个文件
7. 从主HTML文件中提取:
- 内联`:root { --... }` CSS自定义属性作为设计令牌
- 组件区块(通过class/id/data-screen-label命名)
- 资源引用(<link>, <img>)——保留为URL,不下载
- EDITMODE JSON块(设计时状态——仅作为注释捕获)
8. 生成标准化输出负载(参见agent规范)
9. 将来源信息写入.claude/design-handoffs/<bundle_id>.json:
- bundle_url, bundle_id, fetched_at, status, components: [], pr: null
10. 返回标准化负载为JSON格式
明确显示任何与预期tar包结构不符的偏差。
不要假设存在JSON `components[]`字段——这是旧的(错误的)结构。
"""
)Phase 2 — Reconcile tokens
阶段2 — 协调令牌
Read the normalized from the agent's payload.
token_diff| Diff field | Action |
|---|---|
| Append to project's design-tokens.json (or Tailwind config). No prompt — additions are safe. |
| Show diff. AskUserQuestion: keep project value, accept bundle value, or open editor. |
| Block scaffolding. AskUserQuestion to resolve before continuing. |
python
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
}])从agent的负载中读取标准化的。
token_diff| 差异字段 | 操作 |
|---|---|
| 追加到项目的design-tokens.json(或Tailwind配置)。无需提示——新增操作是安全的。 |
| 显示差异。询问用户问题:保留项目值、接受交付包值,或打开编辑器。 |
| 阻止组件搭建。询问用户问题,解决后再继续。 |
python
if token_diff["conflicts"]:
AskUserQuestion(questions=[{
"question": f"令牌冲突:{conflict.path}。项目值为{conflict.project},交付包值为{conflict.bundle}。如何解决?",
"header": "令牌冲突",
"options": [
{"label": "保留项目值", "description": "交付包适配项目"},
{"label": "接受交付包值", "description": "项目适配交付包(写入新令牌)"},
{"label": "两者并存——为交付包令牌添加命名空间", "description": f"添加为{conflict.path}.imported"}
],
"multiSelect": False
}])Phase 3 — Dedup components
阶段3 — 组件去重
The agent already ran component-search per component. Read decisions from the normalized payload:
| Behavior |
|---|---|
| Log "skipped (existing: <path>)" — do nothing on disk |
| Pipe through |
| Pipe through |
agent已针对每个组件运行component-search。从标准化负载中读取决策:
| 行为 |
|---|---|
| 记录“已跳过(已存在:<路径>)”——不修改磁盘文件 |
| 传入 |
| 传入 |
Phase 4 — Scaffold
阶段4 — 组件搭建
For each component with decision or , invoke design-to-code:
scaffoldadaptpython
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="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.
"""
)针对每个决策为或的组件,调用design-to-code:
scaffoldadaptpython
for component in payload["components"]:
if component["decision"] in ("scaffold", "adapt"):
# 组合调用,不要重新实现——design-to-code负责EXTRACT/MATCH/ADAPT/RENDER流程
Agent(
subagent_type="frontend-ui-developer",
description=f"从交付包搭建{component['name']}",
prompt=f"""使用design-to-code技能搭建该组件。
来源:交付包{payload['bundle_id']}
组件:{component['name']}
目标路径:{component['target_path']}
交付包搭建种子:
```tsx
{component['tsx_scaffold']}
```
已解析令牌:{component['tokens_resolved']}
决策:{component['decision']}
{f"适配来源:{component['existing_match']}" if component['decision'] == 'adapt' else ''}
写入组件,镜像现有项目文件结构,使用项目令牌。
"""
)Phase 5 — Provenance
阶段5 — 来源信息
Update the provenance file with the actual file paths written:
python
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)更新来源文件,写入实际已创建的文件路径:
python
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打印简洁的摘要(不要输出大量JSON):
已导入交付包 <bundle_id>
来源:<bundle_url>
来源信息:.claude/design-handoffs/<bundle_id>.json
组件:
✓ PricingCard 已搭建 src/components/pricing/PricingCard.tsx
↻ Button 已复用 已存在:src/components/ui/Button.tsx
⤳ Hero 已适配 适配自:src/components/Hero.tsx
令牌:
+ 3个新增(已添加到design-tokens.json)
~ 1个已修改(用户已接受交付包值)
✗ 0个未解决冲突
下一步:/ork:design-ship <bundle_id> # 创建PR
/ork:dogfood # 验证Hooks
钩子
- After completion, the hook auto-runs
post-design-import+/ork:dogfood(non-blocking, see hook for details)./ork:expect
- 完成后,钩子会自动运行
post-design-import+/ork:dogfood(非阻塞,详见钩子说明)。/ork:expect
Composition
组合技能
| Skill | Role |
|---|---|
| Owns the actual scaffold pipeline (EXTRACT/MATCH/ADAPT/RENDER). This skill delegates to it per component. |
| Used by the orchestrator agent for dedup |
| Used if bundle is missing |
| Token reconciliation reference |
| Provenance + prior-import detection |
| 技能 | 作用 |
|---|---|
| 负责实际的搭建流程(EXTRACT/MATCH/ADAPT/RENDER)。本技能按组件委托给它。 |
| 编排agent用于去重 |
| 若交付包缺少 |
| 令牌协调参考 |
| 来源信息 + 导入历史检测 |
NOT this skill's job
非本技能职责
| Concern | Owned by |
|---|---|
| Open PR | |
| Run tests | |
| Generate Storybook stories | |
| Re-prompt Claude Design | Not yet — no public API |
| 事项 | 负责技能 |
|---|---|
| 创建PR | |
| 运行测试 | |
| 生成Storybook故事 | |
| 重新请求Claude Design | 暂不支持——无公开API |
Limitations
局限性
- No public Claude Design API yet: bundles are one-shot exports. To iterate, re-export from claude.ai/design and re-import. (See Bet B for the future drift-sync workflow.)
- 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 are kept as-is. If you need them in-repo, run a separate sync step.
asset_urls
- 暂无公开Claude Design API:交付包是一次性导出。如需迭代,请从claude.ai/design重新导出并重新导入。(未来的差异同步工作流请参见Bet B。)
- 架构为临时版本:Claude Design尚未发布稳定的交付包架构。编排agent会适配偏差,但随着格式稳定可能需要更新。
- 资源URL仅引用,不下载:交付包中的保持原样。如需在仓库中存储,请运行单独的同步步骤。
asset_urls