| name | ddev-spec |
| description | 在代码修改前需要编写 spec 文档且应优先用图表达边界、入口、流程和改动关系时使用(仅限代码改动场景,非项目级架构文档初始化) |
实现规格工作流
作用
在进行代码修改(新增、重构、修复)前,先出 spec 图,用图讲清改动边界、模块关系、接入点和主流程,再进入编码。本 skill 仅用于代码改动场景,项目的整体架构文档初始化请使用 ddev-arch。
边界声明:本 skill 仅产出设计文档,不得直接修改代码。所有代码修改必须在本 skill 产出 spec 文档并获得确认后,通过 ddev-plan 拆解执行计划,再由执行计划驱动编码实现。
如果仓库已存在 docs/architecture/,本 skill 必须先读取项目级架构规范,并让本次 spec 显式遵守其中的模块职责、允许依赖、状态所有权和允许修改范围。
文档表达原则
spec 文档默认采用”图优先,文辅佐”表达。只保留两类内容:
- 图: 这次改动要做什么
- 文: 每张图补充少量约束和验收口径
能画图说明的内容,不要改写成长段文字。文字只补图里不适合承载的约束、判定条件和验收口径。
不要专门写“明确不做什么”“范围外什么不做”这类反向清单。文档里没有写到的事项,默认就是这次改动不做,不需要额外声明。
如果某件事容易和本次改动混淆,不要写“这个不做”;直接补一张边界图、入口图或对比图,正向说明这次实际落地范围。
图怎么画、怎么命名、怎么渲染、怎么同步维护:
⚠️ 硬门禁:画图前必须先加载 ddev-diagram
在任何 ASCII 图动笔之前,必须执行 Skill("ddev-diagram") 加载绘制规范。加载完成前禁止写任何 ASCII 图。
spec 文档默认落到 docs/plans/YY-MM-DD_name/spec/<feature-name>.md。
默认优先用于嵌入式 C / 纯 C / Rust / HTML / Python 的改动,尤其是 BSP、驱动、协议、板级初始化和静态页面这类需要看边界的工作。
对于 C 项目(.c / .h),本阶段必须加载 ddev-c-pro 和 ddev-comment-gen skill,将其中的设计规范、命名规范、注释规范作为 spec 约束一并写入文档,不得留到编码阶段临场决定。对于其他语言项目,如果有对应的编码规范 skill,也应在本阶段加载并写入 spec 约束。
对于嵌入式 C / 纯 C 改动,这一步不只是”把模块关系画出来”,还要提前约束 AI 和实现者的结构选择,避免后续编码阶段直接滑向全局变量、长链 if/else 和职责混杂的大函数。对于其他语言,同样需要提前约束模块边界和职责划分。
联动顺序
- 如果仓库存在
docs/architecture/,先阅读 01_架构总览.md 和相关模块文档,确认本次改动是否在项目级架构规范允许范围内。
- 先做代码现状分析(强制),了解现有模块结构、公开接口和文件布局。
- 再做现有框架对齐分析(强制),确定设计如何嵌入现有框架——复用哪些扩展点、沿用哪些模式、新增哪些机制及理由。
- 先出本次 spec 图,并标出遵守了哪些项目级约束和框架对齐结果。
- 再交给
ddev-diagram,按规范手写 ASCII 图到 .md。
- 图确认后,可选进入
ddev-pc-test,判断本次修改是否可在 PC 上写测试 demo 直接验证;如果可以则产出测试用例文档和 demo 代码。若不需 PC 测试或不可测试,直接跳过本步骤。
- 若无需 PC 测试或跳过步骤 6,进入
ddev-detail 继续细化结构体和数据流;若步骤 6 已产出测试,仍可按需进入 detail 补充实现细节。
- 再进入
ddev-plan,把已确认设计拆成执行计划。
- 实现完成并拿到验证证据后,默认进入
ddev-gate,按图对照代码实现是否一致。若步骤 6 产出了测试 demo,ddev-gate 阶段必须跑通该 demo。
- 在 spec 设计过程中出现方向性修改、方案取舍时,将决策记录到 spec 文档本身或
implementation-notes.md 中;spec 最终定版时,写入设计依据摘要。
基本流程
- 先判断这次改动属于哪一类:
- 代码现状分析(强制):在画图之前,先从实际源码中了解现有模块结构、公开接口和文件布局。不完成此步骤不得开始画图。 详见下方”代码现状分析”章节。
- 现有框架对齐分析(强制):在了解代码现状后,分析本次设计应该如何嵌入现有框架——优先复用现有扩展点和模式,新建必须有充分理由。不完成此步骤不得开始画图。 详见下方”现有框架对齐分析”章节。
- 如果存在
docs/architecture/,先做项目级架构越界检查:
- 本次改动属于哪些模块
- 是否落在模块文档的”允许修改范围”内
- 是否新增或改变跨模块依赖
- 是否改变公共接口、外部行为或状态所有权
- 是否触发项目级”架构变更门禁”
- 先出图,后补文。
- 按
ddev-diagram 绘制规范手写所有 ASCII 图。
- 检查是否做到”看图即可理解主信息”。
- 在每张 ASCII 图上方标注图的用途和来源。
- 如果看不清,优先重画,不优先补长文。
代码现状分析(强制)
在画任何图之前,必须先从源码中理解”代码现在长什么样”。spec 图里画的模块边界、接口方向和文件路径必须与代码实际结构一致。
搜索范围
- 本次改动涉及的模块或目录的文件结构
- 相关模块的公开头文件(
*.h)和关键源文件
- 已有的公开接口、结构体和类型定义
- 模块之间的实际依赖关系和 include 链
搜索方法(优先级递减)
优先使用 CodeGraph 结构化查询:
codegraph_files 了解涉及的目录和文件结构
codegraph_context 理解模块的架构角色和关键符号
codegraph_explore 批量查看相关源码
CodeGraph 未初始化时回退方案:
Glob 查看目录结构
grep 搜索关键符号和 include 关系
Read 打开关键头文件确认接口
产出(嵌入 spec 图/文)
不要求单独文档,但 spec 文档中必须包含:
- 图中标注的模块名必须能对应到实际源码路径
- 图中标注的接口必须能在实际头文件中找到
- 如果 spec 计划修改模块边界或接口,必须在图中显式标注”现状 → 目标”的差异
强制约束
- 如果代码的实际模块边界与 spec 预期不符,必须在 spec 文档中显式标注,并说明是沿用现状还是计划调整
- 不得凭空画出不存在的模块或接口,除非明确标注为”新增”
- 如果因为 CodeGraph 未初始化且项目过大无法完整分析,至少分析本次改动直接涉及的目录和文件
现有框架对齐分析(强制)
在代码现状分析完成后、开始画图之前,必须回答一个核心问题:本次设计是在现有框架里扩展,还是在现有框架之外另起炉灶?
原则:默认扩展,例外新建。优先在现有模块、现有接口、现有模式上扩展;新建模块/接口/模式必须有充分理由。
分析步骤
- 识别现有扩展点:当前涉及的模块已提供了哪些扩展机制?
- 回调注册 / 钩子函数
- 命令表 / 消息分发表追加
- 枚举新增值
- 配置项追加
- 子类继承 / 接口实现
- 构建目标追加(
CMakeLists.txt、Makefile 中的源文件列表)
- 识别现有模式:同类功能在代码库中是怎么组织的?
- API 命名惯例(前缀、后缀、动词-名词结构)
- 错误处理模式(返回码类型、错误传播路径、集中/分层处理)
- 状态管理模式(上下文结构体、状态机、全局/局部状态归属)
- 内存管理惯例(谁分配谁释放、内存池/堆、引用计数)
- 文件组织方式(一对
.c/.h、模块目录结构、测试文件位置)
- 识别参考实现:找到仓库中与本次改动最相似的已有功能作为设计模板,标注其文件路径和关键符号。找不到时显式声明"本仓库无类似实现可参考"。
- 逐项对齐检查:对本次设计的每个关键决策,核对——
- 新增模块/文件是否可用现有目录扩展代替?
- 新增接口是否符合现有 API 命名和签名惯例?
- 新增数据结构是否复用了现有类型定义?
- 错误处理、状态管理、内存管理是否沿用了现有模式?
产出(嵌入 spec 文档)
- 复用清单:本次设计复用了哪些现有框架机制(扩展点、模式、类型、接口)
- 新建清单:本次设计新增了哪些框架机制,以及为什么不能复用现有机制(每条必须给出理由)
- 参考模板:参考了哪个已有实现作为模式模板,或声明"本仓库无类似实现可参考"及设计模式来源(外部标准/团队约定/从零设计)
强制约束
- 任何"全新模块/全新接口/全新模式"必须在 spec 中标注,并给出不能复用的理由
- 找不到参考实现时,必须显式声明并说明设计模式来源,不得沉默跳过
- 未完成框架对齐分析,不得开始画图
- 如果分析过程中发现现有框架无法支撑本次需求(如扩展点不足、模式不适用),必须在 spec 中显式标注为"框架缺口",并评估是否需要先做框架级重构
联动影响分析(强制)
在画图之前,必须搜索并识别本次改动需要联动修改的所有位置。不完成此步骤不得开始画图。
触发条件
当改动属于以下类别之一时,必须执行联动分析:
- 新增模块/驱动/平台适配
- 新增指令/消息类型
- 新增枚举值/配置项
- 新增回调/事件处理
- 新增源文件(
.c/.h)
搜索范围
⚠️ 硬门禁:联动分析前必须先读取 cross-cutting-patterns.md
进入联动搜索前,必须用 Read 读取 references/cross-cutting-patterns.md,加载完整的模式列表、搜索关键词和判断标准。禁止凭记忆或猜测选择搜索模式。
从已加载的 cross-cutting-patterns.md 中提取模式列表,按模式逐一搜索:
- 指令/消息分发表(
cmd_table, extra_cmd, msg_handler 等)
- 回调/钩子注册(
callback_register, event_handler, hook_list 等)
- 枚举↔字符串/枚举↔函数映射表
- 模块/驱动注册数组(
driver_list, module_init 等)
- 配置项初始化列表(
default_config, cfg_default 等)
- 条件编译开关链(
#ifdef FEATURE_* / #if defined(HAS_*))
- 构建/编译系统联动(
CMakeLists.txt, Makefile, Kconfig, *.mk)
参考文档:ddev-spec/references/cross-cutting-patterns.md,包含每种模式的详细搜索关键词、grep 正则和判断标准。
搜索方法(优先级递减)
优先使用 CodeGraph 结构化查询:
codegraph_search 搜索已知符号模式
codegraph_callers 逆向追踪:找到引用同名模块/同目录文件的所有调用者
grep 搜索模式关键字和正则(CodeGraph 未初始化时的回退)
产出(嵌入 spec 文档)
联动修改清单,每个联动点标注:
- 文件路径
- 符号名(函数/变量/宏/表名)
- 需要添加什么(具体条目)
- 不确定时标注 "待确认" 并给出怀疑理由
强制约束
- 如果搜索到明确的注册表/回调表/映射表,必须在 spec 中标注并说明本次是否需要修改
- 如果判断"不需要修改",必须给出理由(如"该表只覆盖 X 类型,本次新增的是 Y 类型")
- 不确定时标注 "待确认" 而非沉默忽略
- 如果所有搜索返回空(非标准命名项目),须显式输出"未发现标准化联动模式,需人工确认"并附搜索过程(用了哪些关键词、搜了哪些目录),不得直接跳过
编码设计约束前置
根据项目语言,在 spec 阶段将对应的编码规范约束前置写入 spec 文档,不得留到编码阶段临场决定。
C 项目(.c / .h)
必须先加载 ddev-c-pro skill,本阶段把以下约束写进 spec 文档:
- 模块运行状态默认封装到
context / session / handle 结构体,禁止把业务状态设计成全局变量
- 需要跨调用保存的状态,必须写清所有权、生命周期、谁能修改、谁能读取
- 主流程如果预计会出现多路分发或阶段迁移,优先在 spec 里判断是
switch、表驱动、状态机还是策略函数,不接受默认长链 if/else
- 配置、运行时状态、输入载荷、输出结果要分开建模,不要混在一个无语义大结构体里
- 需要共享的状态必须说明为什么不能下沉到局部变量、文件内私有状态或上下文对象
- 函数边界必须先按职责切开,避免后续出现”校验 + 解析 + 决策 + 执行”全塞进一个函数
- 参数超过 4–5 个的函数,spec 阶段就要规划用结构体封装
- 模块命名、类型命名(
_t 后缀)、API 前缀、错误码枚举必须按 ddev-c-pro 规范提前约定
- 公开 API 的 Doxygen 注释标准(
@brief / @param / @return)在 spec 文档中就要明确要求,参照 ddev-comment-gen skill
如果这些点在 spec 阶段说不清,说明还不该进入实现计划。
spec 文档必须回答的 C 设计问题
对于 C 项目,spec 文档至少要额外回答:
- 这次改动的核心状态属于哪个结构体,而不是属于哪个全局变量
- 状态迁移如何表达,是显式状态机、表驱动还是简单守卫式流程
- 哪些判断是真正的业务分支,哪些只是坏数据结构导致的补丁式分支
- 是否存在超过 4 个固定分支的分发点;如果有,准备采用什么替代长链
if/else
- 哪些接口是对外暴露的,哪些函数必须保持
static 私有
- 错误码和异常出口是集中处理还是分层返回
- 模块公开 API 命名前缀、类型
_t 后缀、宏命名规则是否已按 ddev-c-pro 规范约定
- Doxygen 注释是否已在 spec 约束中明确要求(参照
ddev-comment-gen skill)
图怎么选
- 架构规划: 组件图、边界图
- 接入点: 编号接入点图
- 功能流程: 流程图或活动图
- 修改对比: before / after 对照图
如果不确定,优先选“架构规划”,再补接入点和流程图。
最低验收
在实现开始前,文档至少要通过图讲清楚:
- 改什么
- 交付什么
- 接到哪里
- 主流程怎么走
- 前后差了什么
- 每张 ASCII 图是否按 ddev-diagram 规范绘制
- 联动修改清单:是否已列出所有本次改动需要同步修改的注册表/回调表/映射表/枚举入口/编译开关/构建文件;未发现标准化模式时是否已显式标注并附搜索过程
- 框架对齐清单:是否已列出复用的现有扩展点和模式;新增模块/接口/模式是否已给出不能复用的理由;是否已标注参考实现或声明无类似实现可参考
如果仓库存在 docs/architecture/,还必须讲清楚:
- 本次改动对应的项目级架构文档路径
- 本次改动涉及哪些模块,以及是否在各模块"允许修改范围"内
- 是否新增或改变跨模块依赖
- 是否改变公共接口、外部行为或状态所有权
- 是否触发架构变更门禁;如果触发,必须先更新
docs/architecture/ 再进入实现计划
如果是 C 项目,还必须能看出:
- 运行时状态是否已经收敛到明确的上下文对象
- 关键分支是否已经选定为守卫式返回、
switch、表驱动或状态机,而不是含糊留给实现时发挥
- 是否已经识别需要避免的全局变量、魔法状态值和职责过载函数
- 命名规范是否已按
ddev-c-pro skill 在 spec 约束中明确;Doxygen 注释要求是否已按 ddev-comment-gen skill 在 spec 约束中明确
对于其他语言项目,必须能看出模块边界、接口契约和关键流程分发策略。具体编码规范由对应语言的审查 skill 决定,不需要在 spec 中堆砌语言无关的编码规范。
自检
spec 文档完成后,必须逐项核对:
- 代码一致性:图中标注的模块/接口是否能在实际源码中找到对应文件/符号?如果有不存在的模块/接口,是否已标注为"新增"?
- 边界真实性:图中的模块边界和依赖方向是否与实际代码结构一致?如果不一致,是否已在 spec 中显式标注差异?
- 无凭空设计:是否存在源码中完全没有对应、也未标注为"新增"的模块名或接口名?
- 图优先:是否做到了"看图即可理解主信息"?文字是否只补充了约束和验收口径?
- 设计约束前置:C 项目的上下文收敛、分支策略、命名规范是否已在 spec 中明确?其他语言项目的模块边界和接口契约是否已明确?
- 联动覆盖:是否已搜索过项目中存在的注册表/回调表/映射表/条件编译链/构建文件?每个联动点是否已在 spec 中标注处理方式(需要修改/不需要修改及理由/待确认)?所有搜索返回空时是否已显式标注并附搜索过程?
- 框架对齐:本次设计是否优先复用了现有扩展点和模式?新增模块/接口/模式是否有充分理由并标注在 spec 中?是否标注了参考实现或声明了"无类似实现可参考"?
如有任一项不通过,必须在修复后再交给下游。