Serial Studio 的 Spec-Driven Development 体系:`doc/claude/specs/` 目录的规范、模板与生命周期
2026/9/18 2:38:03 网站建设 项目流程

Serial Studio 的 Spec-Driven Development 体系:doc/claude/specs/目录的规范、模板与生命周期

【免费下载链接】Serial-StudioOpen-source telemetry dashboard. Supports UART, BLE, MQTT, Modbus, CAN Bus and more.项目地址: https://gitcode.com/GitHub_Trending/se/Serial-Studio

本文以 Serial Studio 仓库中 doc/claude/specs/README.md 为骨架,系统讲解该仓库如何用"编号目录 + 三阶段文档"承载规格驱动开发(Spec-Driven Development)。你将理解spec.md / plan.md / tasks.md三份产物各自承载什么、编号与状态生命周期如何管理、为什么这些工件必须进入 git,并看到一个已落地的真实示例(Dashboard Freeze Mode,spec 0007)。

一、背景:什么是 Spec-Driven Development

在 Serial Studio 中,非平凡功能开发默认走"规格驱动"工作流,其总纲记录在 doc/claude/spec-driven.md:

相比在开放式对话里"提示词工程"式地引导一个功能,意图被捕获为可评审、互相设闸的工件:spec → plan → tasks → implementation。每个阶段产出一份文档,经人工批准后才进入下一阶段。契约从"Agent 是否猜对了"变成"我们在代码存在之前,是否以书面形式就此事达成一致"。

该工作流复用仓库已有的基础设施:doc/claude/下的架构子文档作为 plan 阶段的知识库、scripts/下的 linter 作为验证闸门、CLAUDE.md 中的 Trust Contract,以及若干既有技能(ss-hotpathss-verifyqt-cpp-review等)。工作流本身不做新轮子,只是把这些东西按顺序编排起来。

doc/claude/specs/目录就是这套工作流的产物仓库——每个功能一个编号目录,存放三个阶段文档。

二、目录布局:编号目录 + 共享模板

依据 doc/claude/specs/README.md,目录结构如下:

doc/claude/specs/ README.md <- 本文件(目录规范) templates/ <- 技能复制用的骨架(不要按功能逐个修改) spec.md plan.md tasks.md NNNN-short-slug/ <- 每个功能一个目录 spec.md <- /ss-spec WHAT & WHY、验收标准、非目标 plan.md <- /ss-plan 文件清单、数据流、hotpath/线程、权衡、风险 tasks.md <- /ss-tasks 有序、可单独验证的检查清单

模板目录templates/存放三个阶段的骨架文件,由技能(skills)复制后使用,不允许按功能去编辑模板本身。功能目录则按NNNN-short-slug命名,例如仓库中实际存在的:

  • 0001-composition-root(含额外的构造顺序证明笔记ctor-proof-2026-07-28-licensing-first.md
  • 0007-dashboard-freeze
  • 0021-simd-kernels
  • 0071-gpu-plot3d-waterfall

截至当前仓库,doc/claude/specs/下已有 0001 至 0086 共 86 个功能目录,覆盖从 UI(0010-manual-layout-guides)、绘制(0014-log-axes0016-multires-fft)、协议(0066-opcua-driver0074-sparkplug-multisource-node)到基础设施(0021-simd-kernels0081-runtime-simd-dispatch)的各类改动。

三、编号规则:四位补零、单调递增、永不复用

编号规则有三条硬性约定(见 doc/claude/specs/README.md 的 Numbering 一节):

  1. 四位补零、单调递增00010002、……下一个编号是max(existing) + 1,由/ss-spec技能自动计算。
  2. 编号永不复用:即使某个 spec 被搁置(shelved),它的编号也不会让给其他功能,保证历史记录的引用稳定。
  3. slug 采用 kebab-case:几个短横线分隔的小写单词描述功能名,如0007-canbus-filter风格(仓库实际例子如0007-dashboard-freeze0049-gsusb-canfd-hotplug)。

这套规则保证了目录既是"功能索引"也是"历史档案"——按编号即可感知功能引入的先后顺序,且每个编号可以永久安全地引用。

四、状态生命周期:frontmatter 驱动

每个 spec 的生命周期状态记录在spec.mdfrontmatterstatus:字段中(各阶段文档另带自己的 gate 状态)。状态机共五态(doc/claude/specs/README.md 的 Status lifecycle 一节):

状态含义
draft正在撰写,尚未成为契约
approved维护者已接受该 spec,可以开始规划
in-progress实现进行中(由/ss-implement设置)
done全部验收标准已满足并验证
shelved放弃或推迟;保留记录,编号不回收

以真实文件佐证:0007-dashboard-freeze/spec.md 的 frontmatter 写有status: done,而其 plan.md 的 frontmatter 为status: approved——这正是"spec 已验收、plan 作为设计文档保留"的分工体现。

模板 templates/spec.md 的 frontmatter 还要求spectitlecreatedauthor字段,形成完整的元数据;plan.mdtasks.md则额外携带phase: plan/phase: tasksupdated字段。

五、为什么这些工件必须进 git

doc/claude/specs/README.md 的最后一部分给出了明确的理由:spec 是可评审、可持久化的工件,不是草稿。具体收益有三点:

  1. 代码存在之前即可否决方案:把 spec 与架构子文档放在一起跟踪,意味着 plan 可以在代码写出之前就被否决——此时改动的成本为零,而不是在 600 行 diff 里返工。
  2. 半成品可恢复:一个做到一半的功能就是三个文件(spec/plan/tasks),而不是一段丢失的聊天记录;上下文压缩、新会话甚至不同的人都能无缝接手。
  3. PR 可引用:Pull Request 可以直接指向它实现的 spec,让"为什么要这么做"与"做了什么"一起随代码旅行。

在 doc/claude/spec-driven.md 中这条被概括为:spec 是持久工件,随代码同行,可被 PR 链接,为未来的你记录 why 而不只是 what

六、三份模板详解:每个阶段写什么、闸门在哪

templates/下的三个骨架文件对应四阶段工作流中的前三阶段,每一阶段都有明确的人工审批闸门。以下结合模板原文逐一拆解。

6.1spec.md—— WHAT 与 WHY(阶段 1,/ss-spec

模板顶部用引用块声明定位:

Phase 1 of 4 —— 讲 WHAT 和 WHY。不含实现细节;没有文件路径、类名、信号接线(那是plan.md的事)。闸门:在人工标记approved之前,不要启动/ss-plan

spec.md的章节结构(templates/spec.md):

  • Problem / Motivation:为什么需要它;基于真实行为(用户报告、截图、测得的限制、反复出现的支持问题)而非纸上推理,一至两段。
  • Goals:成功在可观察层面长什么样,每一条是用户或维护者能确认的单一结果。
  • Non-Goals:明确的边界——本功能刻意不做什么,防止 plan 过度建设、评审无限扩大。
  • Requirements:编号的、可测试的用户可见行为陈述,格式偏好"当 Y 发生时仪表盘显示 X"而非"为 X 添加 handler"。
  • Acceptance Criteria:每条需求如何验证,尽可能绑定到真实可跑的检查(pytest集成测试、tests/scripts/的 JS 单测、--benchmark-hotpath门禁,或维护者在运行中的应用中的具体观察);这些会演变成plan.md的测试计划。
  • Constraints & Invariants:实现绝不能破坏的东西,以约束而非设计的形式陈述(如"不得回退 256 kHz hotpath 门禁""Pro 专属功能,用BUILD_COMMERCIAL门控""不得引入新依赖")。
  • Open Questions:任何会阻碍自信规划的悬而未决问题,必须在/ss-plan前与维护者解决——错误假设会传播到后续所有阶段。

6.2plan.md—— HOW(阶段 2,/ss-plan

模板同样以引用块声明:

Phase 2 of 4 —— 讲 HOW。满足spec.md中每条需求的技术设计。写作前必须阅读相关doc/claude/子文档与真实代码——基于过时心智模型写出的 plan 比没有 plan 更糟。闸门:人工标记approved前不得启动/ss-tasks

plan.md的章节(templates/plan.md):

  • Approach:3–5 句话概括所选设计:建什么、插在哪里、为何选这个形态。
  • Affected subsystems & files:具体路径表格,列出每个待创建/修改的文件及一行职责;要求用 grep 确认触点真实存在。
  • Architecture & data flow:数据与控制如何流经改动,点名对象、signal/slot 与线程。
  • Hotpath & threading impact(必答):模板明确标注REQUIRED,即使答案是"无影响"也要显式写出,包括:是否触及 hotpath(FrameReader/CircularBuffer/FrameBuilder/ Dashboard 绘制 / span 快车道);是否有新的跨线程 signal/slot;是否给缓存的 hotpath 标志(m_operationModem_anyAsyncSink等)新增输入;时间戳所有权归属。
  • Data model & persistenceFrame.hKeys::新增(单一事实来源)、schema/写版本号、项目 JSON 形状、Sessions DB schema、旧别名回退与迁移方案。
  • API / SDK surface:新增或变更的 API handler(注册在CommandHandler::initializeHandlers())、EnumLabels.cpp、生成的 SDK、商业面用#ifdef BUILD_COMMERCIAL门控。
  • QML / UI:新组件、数据模型、ComboBox 恢复竞态防护、主题/玻璃表面、字体自动缩放。
  • Tradeoffs & alternatives considered:评审者可能做不同决策的点,用"决策 | 选项 | 选择与理由"表格前置呈现。
  • Risks & mitigations:可能回退或破坏什么、如何防御,包含common-mistakes.md中的静默破坏类别。
  • Test & verification plan:把每条验收标准映射为具体检查,区分"你能跑的单元测试"与"维护者跑、需要应用带 API server 起来的 pytest 套件",以及静态检查(code-verify.pyqt-cpp-reviewsanitize-commit.py)。

6.3tasks.md—— 有序检查清单(阶段 3,/ss-tasks

Phase 3 of 4 —— 有序清单。plan.md拆解为小、有序、可单独验证的单元——每个都是评审者能独立阅读的连贯 diff。/ss-implement自上而下执行并持续更新状态框。闸门:人工标记approved前不得启动/ss-implement

模板约定(templates/tasks.md):

  • 一个任务 = 一个聚焦、可评审的改动;若一个任务触及超过 3 个文件或需要一段话才能描述,就拆分它。
  • 每个任务块包含Files / Does / Verify / Deps四个字段;Verify通常是python scripts/code-verify.py --check <files>加上适用处的测试或回读;Deps列出必须先落地的任务 ID;任务间按"每步之后(概念上)树仍可编译"排序。
  • 末尾是Definition of Done整体闸门:所有验收标准达标并在spec.md勾选、code-verify.py对改动文件零新错误、qt-cpp-review通过、hotpath 相关则--benchmark-hotpath无回退、列出维护者应跑的 pytest、sanitize-commit.py通过、diff 严格等于"被要求的内容且仅此而已"、最后把spec.md状态置为done

七、真实示例走读:Spec 0007 —— Dashboard Freeze Mode

以 0007-dashboard-freeze 为例,可以看到三份文档如何在真实功能上落地。

spec.md完整展示了六个章节的用法:

  • Problem:来自 LabVIEW 的用户期望能"完成"一个仪表盘,但 Serial Studio 当时每个 widget 都永久显示桌面窗口的装饰(标题栏按钮、可选工具栏带、阴影),且布局始终可拖拽调整——即使启用手动布局与隐藏任务栏,结果仍像"塞满小窗口的窗口管理器"而非仪表盘。决定性约束:冻结状态必须随项目文件(.ssproj)旅行——工程师准备好的项目交给操作员打开时必须是冻结的,若冻结是每台机器的查看器设置,该功能就失去意义。
  • Goals / Non-Goals:Goal 是"单一 Freeze 开关把当前仪表盘变成无装饰面板""冻结的项目在任何有合法许可证的机器上打开即冻结""冻结时布局完全惰性,只保留 widget 内容交互";Non-Goal 明确排除输出控件外观定制、悬停显隐工具栏、隐藏任务栏、OS 级 kiosk 锁定、按 widget 粒度的冻结等,并说明冻结只防止新建弹窗。
  • Requirements:13 条编号需求,涵盖三个等效入口(任务栏按钮、Ctrl+Shift+F快捷键、主菜单项,R1)、隐藏标题栏/工具栏/阴影(R2,含 DataGrid 隐藏表头行的修订)、布局锁定(R3)、内容保持可交互(R4)、项目文件持久化(R5,Quick Plot 模式仅会话级)、解冻完全还原(R6)、Pro/Trial 门控(R7)、无许可证打开未冻结但标志不丢失(R8)、延迟激活后自动冻结无需重载(R9)、与任务栏可见性正交(R10)、被动冻结指示器(R11)、冻结时最大化的 widget 保持最大化并持久化(R12)、中央工具栏组件(R13,维护者批准的修订)。
  • Acceptance Criteria:7 条验收标准全部[x]勾选完成,每条标注验证方式(维护者观察、pytest 集成测试、--benchmark-hotpathCI 门禁)。
  • Constraints & Invariants:不得影响 hotpath(256 kHz 基准门禁);许可证门控的派生状态必须在激活变化时重派生(引用 2026 年 7 月 Plot3D 的教训);未知键容忍;冻结标志永不被 load/save 循环静默丢弃;无新依赖;持久化职责划分保持。
  • Open Questions:标注"全部于 2026-07-14 与维护者解决",记录冻结指示器、快捷键、最大化行为三个决议。

plan.md展示了 HOW 的落地细节:冻结标志作为ProjectModel::frozen+Keys::Frozen一等项目属性(镜像plotTimeRange模式),有效状态为只读的UI::Dashboard::frozen = ProjectModel::frozen && proWidgetsEnabled()且 notify 同时接到frozenChangedLemonSqueezy::activatedChanged(延迟激活免费重派生);输入锁定放在WindowManagerstartManualPress()首行早退——一个闸门同时关闭标题栏拖动、手动模式下未聚焦窗口的 body 拖动与边缘缩放;工具栏收敛为单一WidgetToolbar组件,过窄时横向滚动而非隐藏(删除每 widget 的hasToolbar命令式 resize 处理器)。

值得注意的是 plan 中的决策表:存储位置选 ProjectModel 一等键而非 layout blob 或 QSettings(后者机器级作用域恰是 spec 明令禁止的);有效状态所有者选 C++ Dashboard 属性而非每文件 QML 表达式(约 8 个 QML 消费者的单一事实来源);输入锁定选 WindowManager 早退而非 QML MouseArea 覆盖层(覆盖层会挡住 widget 内容交互,违反 R4)。

八、与仓库其他机制的组合方式

doc/claude/spec-driven.md 的 "How it composes with the rest of the repo" 一节明确了该工作流与既有机制的四条组合链路:

  • Hotpath/ss-plan要求对 hotpath/线程影响给出显式答案并引入ss-hotpath/ss-implement完整阅读 hotpath 文件并把--benchmark-hotpath结果转交维护者。
  • Verify/ss-implement每个任务跑code-verify --check,收尾时跑sanitize-commit.py(经ss-verify);交接前对 C++ diff 跑qt-cpp-review。这些脚本位于 scripts/(如 scripts/code-verify.py、scripts/sanitize-commit.py)。
  • Trust Contract:plan 的文件清单本身就是"车道"——清单之外的东西在对话中明确提出,绝不悄悄塞进 diff;绝不触碰工作树中的外来文件;未经每轮明确许可不提交任何内容;自评审("被要求了什么,且仅此而已")是 Definition of Done 的一部分。
  • Tests:验收标准映射为具体检查——tests/scripts/ 的 JS 单元测试 Agent 可直接运行,pytest集成/安全/性能套件(tests/integration/、tests/security/、tests/performance/)由维护者对运行中的应用执行。

九、何时使用、何时跳过

Spec-driven 是非平凡或多文件工作的默认路径(doc/claude/spec-driven.md),它在可操作层面落实了 CLAUDE.md 中"多文件改动前先规划""非平凡工作前先陈述计划"的既有规则。当一位理性评审者可能偏好不同方案时就用它:新驱动、新 widget、schema 变更、API 面、任何触及 hotpath 的改动。

真正琐碎的改动则明确跳过:错别字、单行修复、重命名、注释、文档微调。为一行改动强上四阶段仪式本身就是一种浪费。分界线靠判断力,规则同仓库一贯约定:改动小、显然正确、评审者不可能合理偏好其他方案时,直接做。

四阶段工作流还包含一个可选的Phase 0 探索(无闸门):在/ss-spec之前允许抛弃式原型(Node/Python scratchpad 仿真、对运行中应用localhost:7777的 API 实验、注定被否决的快速草图),无工件、无闸门、无审批,产物只是理解——任何值得保留的东西都会重述进spec.md,Phase 0 的任何内容都不进仓库。

闸门纪律是整套体系的核心:上一阶段未经人工批准,绝不进入下一阶段。Agent 写一个阶段、停下、呈交;维护者评审后退回或批准。若后续阶段暴露了前一阶段的错误,必须回头修订更早的文档并重新确认,而不是静默分叉——工件必须保持真实,过期的 spec 比没有更糟。

十、总结:一条可记忆的心智模型

doc/claude/spec-driven.md 的收尾给出了一行式心智模型:

/ss-spec就问题达成一致。/ss-plan就方案达成一致。/ss-tasks就步骤达成一致。/ss-implement执行、验证并证明它——每个阶段之间都有一道人工闸门。

对任何想为 Serial Studio 贡献非平凡功能的开发者,这套体系的价值在于:设计在代码存在之前就可评审、可否决权衡以决策形式前置呈现hotpath 与静默破坏类别得到每次必答的显式回应半成品功能用三个文件即可恢复spec 作为持久工件随代码同行、可被 PR 引用。若需深入了解工作流细节,可继续阅读 doc/claude/spec-driven.md、目录规范 doc/claude/specs/README.md、模板 templates/spec.md / templates/plan.md / templates/tasks.md,以及 0007-dashboard-freeze 这样的完整落地示例。

【免费下载链接】Serial-StudioOpen-source telemetry dashboard. Supports UART, BLE, MQTT, Modbus, CAN Bus and more.项目地址: https://gitcode.com/GitHub_Trending/se/Serial-Studio

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询