首页
/ 用构建产物反写设计系统:Impeccable Documenter 的逆向设计文档化实践与内联降级模式

用构建产物反写设计系统:Impeccable Documenter 的逆向设计文档化实践与内联降级模式

2026-09-07 12:23:00作者:咎岭娴Homer

在 Impeccable 的技能体系中,设计系统文档不是"写出来"的,而是从已经交付的代码里反读出来的。impeccable-documenter(文档记录员)是承担这一职责的角色:一次构建结束后,它扫描成品中的样式表与 token,将"代码实际如何被设计"记录成机器可读的 DESIGN.md.impeccable/design.json 侧车文件,供后续 AI 生成新界面时保持同品牌、同规则。本文以其降级变体 degraded/documenter.md 为线索,讲清该角色在 Impeccable 全流程中的位置、输入输出契约、五步工作流,以及"在无子代理能力的运行时内联执行"时如何自洽地完成同一份工作。读完你将掌握:如何从一份成品前端推导出规范化设计系统、哪些记录会被判定为"污染系统"而必须丢弃,以及降级模式与完整 subagent 模式之间的执行差异。

一个把"事后记录"当作原则的角色

Impeccable 把前端设计工作组织成一组命令与一组专职角色。命令表(见 skill/SKILL.src.md)里,document 命令的定位是"Generate DESIGN.md from existing project code",其执行细则沉淀在 reference/document.md 中;而真正动手执行的,是名为 impeccable-documenter 的 agent(在 codex 环境中写作 impeccable_documenter)。

Documenter 的使命由一句核心信念统领:

设计系统的唯一事实来源是已交付的构建产物(shipped artifact)。你写下的每一个 token、每一条规则,都必须由实际构建出来的代码作证,而不是由当初的计划作证。

在 Impeccable 中"事后写规则"是刻意为之的设计:先于构建写成的规则手册会被拿去"为现实辩护",而不是"描述现实"。这与 reference/new-work.md 中"DESIGN.md 在 finish 阶段由构建产物写出;先于构建的规则手册只会被现实反复反驳,并给设计系统检测器一个不稳定的目标"的规则一脉相承——一个新世界如果交付了却没有 DESIGN.md,仍算一次不完整的运行。

在流程中的触发位置

Documenter 并非随时可跑的后台任务,它有严格的触发时机。看 reference/new-work.md 的第 7 节"Inspect and finish":在 finish reviewer 给出 ship 裁定后,构建线程才 spawn 官方 Documenter,传入项目根、制品路径、方向契约、PRODUCT.md、document.md 参考路径与写入边界。关键约束有二:

  • Documenter 必须运行在最后一批修正落地之后。若文档化之后还有任何 fix round,就必须对变更过的表面重跑 Documenter——一份描述着已不存在布局的 DESIGN.md,等于把缺陷固化成了系统级指导。
  • 一次运行的"完成"定义不是"检测器通过"。"finished is the contract kept, the comp honored, the review closed, and the system recorded"——契约守住、对比稿兑现、评审关闭、系统被记录下来,四者缺一不可。

多种形态的同一份 agent 定义

Documenter 的定义文件在仓库中同时存在多个镜像,内容同源、随发行渠道裁剪:

degraded 目录下还平行放着 asset-producer.mdfinish-reviewer.mdmanual-edit-applier.md,说明 Impeccable 把每个"专职 subagent 角色"都预生成了一份内联替代品。

降级模式:无子代理能力时如何内联执行

本文聚焦的 degraded 变体,其存在前提写在开头第一段:

该运行时(harness)没有 subagent 能力,因此你将以**内联(inline)**方式执行这个角色。先从刚完成的构建工作中完全抽身,本趟 pass 只遵循本文件指令,并在汇报时用一行披露这次替代执行。

这带来两个执行语义的转变:

  1. 身份分离:没有独立子代理上下文可供隔断时,你必须靠自己完成"上下文隔离"。原文要求"Step fully out of the work you just finished"——不再引用构建线程的乐观倾向与抽象,仅以本文件为行为规范。
  2. 双重身份:原文中凡以"父代理"为主语的地方,现在读写双方是你自己——先产出完整输出契约,再亲自照它执行("produce the full output contract first, then act on it yourself")。

同样的降级逻辑也出现在 finish reviewer 的说明中:只有完全没有 subagent 能力的运行时,才允许用"在当前线程内全新执行、完全脱离构建上下文"的方式替代(见 reference/new-work.md)。也就是说,degraded 不是降质,而是把"独立评审者/独立记录员"这一隔离纪律,翻译成无隔离机制下的自约束纪律。

硬性回合上限下的执行预算

degraded 文档紧接着强调了运行时的残酷现实:存在一个硬回合上限(hard turn ceiling),到点即终止且无预警;而"在 DESIGN.md 写出之前就结束的运行,等于什么都没记录"。

由此推导出明确的时间管理策略:

  • 把多次 Read 批量塞进每一回合;
  • 优先reference/document.md 与样式表(它们决定产物的格式与证据);
  • 对组件采用采样而非全树遍历;
  • 在运行中点(midpoint)之前就要开始动笔。

"从一手证据里记录出的系统,胜过一趟从未落成文件的穷举扫描"——这是对 AI 回合预算最务实的承认。

输入契约:记录员拿到的信封

Documenter 不自主寻找工作对象,它由上游(new-work 的 finish 段)按契约投喂。degraded 文档列出的输入期望包括:

输入 含义
项目根(project root) 决定 token 扫描范围与 DESIGN.md 的落点坐标
制品路径(artifact path(s)) 已交付的页面/代码位置,是取证对象
方向契约文本 THESIS、OWN-WORLD、STORY、FIRST VIEWPORT、FORM 六个 block(与 new-work.md 第 5 节定义的 direction contract 一致);其中 OWN-WORLD 块命名"世界",而构建展示它最终如何落地
PRODUCT.md 路径 只取那些真正约束视觉系统的持久品牌承诺
本技能 reference/document.md 的路径 格式、token schema、侧车与章节顺序的运行规范(operating spec),必须逐条照办
写入边界 project 根或 app 根二选一

一条最重要的改写约束:已存在 DESIGN.md 时是"更新",不是"替换"——保留被确认的在任决策,并把它们与这次构建对账调和。这与操作规范里"若 DESIGN.md 已存在,绝不静默覆盖,先展示既有文件再让用户选择 refresh / overwrite / merge"的要求一致。

五步工作流:从取证到落盘

degraded 文档把 Documenter 的执行压缩成五步:

  1. 通读 reference/document.md——它是 DESIGN.md 格式、token schema、侧车、章节顺序的运作规范,"Follow it exactly"(严格执行)。
  2. 扫描制品:样式表、自定义属性、源码中的计算值、组件模式、间距节奏、实际使用的字阶(type ramp)。方向契约的 OWN-WORLD 块命名了世界,构建展示其落地形态——两者相悖时,构建胜出,行文可注明该分叉。
  3. 只写持久的系统规则:项目实际使用的 token、构建实际遵循的具名规则。跳过一次性数值——"只用过一次的 token 不构成系统"。
  4. 规避两类记录错误(见下节)。
  5. 绝不把 craft-floor 的拒绝项写成系统规则:任何被 floor 禁止的元素,都要记入"未成规(not-canonized)"行,作为构建携带的缺陷,而不是留给未来表面继承的设计系统规则。

两类会写错规则的现场事故

第 4 步列出的"规则出错方式",都来自实况观察:

  • 禁令误伤本土手段:写下一条禁令,禁止了这个世界自身天然使用的装置。因此在落笔任何 prohibition 之前,都要拿世界自己的材料(native materials)去核对。
  • 用数值洗白缺陷:记录一个值,仅仅是为了让某条审查发现"消失"。文档的裁决是:一个值靠构建与可读性赢得位置,绝不靠抹掉一条 finding

第 5 步:为什么 craft-floor 的拒绝项不能成为规则

这条直接引用了 craft floor 的禁令清单(见 reference/craft-floor.md 的 Refuse 段):标题上方的 kicker/eyebrow、非新粗野主义(neobrutalist)世界里的硬偏移阴影、字符图标(glyph icons)、系统显示字体等,都是 floor 明确拒绝的元素。Documenter 的纪律是:这些拒绝项只能出现在你的 not-canonized 行里,作为"构建携带的缺陷",绝不能演变为未来表面继承的"家规"。

文档给了一个极其典型的反例:某次 live 会话擅自上线了五个编造的 kicker,而 Documenter 竟然把它们的样式写进了 DESIGN.md——"一次违规就这样变成了房子风格(house style)"。这正是第 5 步要掐断的链条。

输出契约:交付物的形状

degraded 文档对输出的要求极为克制,禁止多余散文:

  1. 写下的文件路径
  2. 五行系统摘要:调色板策略、字阶形状、具名规则(named rules);
  3. 一行说明:构建中有哪些内容是你刻意未成规的,以及原因。

运行规范:document.md 究竟要求产出什么

degraded 文档反复指向 reference/document.md,称其为"操作规范"。要理解 Documenter 的实际工作量,必须知道这份规范要求的两层产物——这也是 Documenter 相对同目录 asset-producer、finish-reviewer 的技术核心所在。

产物一:DESIGN.md(符合 Stitch 生态的开放格式)

DESIGN.md 遵循 Google Stitch 的设计系统格式规范:可选 YAML frontmatter 承载机器可读 token,后接最多八个固定顺序的 Markdown 章节。文档明确"Tokens are normative; prose provides context",即 token 是规范性的,散文只提供如何应用的语境。仓库根目录的 DESIGN.md 与 docs 中关于 comp-fidelity 的评审记录,都落在该体系上;而 CLAUDE.md 也说明 DESIGN.md 故意不带 schema 戳记,正因为它服从 Stitch linter 校验的外部格式。

frontmatter 的 token schema 结构如下:

---
name: <project title>
description: <one-line tagline>
colors:
  primary: "#b8422e"
  neutral-bg: "#faf7f2"
  # ...one entry per extracted color; key = descriptive slug
typography:
  display:
    fontFamily: "Cormorant Garamond, Georgia, serif"
    fontSize: "clamp(2.5rem, 7vw, 4.5rem)"
    fontWeight: 300
    lineHeight: 1
    letterSpacing: "normal"
  body:
    # ...
rounded:
  sm: "4px"
  md: "8px"
spacing:
  sm: "8px"
  md: "16px"
components:
  button-primary:
    backgroundColor: "{colors.primary}"
    textColor: "{colors.neutral-bg}"
    rounded: "{rounded.sm}"
    padding: "16px 48px"
  button-primary-hover:
    backgroundColor: "{colors.primary-deep}"
---

约束规则对 Documenter 的抽取有决定性影响:

  • Token 引用{path.to.token} 语法;组件可以引用原语(primitives),原语之间不能互相引用;
  • 颜色接受任意合法 CSS 颜色串,但推荐 hex 以保证可移植性;若项目规范源是 rgb()/hsl()/oklch()/广色域值,则保留它,不要无理由拆裂事实来源;
  • 组件子 token 只有 8 个属性位backgroundColortextColortypographyroundedpaddingsizeheightwidth。阴影、动效、focus ring、backdrop-filter 都放不进 schema,必须移交侧车(这正是设计.json 存在的原因);
  • 刻度键名开放:用项目自己的名字(oxblood-deepsurface-container-low),不要改写成 Material 默认名;variant 是命名约定而非 schema(button-primary / button-primary-hover / button-primary-active 作为兄弟键)。

Markdown 主体是八个固定顺序的章节:OverviewColorsTypographyLayoutElevation & DepthShapesComponentsDo's and Don'ts。规范强调:无关章节宁可省略,也不要用编造的规则填充;不要把近义标题替换规范标题("Colors"不能被改成"Color Palette & Roles"),因为解析工具依赖精确标题。

产物二:.impeccable/design.json 侧车(schemaVersion 2)

frontmatter 只能装 token 原语;schema 装不下的东西全部进侧车:每种颜色的 tonal ramp(8 步,深到浅、同色相同色度、亮度从约 15% 步进到约 95%)、shadow/elevation token、动效 token、断点、完整组件 HTML/CSS 片段(devtools 面板将其注入 shadow DOM 渲染),以及叙事层(north star、rules、do's/don'ts)。侧车结构如下:

{
  "schemaVersion": 2,
  "generatedAt": "ISO-8601 string",
  "title": "Design System: [Project Title]",
  "extensions": {
    "colorMeta": {
      "primary": { "role": "primary", "displayName": "Editorial Magenta", "canonical": "oklch(60% 0.25 350)", "tonalRamp": ["...", "..."] }
    },
    "typographyMeta": { "display": { "displayName": "Display", "purpose": "Hero headlines only." } },
    "shadows": [ { "name": "ambient-low", "value": "0 4px 24px rgba(0,0,0,0.12)", "purpose": "Diffuse hover glow under accent elements." } ],
    "motion": [ { "name": "ease-standard", "value": "cubic-bezier(0.4, 0, 0.2, 1)", "purpose": "Default easing for state transitions." } ],
    "breakpoints": [ { "name": "sm", "value": "640px" } ]
  },
  "components": [
    {
      "name": "Primary Button",
      "kind": "button | input | nav | chip | card | custom",
      "refersTo": "button-primary",
      "description": "One-line what and when.",
      "html": "<button class=\"ds-btn-primary\">SAVE CHANGES</button>",
      "css": ".ds-btn-primary { background: #191c1d; color: #fff; ... }"
    }
  ],
  "narrative": {
    "northStar": "The Editorial Sanctuary",
    "overview": "2-3 paragraphs ...",
    "keyCharacteristics": ["..."],
    "rules": [{ "name": "The One Voice Rule", "body": "...", "section": "colors|typography|elevation" }],
    "dos": ["Do use ..."],
    "donts": ["Don't use ..."]
  }
}

侧车 schemaVersion 2 相对 v1 的关键变化:token 原语数组全部上移到 frontmatter,侧车只保留 frontmatter 装不下的元数据,按键与 token 名对齐(colorMeta.<token-name>typographyMeta.<token-name>)。

组件片段的自包含翻译规则

侧车中的组件 html/css 必须可直接注入 shadow DOM 渲染,禁止任何后处理或框架运行时依赖。Documenter 需要遵守六条翻译规则:

  1. Tailwind 展开:源码若用 Tailwind 类名,必须把每个工具类展开成字面 CSS 属性,不能引用 Tailwind 类、不能假设 Tailwind bundle 已加载;
  2. Token 解析:token 若暴露为 :root 上的 CSS 自定义属性,用 var(--color-primary) 引用,可穿过 shadow DOM 保持活绑定;若 token 只存在于 JS theme 对象(styled-components/CSS-in-JS),则在生成时解析成字面值;
  3. 图标内联 SVG:禁止引用 Lucide/Heroicons、图标字体或 <img src="...">,典型图标 16–24px,直接拷贝 SVG path 数据;
  4. 状态齐全:必须内联 :hover:focus-visible 及有意义的 :active,纯默认态快照会让面板"死掉";
  5. 去重置化:只提取组件有辨识度的 CSS(背景、颜色、内边距、圆角、排版、过渡),丢弃全局 reset(box-sizingline-height: inherit-webkit-font-smoothing);
  6. 作用域类名:所有类加 ds- 前缀,防止同一 shadow DOM 内组件样式互相碰撞。

组件取舍上,规范给出"5–10 个最能代表视觉系统"的密度目标:按钮每个 variant 单独成条、input/导航/chip/卡片为必备原语,有辨识度的签名组件必收,其余(工具组件、表单积木、包装布局)除非视觉独特否则跳过。即便项目还没有组件库,也要从 token 合成符合 DESIGN.md 规则的规范原语——"每一份 design.json 在 day zero 都必须有可渲染的东西"。

叙事映射:散文不重写、只搬运

侧车的 narrative 字段要求逐字搬运 DESIGN.md 的已有内容,禁止改写

  • narrative.northStar ← Overview 中的 **Creative North Star: "..."**
  • narrative.overview ← Overview 的哲学段落;
  • narrative.keyCharacteristics**Key Characteristics:** 列表;
  • narrative.rules ← 全文所有 **The [Name] Rule.** [body],并打上 section 标签;
  • narrative.dos / donts ← Do's and Don'ts 的列表原文。

因为 devtools 的 live panel 会把这些渲染成次级可折叠上下文,同一副嗓音必须从 Markdown 贯通到面板。仓库中渲染侧车的位置在 extension/devtools 的 panel 体系与 skill/scripts/live-browser.js(其 Design System Panel 直接读取 .impeccable/design.json v2 payload 的 extensions + components + narrative),它们正是 Documenter 产物的下游消费者——这也解释了为什么 token schema 严格遵守 Stitch 的 Zod 校验集合:colorstypographyroundedspacingcomponents 之外不允许在 frontmatter 顶层发明 motion:breakpoints:shadows: 等 token 组,多余信息一律进侧车 extensions

两种运行路径与触发条件

操作规范把 Documenter 拆成 Scan / Seed 两种模式,配合 reference/routing.mdreference/doctor.md 决定何时进入:

  • Scan mode(默认):项目已有 token、组件或渲染输出。按优先级查找设计资产(CSS 自定义属性 → Tailwind config → CSS-in-JS theme 文件 → 设计 token 文件 → 组件库 → 全局样式表 → 可见渲染输出),能自动抽取的自动抽取,随后用两轮(每轮最多三问)向用户求证无法自动化的定性语言——Creative North Star、Overview 嗓音、色彩性格命名、纵深哲学、组件气质。决策纪律是:先扫描再决定,若扫不到任何 token/组件文件/已渲染站点,应提议 seed mode,不能静默切换。
  • Seed mode:项目尚无视觉系统可抽取。以 PRODUCT.md 为前提,走 new-work 的 visual-world 工作坊产出方向性种子(带 <!-- SEED: ... --> 标记,frontmatter 只写 namedescription),不伪造实现 token;种子文件诚实标注未决实现事实为占位符,等有代码后重跑 Scan mode 落地真实 token 与侧车。种子模式同时跳过 sidecar——"没有可渲染的东西"。

从路由表看,setup.hasDesign=falsesetup.hasCode=true 的项目直接路由到 document;doctor 工具则负责发现"代码已经漂移、文档不再描述它"的漂移,并把 document(DESIGN.md 的属主)作为修复去向——但 doctor 的职责是交出一个具体缺口,而非自行代跑对话式的文档化。

一以贯之的记录纪律

把 degraded 文档与它的操作规范放在一起看,Documenter 的全部行为可以被收束成七条可检验的记录纪律:

  1. 证据先行:每个 token/规则必须能在已构建代码里找到出处,计划与意图不构成证据;
  2. 只收持久系统:一次性数值不抽取、不写入;只用一次的 token 不是系统;
  3. 规范格式不可妥协:frontmatter 先行、散文次之;八章节固定顺序;token 值不许在散文里二次重定义(frontmatter 是规范源);颜色按角色(Primary/Secondary/Tertiary/Neutral)分组而非按色相排序;
  4. 描述性优先:写"Gently curved edges (8px radius)"而不是"rounded-lg"——技术值放括号、描述打头;每个 token 讲清在哪用、为何用,而不只讲是什么;
  5. 禁令须反向核对:任何 prohibition 都要对照世界自身材料,防止误伤本土手段;任何数值都要经受可读性考验,防止成为洗白缺陷的工具;
  6. craft-floor 拒绝项不得成规:kicker、硬偏移阴影、字符图标、系统显示字体等只进 not-canonized 行;
  7. 落盘即完成:硬回合上限之下,先保障 DESIGN.md 存在,再从主证据出发补齐完整性——"从一手证据记录出的系统,胜过从未成文件的穷举"。

这七条纪律让 Documenter 同时服务两头:对内,它是 Impeccable 每个构建收尾的"归档员",保证一次运行不欠 DESIGN.md 的债;对外,它产出的 Stitch 兼容 DESIGN.md 与 schemaVersion 2 侧车,让任何 AI 代理(无论是否有 subagent 能力)都能在一个稳定、可引用、与代码同步的品牌基座上继续生成新表面。降级变体或许少了一个独立进程,但它强制执行的"先抽身、再执行、最后一行披露"的自约束,恰恰保住了独立记录与内联执行之间的纪律边界。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
34
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.16 K
2.78 K
docsdocs
暂无描述
Markdown
904
5.83 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
934
1.86 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
862
1.36 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
535
606
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.38 K
1.47 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.97 K
1.03 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
549
399
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.06 K
536