用构建产物反写设计系统:Impeccable Documenter 的逆向设计文档化实践与内联降级模式
在 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 的定义文件在仓库中同时存在多个镜像,内容同源、随发行渠道裁剪:
- skill/agents/impeccable-documenter.md:技能包内的源定义,含完整 frontmatter(
name: impeccable-documenter、codex-name: impeccable_documenter、tools: Read, Write, Bash, Glob, Grep、effort: medium、max-turns: 30等); - plugin/agents/impeccable-documenter.md:OpenAI plugin 发行版的同角色(frontmatter 使用
maxTurns: 30); - .grok/skills/impeccable/reference/degraded/documenter.md 与 plugin/skills/impeccable/reference/degraded/documenter.md:按运行时能力裁剪出的 degraded(降级)变体,文件头注明"Generated from skill/agents/ at build time. Do not edit; edit the agent definition.",即它是构建时从
skill/agents/生成的派生文件,改源头才有效。
degraded 目录下还平行放着 asset-producer.md、finish-reviewer.md、manual-edit-applier.md,说明 Impeccable 把每个"专职 subagent 角色"都预生成了一份内联替代品。
降级模式:无子代理能力时如何内联执行
本文聚焦的 degraded 变体,其存在前提写在开头第一段:
该运行时(harness)没有 subagent 能力,因此你将以**内联(inline)**方式执行这个角色。先从刚完成的构建工作中完全抽身,本趟 pass 只遵循本文件指令,并在汇报时用一行披露这次替代执行。
这带来两个执行语义的转变:
- 身份分离:没有独立子代理上下文可供隔断时,你必须靠自己完成"上下文隔离"。原文要求"Step fully out of the work you just finished"——不再引用构建线程的乐观倾向与抽象,仅以本文件为行为规范。
- 双重身份:原文中凡以"父代理"为主语的地方,现在读写双方是你自己——先产出完整输出契约,再亲自照它执行("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 的执行压缩成五步:
- 通读
reference/document.md——它是 DESIGN.md 格式、token schema、侧车、章节顺序的运作规范,"Follow it exactly"(严格执行)。 - 扫描制品:样式表、自定义属性、源码中的计算值、组件模式、间距节奏、实际使用的字阶(type ramp)。方向契约的 OWN-WORLD 块命名了世界,构建展示其落地形态——两者相悖时,构建胜出,行文可注明该分叉。
- 只写持久的系统规则:项目实际使用的 token、构建实际遵循的具名规则。跳过一次性数值——"只用过一次的 token 不构成系统"。
- 规避两类记录错误(见下节)。
- 绝不把 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 文档对输出的要求极为克制,禁止多余散文:
- 写下的文件路径;
- 五行系统摘要:调色板策略、字阶形状、具名规则(named rules);
- 一行说明:构建中有哪些内容是你刻意未成规的,以及原因。
运行规范: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 个属性位:
backgroundColor、textColor、typography、rounded、padding、size、height、width。阴影、动效、focus ring、backdrop-filter 都放不进 schema,必须移交侧车(这正是设计.json 存在的原因); - 刻度键名开放:用项目自己的名字(
oxblood-deep、surface-container-low),不要改写成 Material 默认名;variant 是命名约定而非 schema(button-primary/button-primary-hover/button-primary-active作为兄弟键)。
Markdown 主体是八个固定顺序的章节:Overview、Colors、Typography、Layout、Elevation & Depth、Shapes、Components、Do'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 需要遵守六条翻译规则:
- Tailwind 展开:源码若用 Tailwind 类名,必须把每个工具类展开成字面 CSS 属性,不能引用 Tailwind 类、不能假设 Tailwind bundle 已加载;
- Token 解析:token 若暴露为
:root上的 CSS 自定义属性,用var(--color-primary)引用,可穿过 shadow DOM 保持活绑定;若 token 只存在于 JS theme 对象(styled-components/CSS-in-JS),则在生成时解析成字面值; - 图标内联 SVG:禁止引用 Lucide/Heroicons、图标字体或
<img src="...">,典型图标 16–24px,直接拷贝 SVG path 数据; - 状态齐全:必须内联
:hover、:focus-visible及有意义的:active,纯默认态快照会让面板"死掉"; - 去重置化:只提取组件有辨识度的 CSS(背景、颜色、内边距、圆角、排版、过渡),丢弃全局 reset(
box-sizing、line-height: inherit、-webkit-font-smoothing); - 作用域类名:所有类加
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 校验集合:colors、typography、rounded、spacing、components 之外不允许在 frontmatter 顶层发明 motion:、breakpoints:、shadows: 等 token 组,多余信息一律进侧车 extensions。
两种运行路径与触发条件
操作规范把 Documenter 拆成 Scan / Seed 两种模式,配合 reference/routing.md 与 reference/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 只写name与description),不伪造实现 token;种子文件诚实标注未决实现事实为占位符,等有代码后重跑 Scan mode 落地真实 token 与侧车。种子模式同时跳过 sidecar——"没有可渲染的东西"。
从路由表看,setup.hasDesign=false 且 setup.hasCode=true 的项目直接路由到 document;doctor 工具则负责发现"代码已经漂移、文档不再描述它"的漂移,并把 document(DESIGN.md 的属主)作为修复去向——但 doctor 的职责是交出一个具体缺口,而非自行代跑对话式的文档化。
一以贯之的记录纪律
把 degraded 文档与它的操作规范放在一起看,Documenter 的全部行为可以被收束成七条可检验的记录纪律:
- 证据先行:每个 token/规则必须能在已构建代码里找到出处,计划与意图不构成证据;
- 只收持久系统:一次性数值不抽取、不写入;只用一次的 token 不是系统;
- 规范格式不可妥协:frontmatter 先行、散文次之;八章节固定顺序;token 值不许在散文里二次重定义(frontmatter 是规范源);颜色按角色(Primary/Secondary/Tertiary/Neutral)分组而非按色相排序;
- 描述性优先:写"Gently curved edges (8px radius)"而不是"rounded-lg"——技术值放括号、描述打头;每个 token 讲清在哪用、为何用,而不只讲是什么;
- 禁令须反向核对:任何 prohibition 都要对照世界自身材料,防止误伤本土手段;任何数值都要经受可读性考验,防止成为洗白缺陷的工具;
- craft-floor 拒绝项不得成规:kicker、硬偏移阴影、字符图标、系统显示字体等只进 not-canonized 行;
- 落盘即完成:硬回合上限之下,先保障 DESIGN.md 存在,再从主证据出发补齐完整性——"从一手证据记录出的系统,胜过从未成文件的穷举"。
这七条纪律让 Documenter 同时服务两头:对内,它是 Impeccable 每个构建收尾的"归档员",保证一次运行不欠 DESIGN.md 的债;对外,它产出的 Stitch 兼容 DESIGN.md 与 schemaVersion 2 侧车,让任何 AI 代理(无论是否有 subagent 能力)都能在一个稳定、可引用、与代码同步的品牌基座上继续生成新表面。降级变体或许少了一个独立进程,但它强制执行的"先抽身、再执行、最后一行披露"的自约束,恰恰保住了独立记录与内联执行之间的纪律边界。
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 StartedRust4.21 K637- DDeepSeek-V4.1-FlashDeepSeek-V4.1-Flash 是一个多模态混合专家(MoE)模型,拥有 5520 亿骨干参数,并支持最多一百万 token 的上下文长度。该模型原生支持图像和文本输入,并以自回归方式生成文本Python320
cherry-studio🍒 Cherry Studio 是一款支持多个 LLM 提供商的桌面客户端TypeScript2 K146
hello-agents📚 《从零开始构建智能体》——从零开始的智能体原理与实践教程Python46567
new-apiAI模型聚合管理中转分发系统,一个应用管理您的所有AI模型,支持将多种大模型转为统一格式调用,支持OpenAI、Claude、Gemini等格式,可供个人或者企业内部管理与分发渠道使用。🍥 A Unified AI Model Management & Distribution System. Aggregate all your LLMs into one app and access them via an OpenAI-compatible API, with native support for Claude (Messages) and Gemini formats.Go20043
JeecgBoot🔥企业级低代码平台集成了AI应用平台,帮助企业快速实现低代码开发和构建AI应用!前后端分离架构 SpringBoot,SpringCloud、Mybatis,Ant Design4、 Vue3.0、TS+vite!强大的代码生成器让前后端代码一键生成,无需写任何代码! 引领AI低代码开发模式: AI生成->OnlineCoding-> 代码生成-> 手工MERGE,显著的提高效率,又不失灵活~Java33951