Impeccable extract 流程详解:从 AI Agent 技能文档看设计系统提取的六步方法论
本篇技术指南基于 Impeccable 技能(/impeccable 前端设计命令集)中的 Extract Flow 参考文档展开,完整解析"从目标代码区域识别可复用的组件、设计令牌与模式,并合并进设计系统"的六步流程:何时该停手询问用户、哪些重复模式值得提取(3+ 次使用门槛)、如何做提取规划与迁移,以及仓库中 DESIGN.md 与 cli/engine/design-system.mjs 如何把提取出的令牌变成可被自动检测器校验的"白名单"。读完你将掌握一套可复制的设计系统收敛(extract & consolidate)操作规范,并理解令牌命名的语义层级为何会直接影响后续的自动化审计。
extract 命令在 Impeccable 中的定位
Impeccable 是一个面向 AI 编码工具(Codex、Claude 等 harness)的前端设计技能包,通过 /impeccable <command> 形式暴露 23 个子命令。在 SKILL.md 的 Commands 表中,extract 被归入 Build 类别:
| 命令 | 分类 | 说明 | 参考文档 |
|---|---|---|---|
extract [target] |
Build | Pull reusable tokens and components into design system | reference/extract.md |
命令的元数据(argumentHint 为 [target])定义在 command-metadata.json 中,其描述明确了 extract 的适用场景:"Pull reusable patterns, components, and design tokens into the design system. Identifies repeated patterns and consolidates them. Use when you have drift across the codebase and want to bring things back to a consistent system." —— 即当代码库中出现了视觉漂移(drift)、同一个概念存在多套实现时,用 extract 把它们收回一致的系统里。
需要注意 extract 与相邻命令 document 的分工差异:document(reference/document.md)负责"从零扫描现有代码生成 DESIGN.md 文档",而 extract 负责"把散落的目标区域内可复用实现收敛为共享组件与令牌,并迁移既有调用点"。前者是记录系统,后者是建立系统。
Step 1:发现既有的设计系统(Discover the Design System)
流程的第一步是定位现有的设计系统、组件库或共享 UI 目录,并理解其结构:组件组织方式、命名约定、设计令牌结构、import/export 约定。原文强调理解"既有约定"优先于动手,因为后续所有命名都要对齐这些约定。
这里有一条关键的控制流(原文标注为 CRITICAL):
如果项目中不存在设计系统,先不要创建。 立即停止(STOP);如果运行时提供了结构化提问工具(如 Codex 的 user-input/question 工具)就使用它,否则直接在对话中提问,澄清你无法自行推断的信息。先弄清用户偏好的存放位置和结构,再开始提取。
这条规则的意义在于:设计系统的存放位置(根目录 DESIGN.md?docs/ 下?某个 ui/ 包?)是项目约定,Agent 不应擅自假设。仓库源码中也印证了这一点——cli/engine/design-system.mjs 中解析设计系统的查找顺序是:当前目录的 DESIGN.md(含大小写变体),再回退到 .agents/context/ 与 docs/ 两个候选目录(FALLBACK_DIRS 常量),并支持 .impeccable/design.json、DESIGN.json 等 sidecar 伴生文件。也就是说,"设计系统在哪"本身就是项目级状态,必须先行确认。
Step 2:识别可提取的模式(Identify Patterns)
在目标区域内寻找提取机会,原文给出六类机会清单:
- 重复组件(Repeated components):同一 UI 模式使用 3 次以上(按钮、卡片、输入框);
- 硬编码值(Hard-coded values):本应成为令牌的颜色、间距、排版、阴影;
- 不一致的变体(Inconsistent variations):同一概念的多种实现;
- 组合模式(Composition patterns):重复出现的布局或交互结构(表单行、工具栏分组、空状态);
- 字体样式(Type styles):重复出现的 font-size + weight + line-height 组合;
- 动画模式(Animation patterns):重复出现的 easing、duration 或 keyframe 组合。
价值判定标准同样明确写在文档中:只提取"同一意图下使用 3 次以上"的东西——过早的抽象比重复更糟(Premature abstraction is worse than duplication)。"同一意图"这个限定词很重要:两个长得相似但目的不同的按钮不应合并(这一点在文末 NEVER 清单中再次强调)。
从源码结构看,仓库自带的检测引擎实际上执行着"反向"的 3+ 判定:例如 tests/fixtures 下的 repeated-container-text.html、overused-font.html 等 fixture 正是为"重复出现的模式/字体"设计的测试场景,说明"重复计数 + 意图归并"是整个项目检测与提取共用的核心判据。
Step 3:制定提取计划(Plan Extraction)
动手前先产出一份系统性计划,覆盖五个维度:
- 要提取的组件:哪些 UI 元素会变成可复用组件?
- 要创建的令牌:哪些硬编码值会变成设计令牌?
- 要支持的变体:每个组件需要哪些变化?
- 命名约定:组件名、令牌名、prop 名如何与既有模式保持一致?
- 迁移路径:现有使用点如何重构为消费共享版本?
文档同时给出增量原则:"设计系统是增量生长的——提取现在明显可复用的东西,而不是所有'将来某天可能'可复用的东西。"
值得注意的是第 4 项"命名约定"并非空话,而是有下游约束的。DESIGN.md 的 frontmatter 是机读的令牌层,示例见 demos/landing-demo/DESIGN.md("Lumina" 演示项目):
colors:
cream: "#faf6ef"
ink: "#1f1a15"
accent: "#c8552b"
accent-deep: "#a8431f"
typography:
display:
fontFamily: "Fraunces, Georgia, serif"
fontSize: "clamp(3rem, 7vw, 5.5rem)"
fontWeight: 400
lineHeight: 1.05
letterSpacing: "-0.02em"
document.md 中的 frontmatter 规则要求颜色键使用描述性语义 slug(如 oxblood-deep、editorial-magenta),而不是 blue-800 这类裸值编号——这正是 extract 文档"tokens 应有语义含义"(primitive vs semantic 分层)在真实文件中的体现。仓库根目录的 DESIGN.md 则是同一结构的完整实例:品牌锚点色(kinpaku-gold、verdigris-patina)、表面色(lacquer-black 等)、中性阶梯(neutral-100…neutral-22)均带注释说明用途,且文件头声明了"frontmatter 是 portable export,CSS 文件才是 source of truth"的双向同步约定。
Step 4:提取并富化(Extract & Enrich)
构建改进后的、可复用的版本,原文对三类产物分别提出质量要求:
- 组件:清晰的 props API 与合理默认值;针对不同用例的恰当变体;内建可访问性(ARIA、键盘导航、焦点管理);配套文档与用法示例。
- 设计令牌:清晰命名(primitive 与 semantic 分层)、恰当的层级与组织、每个令牌的"何时使用"文档。
- 模式(Patterns):该模式何时使用、代码示例、变体与组合方式。
这里"富化"(Enrich)一词提示了 extract 与简单"剪切粘贴"的区别:提取出的共享版本应当比原有的散落实现更完善(默认值、a11y、文档),否则迁移只会把缺陷也集中化了。
Step 5:迁移(Migrate)
替换既有使用点,四个动作缺一不可:
- 找出所有实例:搜索被提取模式的既有实现;
- 系统性替换:逐一更新为消费共享版本;
- 充分测试:确保视觉与功能等价(parity);
- 删除死代码:移除旧实现,避免双份真相。
"视觉与功能等价"是这一步的验收标准。可以推断,这与 Impeccable 全局"有界验证"(bounded passes)的验证哲学一致——SKILL.md 要求构建完成后以批量方式做有上限的验证轮次,而不是无休止的自我 QA。
Step 6:文档化(Document)
最后更新设计系统文档本身:
- 将新组件加入组件库;
- 记录令牌的用法与取值;
- 补充示例与使用指南;
- 更新 Storybook 或组件目录。
文档化不是可选尾巴:在本仓库的证据链中,DESIGN.md 的 frontmatter 才是被自动检测消费的机器可读层(详见下节),跳过文档化等于让提取成果对后续所有 Agent 会话和检测器不可见。
红线清单:NEVER 条款
原文以 7 条 NEVER 收尾,是对前六步的负向约束:
- 不要提取一次性、场景绑定的实现而不做泛化;
- 不要创建泛化到毫无用处的组件;
- 不要在不考虑既有设计系统约定的情况下提取;
- 不要跳过 TypeScript 类型或 prop 文档;
- 不要为每个值都建令牌(令牌必须有语义含义);
- 不要提取意图不同的东西(两个相似但目的不同的按钮应各自独立)。
这 7 条与 Step 2 的"3+ 次同一意图"门槛、Step 4 的语义令牌分层共同构成 extract 的决策边界:宁可保留重复,不可制造错误的抽象。
源码印证:令牌如何被下游检测器消费
extract 的产出并非止步于代码整洁,而是接入了仓库的自动化检测闭环。cli/engine/design-system.mjs 展示了这一闭环的实现:
- 解析层:
loadDesignSystemForCwd()读取DESIGN.md的 YAML frontmatter(内置了一个支持引号、转义与注释的parseYamlSubset解析器),并合并 sidecar(DESIGN.json/.impeccable/design.json)中的colorMeta、roundedMeta、shadows等扩展字段,归一化为normalizeDesignSystem()输出的白名单结构:allowedFonts、allowedColorKeys、allowedRadii、allowedFontSizes、allowedShadowColors。 - 判定层:
isAllowedFont()、isAllowedColorRaw()、isAllowedRadiusRaw()、fontSizeStepStatus()逐一校验源码中的字面量是否在白名单内。颜色比较允许每通道 ±6 的容差(COLOR_CHANNEL_TOLERANCE = 6),阴影色则额外要求 alpha 容差 0.02(SHADOW_ALPHA_TOLERANCE),因为"同一黑色在不同 alpha 下是不同令牌"——这正是 extract 文档"令牌要有语义层级"在数值层面的体现。 - 发现层:越界的字体字面量会被
makeDesignFinding('design-system-font', ...)生成带ignoreValue的发现项(finding),例如 "Frauncesis not declared in DESIGN.md typography"。 - 作用域控制:
findDesignRoot()从扫描目标自身位置向上查找设计系统根,处理 monorepo workspace glob、嵌套package.json与独立.git边界,避免"用项目 A 的 DESIGN.md 去判项目 B"的跨项目污染。
这条链路的含义是:extract 步骤中"哪些值该成为令牌、令牌怎么命名"直接决定了后续 detect 检测器的判定基准——语义命名、层级清晰的令牌让白名单准确;而"为每个值建令牌"的泛滥做法会制造大量误报。文档中 Step 4 的令牌分层要求由此获得了工程上的必要性证明。
一个工程细节:文档的模板化分发
仓库中同时存在两份 extract 文档:安装版 .agents/skills/impeccable/reference/extract.md 与源模板版 skill/reference/extract.md。两者仅一行差异——源模板中 Step 1 的 CRITICAL 条款写作 {{ask_instruction}} 占位符,安装到具体项目时被解析为宿主工具特定的提问指令(Codex 版本展开为"use Codex's structured user-input/question tool when available; if unavailable, ask directly in chat")。这说明 Impeccable 的分发管线(见 scripts/lib/transformers)会按目标 harness 适配同一份流程文档,而"发现设计系统前先询问用户"这一控制流是所有平台变体共享的不变量。
小结:可复用的六步检查表
- 找到(或确认不存在)设计系统;不存在时停手询问,不擅自创建。
- 按六类机会清单扫描目标区域,用"3+ 次同一意图"过滤。
- 产出五维计划:组件、令牌、变体、命名、迁移路径。
- 构建富化版本:props API、语义令牌、内建 a11y、文档。
- 系统性替换全部使用点,验证 parity,删除旧实现。
- 更新设计系统文档与组件目录,让成果进入可被工具和 Agent 消费的状态。
配套红线:不泛化一次性实现、不造过度泛化的组件、不违背既有命名约定、不跳过类型与文档、不为无语义的值建令牌、不合并意图不同的相似组件。在 Impeccable 的完整工作流里,extract 的输出物 DESIGN.md 既是给人看的文档,也是 cli/engine/design-system.mjs 一类检测引擎的判定基准——设计系统的"提取"因此不只是重构,而是把视觉一致性固化为可持续校验的契约。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0622
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00