OpenDesign 四原语解析:31 个 Skill、72 个 System 的库是如何运作的
OpenDesign 从机制上看是四个层层叠加的原语:Skill 决定 agent 做什么,System 决定输出长什么样,Adapter 决定由哪个本地 agent 干活,daemon 则是把它们串接起来的循环。本文逐一拆解这四个原语的文件形态与注册机制,并结合 skills/、design-systems/、apps/daemon/src/runtimes/ 的真实源码说明一个 Markdown 文件如何变成一份可导出的交付物,读完你可以完整理解 OpenDesign 的"文件即注册表"设计,并知道如何 fork、混搭或扩展这个库。
四个原语一览
每个原语都是一个装着文件的文件夹,谁都不需要数据库、插件运行时或托管服务。这就是整个库的全部——没有藏在登录墙后面的第五个概念。
| 原语 | 位于 | 文件 | 事实源 |
|---|---|---|---|
| Skill | skills/ |
SKILL.md |
磁盘上的那个文件 |
| System | design-systems/ |
DESIGN.md |
磁盘上的那个文件 |
| Adapter | apps/daemon/src/runtimes/defs/ |
一个 .ts 文件 |
一次注册(registry 数组中的一条 def) |
原文档写作时内置 31 个 skill、72 个 system、25 个 CLI runtime 的 adapter;以当前仓库快照看,skills/ 下已有 162 个 skill 文件夹,design-systems/ 下有 150 余个 system 包,runtimes/defs 目录内置了 27 个 CLI 定义——库本身在持续增长,但原语的形态没有变。
Skill:能力的基本单位
一个 skill 就是一个文件夹,里面装着一个 SKILL.md 以及零个或多个辅助文件。这个 Markdown 文件是 agent 的契约——文件夹里其余的一切都是为了帮助 agent 兑现它。
一个 skill 文件夹的解剖
一个典型的 skill 长这样:
skills/
guizang-ppt/
SKILL.md
templates/
magazine.html
examples/
product-launch.html
pitch-deck.html
SKILL.md 声明了这个 skill 的名字、触发条件、输入形态、输出形态,以及给 agent 的任何内联指引。templates/ 和 examples/ 文件夹是可选的,但分量很重:example 是已知良好的产物,agent 可以拿它来做模式匹配——这正是"给我做一套 deck"到底是产出一个连贯的东西,还是产出一个临场拼凑的东西之间的区别。
front matter 是 daemon 读来登记 skill 的部分;正文则是 agent 读来执行它的部分。原文文档给出的简化示例:
---
name: guizang-ppt
trigger: a deck, slide presentation, or pitch
output: HTML (exportable to PDF, PPTX)
---
Build a horizontal slide deck. One idea per slide.
Lead with a cover, close with a call to action.
Respect the locked-in design system for color, type, and spacing.
Pattern-match against examples/ for layout density and rhythm.
结合仓库中的 Skills Protocol 规范 可以看到实际的前置语法:SKILL.md 沿用 Claude Code 的 Agent Skills 约定,基础字段包括 name、description、triggers(触发关键词列表),正文则是描述 agent 应遵循工作流的自由 Markdown,通常是编号步骤加原则。在此基础上 OpenDesign 提供可选的 od: 扩展字段来解锁产品 UI,例如:
od:
mode: deck # prototype | deck | template | design-system | image | video | audio
surface: web # web | image | video | audio
scenario: marketing # 画廊/过滤提示
category: presentations # 自由格式的小写过滤 slug
example_prompt: "Create a magazine-style web deck from my content."
design_system:
requires: true # 组合完整的激活 design-system 上下文
craft:
requires: [typography, color, anti-ai-slop]
critique:
policy: opt-in # required | opt-in | opt-out
所有 od: 字段都是可选的,缺失时回退到合理默认值;skills 目录 下的每个 skill 文件夹(例如 skills/deck-guizang-editorial/、skills/faq-page/、skills/mobile-onboarding 对应的模板类 skill)都可以按同一套约定阅读和编写。
为什么文件本身就是注册表
当 daemon 启动时,它会扫描 skills/,并把每一个含有 SKILL.md 的文件夹登记进来。没有插件清单、没有版本字段、没有上传步骤、没有审核队列、没有构建。只有这个文件,而这个文件就是事实源。丢进一个新文件夹,重启 daemon,这个 skill 就出现在选择器里;删掉它,它就没了——不会留下一条指向已不存在代码的孤儿注册项。
内置 skill 覆盖面很广:有些是 deck 生成器,有些产出移动端原型,有些构建编辑风页面,有些撰写办公文档(Word、Excel、PowerPoint)。每一个都是你可以 fork、编辑或替换的文件夹。因为契约就是纯文本,"写一个 skill"和"读一个 skill 来理解它做什么"是同一件事——你审查它的方式就是打开它。
System:审美的基本单位
如果说 skill 描述的是做什么,那么 system 描述的是它应该长成什么样。一个 system 就是一个 DESIGN.md 文件,外加可选的参考资源。它以机器可读的形式描述一套视觉识别:
- Color——前景、背景、强调色、错误色等的取值(原文以 OKLch 为例)
- Type——字体栈、字重、字号阶梯、行高约定
- Space——基础单位、间距阶梯、容器宽度、栏间距规则
- Layout posture——网格选择、非对称规则、密度偏好
- Voice——文字的"排版":语气、用词、句子节奏
DESIGN.md 是一份契约,不是组件库
实践中,一份 DESIGN.md 读起来像一份简短、有主见、agent 不可能误读的品牌 brief:
## Color
--bg: oklch(98% 0.01 95);
--ink: oklch(20% 0.02 260);
--accent: oklch(72% 0.19 35);
## Type
Display — Albert Sans, 600, -0.02em
Body — Albert Sans, 400, 1.7 line-height
## Posture
Generous whitespace. One accent, used sparingly. No drop shadows.
颜色用 OKLch 这类感知均匀的色彩空间表述,是为了让它们在明暗表面上都保持知觉上的均匀;字号阶梯是一架 agent 不会偏离的梯子;而 posture 规则正是"十个生成出来的屏幕感觉像同一个产品"与"十个屏幕感觉像十个不同实习生做的"之间的差别。agent 读一遍这份契约,然后在整个任务里都遵守它。
一个 system 不是 Figma 库。没有组件、没有变体、没有嵌套实例、没有横在你和规则之间的二进制格式。它是任何 agent 都能读、任何人类都能审查的契约。开箱内置的 system 包括 Linear、Vercel、Stripe、Apple、Cursor、Figma 的可移植版本,以及一长串编辑风与品牌 system。
仓库里一个真实 system 包的结构
从源码结构看,当前仓库中每个 system 已经长成一套完整但仍是纯文本/纯 JSON 的包。以 Linear 的 design system 为例,目录包含:
- DESIGN.md——主契约。开篇即声明"Design System Inspired by Linear",随后分章节描述视觉主题与氛围(dark-mode-native 的
#08090a画布、Inter Variable 的cv01/ss03特性、标志性的 510 字重、72px 处 -1.584px 的负字距等)与完整的颜色角色表; - manifest.json——机读清单,声明
schemaVersion: "od-design-system-project/v1"、包 id、分类,以及files字段把 DESIGN.md、tokens.css、design-tokens.json、tailwind-v4.css、components.html 各自指出来,schema 定义在 design-systems/_schema/ 中; - USAGE.md、
tokens.css、design-tokens.json、tailwind-v4.css、components.html及其components.manifest.json——分别承担用法说明、CSS 变量、JSON token、Tailwind v4 主题与组件参考。
default system 是未指定品牌时的回退包,结构完全一致。这印证了原文的论断:system 是契约加参考资产,而不是组件库——components.html 是供 agent 模式匹配的参考,而非需要实例化的二进制组件。
混搭、fork、拥有
因为一个 system 不过是文本,你可以 fork 一个并就地编辑、交付一个变体,或者用大约 30 分钟的专注工作从头写一个自己的。你甚至可以在项目进行中混搭多个 system——排版取自 Linear、配色逻辑取自 Vercel、版式取自一份内部规范——因为没有任何东西被锁进专有的二进制里。skills/ 和 design-systems/ 两个文件夹的拆分是刻意的:能力与审美是正交的,所以任何 skill 都能在任何 system 下运行,任何 system 也都能驱动任何 skill。
Adapter:agent 的基本单位
skill 和 system 是惰性的文本。adapter 则是把它们连接到真正干活的 agent 的那一小段代码。一个 adapter 懂得如何:
- 检测该 agent 是否已安装在用户的
$PATH上 - 用该 agent 开启一个会话
- 把一次 skill 调用喂进去
- 把输出收集回来
daemon 会自动检测哪些 agent 已存在,并在首次启动时以下拉菜单的形式提供它们——你什么都不用配置,只会看到你已经拥有的那些 agent。
源码级:RuntimeAgentDef 是数据规范,不是类
结合 Agent Adapters 设计文档 与源码,adapter 层的实现比"80 行 TypeScript"还要更刻意地小。从源码结构看,adapter 不是一个实现了 agent 循环的类,而是一个纯数据对象——每个 CLI 对应一个 RuntimeAgentDef 对象字面量,声明"如何与这个 CLI 对话":探测哪个二进制(bin / fallbackBins)、如何构造版本探测参数(versionArgs)、如何为单轮构造 argv(buildArgs)、流式输出走哪种格式(streamFormat,如 claude-stream-json、acp-json-rpc、plain)、prompt 走 stdin 还是文件,等等。完整的类型定义在 runtimes/types.ts。
每个字段都是数据或纯参数构造函数——没有 run()、没有 cancel()、没有子类。检测、启动、调用、流解析全部由通用引擎驱动这些声明完成。关键代码的分布:
- 每个 CLI 一个 def 文件:runtimes/defs/ 下的
claude.ts、codex.ts、cursor-agent.ts、devin.ts、hermes.ts、qwen.ts等,每个导出一个对象字面量; - 注册表是一个 id 唯一的数组:runtimes/registry.ts 把所有 def 收集进
SHIPPED_AGENT_DEFS,启动时的循环会在任何重复id上直接抛错,AGENT_DEFS再追加用户自定义的本地 profile。
这意味着新增一个 CLI 是单文件改动:丢一个 runtimes/defs/<cli>.ts 进目录、在 registry 数组里加一行,引擎就能探测、启动、调用并流式解析它——没有引擎编辑、没有新类、没有方法覆写。只有当出现全新的 wire 格式时,才需要额外加一个 *-stream.ts 解析器。内置的 27 个 def 覆盖了 Claude Code、Codex、Cursor Agent、Copilot、OpenCode、Devin、Hermes、Kimi、Kiro、Qwen、DeepSeek、DeepSeek Harness、Aider 等本地 CLI runtime。
如果你只是想新增一个 adapter,"没有要学的 SDK、没有要申请的权限、没有要发布到的中心注册表"——你笔记本上早已信任的那个 agent 就成了引擎,OpenDesign 从不取代它。
daemon:把一切系在一起的循环
daemon 是系统里唯一在运行的进程,是一个用 pnpm tools-dev 启动的 Node 进程(根 package.json 中该脚本指向 workspace 包 @open-design/tools-dev,实现位于 tools/dev/),依次做四件事:
- Detect(检测)——启动时扫描
$PATH查已安装的 agent、扫描skills/查已安装的 skill; - Discover(探询)——打开一个交互式提问表单,为当前 brief 锁定载体、受众、语气、规模和品牌上下文;
- Direct(定向)——给出 5 个确定性的视觉方向(OKLch 配色、字体栈、版式 posture 提示),让用户挑一个;
- Deliver(交付)——用锁定的 system 调起选中的 skill,让 agent 写到磁盘,并在沙箱化的 iframe 里预览输出。
原文档强调这个循环刻意做小:聪明之处在 skill 里,而不在运行时——daemon 的工作就是扫描文件夹、把一份 brief 路由过这四步,然后让到一边。以当前仓库快照看,daemon 进程(apps/daemon/src/)已经长成一个规模可观的服务端代码库,但"文件是事实源、agent 循环全部委托给用户的 CLI"这一架构承诺没有变——检测、调用、流式解析仍全部由上面描述的通用引擎加数据 def 驱动。
实践中它是什么感受
假设你想为一个新产品功能做一套发布 deck,流程是这样的:
- 你在终端里运行
pnpm tools-dev。daemon 在本地端口启动(原文档给出的地址为localhost:7780)。 - 你打开这个 URL。daemon 给你看它找到了哪些 agent(例如 Claude、Cursor、Codex)。
- 你从 skill 列表里挑选一个 deck 生成器(如
guizang-ppt对应的 skill)。 - 弹出一个 30 秒的提问表单:受众是谁、语气是什么、品牌上下文是什么。
- 你被展示了 5 个视觉方向——不同的配色、字体搭配、版式 posture。你挑一个。
- agent 写到磁盘。一个沙箱化的 iframe 显示出结果。你可以导出为 HTML、PDF、PPTX、ZIP 或 Markdown。
顺着这些原语回溯,整件事就一目了然:第 3 步选了一个 skill,第 5 步锁定了一个 system,背后的那个 agent 是通过一个 adapter 接进来的,而 daemon 跑完了这四步循环。输出是真实的,文件是你的——你可以在任何编辑器里改它们,把它们交给一位设计师,或者把它们重新喂回另一个 skill。
为什么用文件,而不是数据库
每一个原语——skill、system、adapter——都是一个装着文本文件的文件夹。没有中心数据库,没有"OpenDesign 账户",没有那种必须一直运转、你的工作才能一直运转的托管服务。
这是一笔刻意的交换。它放弃了做花哨的跨用户分析、跨项目记忆或托管协作的能力,换回来的是:可移植性、长寿、可审查性,以及任何人都能 fork 整个库并交付自己变体的能力。今天写下的一个 SKILL.md,两年后对一个 agent 读起来一模一样,对一个手头没有任何工具的人类也读起来一模一样——而一个被钉死在去年某个 API 上的插件可做不到这一点。
如何在仓库中继续深入
- Skills Protocol:front matter 语法、发现规则、
od:扩展字段的完整规范; - Agent Adapters:adapter 数据契约、检测策略、流式解析分派的完整设计说明;
- Skills Contributing:如何把你的 skill 提交进上游库;
- 架构总览 与 daemon 源码:四步循环在服务端的具体落点;
- skills/ 与 design-systems/:所有内置原语的实体目录,逐一打开即是审查。
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