关于 specops
SpecOps 是面向 Agent 和开发者的规范驱动开发技能,要求先定义经认可且可验证的软件目标状态,再进行实现。它将规范、代码与验证放在同一功能分支和 PR 流程中。
主要功能
- 01实现前定义目标状态
- 02编写声明式且可验证的规范
- 03记录具有决策作用的项目原则
- 04按描述主题组织规范
- 05串联规范变更、实现与验证
适用场景
- 01规划 AI 辅助的功能实现
- 02让多个 Agent 对预期行为达成一致
- 03依据已认可的需求审查代码
- 04跟踪规范与软件之间的已知差距
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ jarvusinnovations/ specops --skill specops安装后在 Claude Code 中输入/specops确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/audit-spec-drift.mdparallel-execution-protocol.mdplans-protocol.mdspec-drift-auditor.mdscripts/specopsspecops.mjs详细介绍
规范驱动开发(SpecOps)
理念
规范声明软件期望达到的完整状态。实现遵循规范。所有工作都从更新规范开始。
这不是文档驱动开发(文档描述已构建的内容),而是规范驱动开发——规范描述应该存在什么,实现则与之保持一致。规范引领,代码跟随。
这为何重要
Agent 或开发者实现功能时,会做出数百个细微决策。没有规范,每个决定都只能靠猜测,可能符合也可能不符合用户意图。有了规范,这些决定就已经明确——实现者的工作是执行,而非发明。这对 AI 辅助开发尤其有力,因为多个 Agent 可能同时开发同一系统的不同部分。
核心循环
1. Spec change → propose what should be true
2. Accept → reviewer agrees on desired state
3. Implement → bring code into conformance
4. Verify → compare running software to spec
没有对应规范的代码属于未指定行为——它可能出于实际原因而存在,但没有任何保证。没有对应代码的规范是已知缺口——而在主分支上,已知缺口附带一份已提交的计划。既没有实现也没有计划的规范不是缺口,而是尚未完善的草稿;在它成形之前,它会留在草稿规划 PR 中(参见开发中的规范放在哪里)。
分支和 PR 围绕实现展开——绝不只围绕规范
不要创建仅包含规范或计划的 PR。 工作开始时,创建一个以即将交付的功能命名的分支和 PR,并以 docs(specs): 提交和计划文件作为起点,以便尽早评审契约(草稿 PR 也可以)。随后将实现提交推送到同一分支,最后提交收尾提交;只有计划完成后,PR 才会合并。评审者可以在同一处看到契约、一致性证据和计划验证,且排列顺序确保规范仍然引领工作。
这是 specops 项目中每个工作事项的默认流程。唯一可以独立创建规范 PR 的情况是:为一批设计仍在协商中的规范创建草稿规划 PR(而且它也会与整套计划一并合并)、受外部方约束的提案计划,以及规范差异大到会淹没实现差异的情况。如果这些情况都不适用,而你正准备创建一个未来不包含实现的 PR,请停下来:你即将创建第二个待办事项列表。完整生命周期请参见:references/plans-protocol.md § 功能分支。
如何编写规范
恰当的详细程度
规范声明必须满足的条件,而非规定如何实现。
恰当的程度——声明式状态 + 规则:
“每行显示:from_stop_name、to_stop_name、pathway_mode 标签、完成比例(已填字段数 / 适用字段数)。排序方式:未完成项优先,然后按 from_stop_name 的字母顺序排列。当一条 pathway 的 from_stop 和 to_stop 共享同一个 level_id 时,它就属于‘本楼层’。”
这段说明告诉实现者必须满足什么条件,而不规定如何实现。它可以测试——你可以查看屏幕并验证是否符合规范。
过于含糊——功能描述:
“任务列表按楼层对路径分组,并跟踪完成情况。”
阅读这段内容的 Agent 仍然需要做出数百个决定。要使用哪些字段?按什么顺序排序?缺失数据时怎么办?
过于详细——实现伪代码:
“查询 pathways WHERE from_stop.level_id == to_stop.level_id,LEFT JOIN field_notes,ORDER BY field_complete ASC,将每个结果渲染为一个
<li>,并……”
这相当于把代码写了两遍。实现一旦偏离,规范就会过时。
编码理念,而不只是列举规则
两个词,一个理念。 项目的理念是它的指导立场——它行事方式背后的原因(“我们优先支持离线使用”;“现场用户优先于办公室分析人员”)。你要把这个理念写成原则:一条条明确、果断表述的规则,每条都对某个权衡作出取舍。理念是整体;原则是其中一个单元。因此,“将理念编码进去”具体来说就是:把它的原则记录在实现者会阅读的地方。 在本技能中,“理念”指立场,“原则”指写下来的单元——principles.md 和规格说明中的 ## Principles 部分都用于存放原则。
回想一下这项技能存在的原因:实现者会做出数百个微小决策,而规格说明决定这些决策是否符合初衷。列举式规则只能涵盖你预想到的决策——你想到并写下来的情况。原则则能覆盖其余情况:它是一条生成式规则,可以解决任何未被列举涵盖的情况,就像作者本人会做的那样。
两者缺一不可:
- 列举式规则 — “先将不完整路径排在前面,再按 from_stop_name 的字母顺序排序。”解决一个特定情况。
- 原则 — “这是一款现场数据录入工具,用户会在交通站点途中用一只手在手机上操作。当显示或交互决策存在冲突时,应优先考虑边走边操作的调查员,而不是坐在办公桌前的分析人员。”解决列举式规则未能涵盖的所有情况——就像作者本人会做的那样。
只有果断明确的原则才值得写进规格说明:它必须对真实的权衡作出取舍,并排除其他选项。比较:
- 不是原则(陈词滥调——没有排除任何选项):“界面应该简洁、易用。”
- 是原则(果断明确——实现者可以据此行动):“优先显示带有数据新鲜度时间戳的过期数据,而不是因刷新而阻塞屏幕。没有信号的地下调查员必须始终能看到最近已知状态。”
检验方式与任何规格说明都一样:两个实现者读完后,能否对代码是否符合要求产生分歧?“易用”——能,所以毫无用处。“显示过期数据并标注时间,优于阻塞”——不能,所以可以执行。
原则应放在哪里——默认放在它所约束的最具体规格说明中。 只影响一个屏幕的原则,应放在该屏幕规格说明的 ## Principles 部分,紧挨着它支持的规则,让阅读该规格说明的实现者能实际看到它。只有真正适用于整个项目、且没有任何单个功能规格说明负责的原则,才放进 principles.md。如果某个局部原则后来开始约束其所属规格说明之外的决策,就将它提升到 principles.md,并在原处留下指引。要留意的具体触发信号是:同一个或类似的原则出现在第二份规格说明中——这种重复表明它已不再只属于某一份规格说明,应将其统一提取出来,并用引用替换两处副本,而不是任由两段近乎相同的表述逐渐产生偏差。这样可以让 principles.md 保持简短、重点明确,而不是沦为杂物堆;同时也让每条原则都贴近它所指导的工作。记录时不必为放置位置过度纠结:先把原则写进你正在编辑的规格说明中,如果它后来扩散到其他地方,再提升即可。
将相关项目原则向下引用到每份规格说明中。 提升会将原则向上归纳;这是反向的向下传递流程。Agent(以及人)经常只深入查看一两份规格说明,却从未打开 principles.md——因此,悄然影响某个屏幕的项目级原则,对负责该屏幕的人来说是不可见的。应对方法:在规格说明的 ## Principles 部分,列出对这份规格说明影响尤为显著的 principles.md 条目,并各用一行说明其在此处的适用方式,同时链接到完整表述。这样,即使实现者只阅读这一份规格说明,也能了解适用的原则,而不会遗漏。要有所取舍——只引用真正影响这份规格说明决策的原则,而不是罗列全部原则;链接每一条原则的规格说明,什么也说明不了。当你将某条局部原则提升到 principles.md 时,留下的指向就是这类引用之一。
规格说明应涵盖的内容
- 显示规则——显示哪些数据,以及在什么条件下显示
- 数据要求——数据来源(API、本地数据库、派生数据)
- 操作——用户可以做什么,以及每项操作会导致什么
- 导航——从此处可以前往哪里、从哪里来到此处
- 业务规则——计算、状态机、验证逻辑
- API 契约——请求/响应结构、身份验证、错误情况
- 原则——用于一致解决未明确规定的细节决策的关键规则——即写下来的理念(参见上文的将理念编码下来)
规格说明不应涵盖的内容
- 视觉设计——颜色、间距、字体。这些由线框图和主题常量决定。
- 窗口小部件/组件拆分——屏幕如何拆分为类。这属于实现决策。
- 测试用例——测试依据规格说明编写,但测试本身不是规格说明。
- 变量名称、文件路径——可随意更改的实现细节。
规格说明目录结构
根据规格说明描述的内容来组织,而不是根据编写时间:
specs/
├── README.md # Workflow docs, directory layout, format conventions
├── principles.md # Project-wide principles — the decisive rules (your philosophy, written down) that resolve unspecified decisions
├── architecture.md # Tech stack, project structure, foundational decisions
├── data-model.md # Schema, field definitions, relationships
├── api/ # One file per endpoint or endpoint group
│ ├── conventions.md # Auth, versioning, error envelope, content types
│ └── <endpoint>.md
├── screens/ # One file per screen/route
│ └── <screen-name>.md
└── behaviors/ # Cross-cutting rules that span multiple screens
└── <behavior>.md
principles.md——将项目理念写成原则:用于解决枚举规则未涵盖的细节决策的关键跨领域规则。它与 architecture.md(具体的技术和结构选择)不同——当两种合理的实现方案发生冲突时,原则体现的是用来作出取舍的价值判断。仅适用于一个屏幕或行为的原则应放在相应规格说明的 ## Principles 部分;principles.md 收录适用于整个项目的原则,而功能规格说明会在各自的 ## Principles 部分向下引用这些原则。
screens/——每个屏幕/路由对应一个文件。说明用户在该 URL 上能看到什么、能做什么。
behaviors/——跨越多个屏幕的规则。当屏幕规格说明提到“完成比例”时,完成行为规格说明会定义其计算方式。
api/——客户端与服务端之间的契约。双方都依照这些规格说明实现。
规格说明文件模板
屏幕规格说明
# Screen: <Name>
## Route
The path/URL for this screen.
## Data Requirements
What data this screen needs and where it comes from.
## Display Rules
Declarative description of what appears and under what conditions.
This is what a reviewer checks the implementation against.
## Actions
What the user can do and what each action causes.
## Navigation
Where you can go from here, where you came from.
## Principles (optional)
The decisive rules governing this screen — what to favor for any case the rules
above don't enumerate.
**Inherited** — project principles from `principles.md` that especially bite here:
- [Offline-first beats fresh](../principles.md#offline-first-beats-fresh) — this screen
must render last-known state instantly; treat the live refresh as a background nicety.
**Local** — principles owned by this screen (promote to `principles.md` if they spread):
- ...
Omit either subsection if empty. Reference only principles that genuinely shape this
screen's decisions — not the whole list.
行为规格说明
# Behavior: <Name>
## Rule
The invariant or rule, stated declaratively.
## Applies To
Which screens or components this behavior affects.
## Details
Edge cases, calculations, timing, error handling.
## Principles (optional)
Same two-part shape as the screen template: **Inherited** — linked `principles.md`
entries that especially govern this behavior, each with a one-line gloss of how it
applies; **Local** — the decisive trade-off behind this rule, if any (promote if it
spreads). Omit either subsection if empty.
API 规格说明
# API: <Name>
## Endpoint
Method, path, auth requirements.
## Request
Parameters, body shape with field types.
## Response
Success body shape with field types. Error cases.
## Notes
Caching, idempotency, offline implications.
## Principles (optional)
Same two-part shape as the screen template: **Inherited** — linked `principles.md`
entries that especially govern this endpoint, each with a one-line gloss; **Local** —
the decisive trade-off for this endpoint (e.g. what to favor when consistency and
latency conflict), promoted if it spreads. Omit either subsection if empty.
原则(principles.md)
# Principles
The project's philosophy, written down as principles. Each is decisive: it picks a
side of a real trade-off so an implementer can resolve an unspecified case the way
the author would.
## <Principle name>
The principle, stated as a rule that rules something out. Include the *why* — the
context that makes the trade-off land — so a future reader applies it correctly.
> Example: **Offline-first beats fresh.** This tool runs in stations with no signal.
> When freshness and availability conflict, always show last-known state with a
> timestamp rather than block on a network round-trip.
为每条原则设置简短且稳定的 ## <Name> 标题——该标题会成为锚点,功能规格说明可从自身的 ## Principles 部分链接到此处(principles.md#<name>)。引用只单向进行:规格说明只向上指向 principles.md。不要在 principles.md 中维护“受这些规格说明约束”的列表——这就像手工绘制的 DAG,一旦规格说明有所变更,就会过时。要查找某条原则适用于哪些内容,请搜索指向其锚点的链接。
任何屏幕、行为或 API 规格说明也可以包含可选的 ## Principles 部分,用于记录仅适用于该规格说明的原则——标准相同(具有决定性,能排除某些做法)。当某条原则开始影响该文件之外的决策时,就将其提升到 principles.md。
Agent 如何使用规格说明
实现功能或修复 Bug 时:
- 先阅读相关规格说明。 每个屏幕、端点和行为都有对应的规格说明文件。编写代码前先阅读。
- 规格说明回答“是什么”,而不是“怎么做”。 它说明会显示哪些数据、有哪些操作、适用哪些规则,但不会规定控件树或类层次结构。
- 如果规格说明含糊不清,就澄清规格说明——不要猜测后直接编码。提出规格说明修订建议。
- 如果规格说明有误,就修正规格说明——不要在代码中绕过问题。
- 完成后,按照规格说明检查工作——核对每条显示规则、每项操作和每个条件。
开始新功能时
先判断这项工作属于 哪种类型——这会影响计划是在现在、稍后还是与规格说明同步制定(参见何时(以及何时不)编写计划)。以下步骤是常见情况下的默认流程:在周边规格说明稳定的项目中实现一个范围明确的功能。
所有工作都在同一个分支和同一个围绕待发布功能的 PR 上完成:一开始就创建 PR,计划完成后一次性合并(完整流程参见references/plans-protocol.md § The feature branch):
- 从集成分支创建分支,按功能命名——不要按规格说明命名
- 先编写或更新规格说明文件,并在分支 HEAD 提交
docs(specs):提交 - 编写使代码符合规格说明的计划——包括范围、所实现的规格说明、依赖项和验证标准(对于这个范围明确的单功能场景,应同步起草规格说明变更和计划,并在开始构建前一并提交审核)
- 立即创建 PR,并将其设为草稿,标题以功能命名。此时 PR 中只有规格说明和计划;这正是目的——在代码尚不存在时,先在将承载代码的 PR 上审核契约
- 在同一分支上按规格说明实现
- 验证运行中的软件符合规格说明,然后在最后一次提交中完成计划——计划由此冻结,成为已构建内容的记录
- 将 PR 标记为可审核。审核者先将规格说明差异作为契约阅读,再对照契约检查实现,最后查看计划中的验证证据——一次审核,一次合并
绝不要创建一个最终只包含规格说明和计划的 PR(参见分支和 PR 应围绕实现展开)。例外情况——仍在设计中的一批工作的草稿规划 PR、提案计划,或会淹没实现差异的规格说明差异——均在此处列明。
开发中规范的存放位置:规划草稿 PR
保持 specs/ 树可审计的原则是:主分支上的每项规范都已实现,或附有已提交的计划。 遵循这一原则,规范审计才有意义——表格 1 中“已指定但未实现”的发现,要么是预期中的进展(已有计划;引用即可),要么是真正的违规情况。没有这一原则,审计器就无法区分团队正在推进的缺口和某人搁置的草稿,缺口表也会逐渐沦为噪声。
因此,期望状态仍在协商中的规范不会合并。它会存放在规划草稿 PR 中——该 PR 所在分支包含开发中的规范(最终也会包含其计划集);只有当最终确定的规范和实现这些规范的计划一同提交时,PR 才会从草稿转为正式 PR 并合并。PR 正文会列出倒计时事项:仍未解决的设计问题、需要修订的配套规范,以及需要编写的计划。
规划草稿 PR 为何优于在主分支上添加 status: draft 标记:
- 只有缺席才是明确无误的标记。 主分支上的草稿仍会污染 grep 结果和阅读上下文,而且实现者(或 Agent)进入
specs/时,没有可靠的习惯能确保他们在依据规范开发前先检查状态字段。 - 每个工具都得知道这个标记——漂移审计器、基于
grep的规范引用、计划中的specs:字段。缺席不需要任何人做额外处理。 - 评审对话本来就发生在评审所在的位置——也就是 PR 上,围绕差异进行讨论,而不是通过修改主分支上的半成品文件来讨论。
实际上,这一原则几乎完全由已实现的规范来满足,因为计划会完整合并(参见 references/plans-protocol.md § 功能分支)。主分支上的 planned 计划仅用于两种情况:即将处理完成的一批引导任务,以及提案计划。如果 plans/ 中除这两种情况外还积累了 planned 文件,这些工作就应该放到问题跟踪器中。
不要将规划草稿 PR 与普通功能 PR 混淆;普通功能 PR 也会尽早创建,最初仅包含规范和计划。功能 PR 围绕一项实现展开,并会包含该实现;规划草稿 PR 则包含一批设计仍在反复调整、尚无计划集的规范。当某项功能的规范已足够确定,可以开始规划时,就不需要规划草稿 PR——直接创建功能 PR 即可。
维护规范:定期将长期存在的规范分支变基到主分支上,确保最终合并顺利;每条设计线索保留一个规划草稿 PR(一批相关规范共用一个 PR;无关的设计线索则不要共用)。
请勿将其与提案计划混淆;提案计划处理的是下一阶段:合同已达成一致,但在外部参与方采取行动前无法实施。提案计划会合并——规范加上一个带 awaits: 的 blocked 计划——因为设计已敲定,需要将记录版本化并供他人共享;计划随规范一同提交,因此这一原则仍然成立。规划草稿 PR 处于达成一致之前:设计仍在反复调整,还没有计划,也没有任何东西可以维持这一原则——因此它完全不会进入主分支。两者可以相互转换:当草稿中的设计敲定,但构建受到外部条件限制时,就将其作为提案计划提交。
修复 bug 时
- 检查行为是否已有规范说明——如果有,规范就是正确的,代码才是错误的
- 如果行为没有规范说明,请判断:是否应更新规范以涵盖这种情况,还是修复足够明显,可以直接编写代码?
- 对于重要的修复,先更新规范,以便记录该修复
评审代码时
根据规范而非你自己对其应如何工作的想法来比较实现。规范就是验收标准。
始终:留意应写入规范的决策和原则
这是一项持续的职责,而不是一个有始有终的阶段。在进行任何工作时——实现、调试、审查,或只是与用户讨论问题——都要留意关键决策作出或原则得以明确的时刻(也就是项目理念凝结成可写下来的规则时)。这些时刻很容易被忽略,因为它们看起来像是在推进工作,而不像是在编写规范:
- 用户解释为什么想要以某种方式做某事,从而揭示了将指导未来决策的原则。
- 对话中确定了权衡取舍(“发生冲突时,始终优先考虑 X,而不是 Y”)。
- 遇到未明确规定的情况时,你选定了一种处理方式,而这意味着一条通用规则。
- 审查意见确立了整个代码库都应遵循的惯例。
- 出现了“我们始终会 / 永远不会……”之类的说法——这几乎总是某种原则的伪装。
- **你在第二份规范中写下了——或注意到——相同(或只是稍作改写)的原则。**规范之间的重复,是最明显的提升信号:这条原则已不再只属于某一份规范。别让两份副本各自演变、渐行渐远。将它提炼到
principles.md中,然后把两处副本都替换为指向该条目的## Principles引用(参见阐明理念,而不只是罗列规则)。要留意相似的原则,而不只是完全相同的表述——两份规范分别用不同措辞写着“优先考虑一线用户,而不是后台分析员”,说的其实是同一条原则。
注意到这类情况时,请停下来并明确指出:说明这项决策是什么,判断它属于一条明确规则还是一项原则,并准确提出应将其落实到何处——默认放在它所约束的最具体的规范中(某个屏幕、行为或 API 规范的规则部分,或其 ## Principles 部分);只有确实适用于整个项目时,才放到 principles.md 中(参见阐明理念,而不只是罗列规则)。随后,按照正常的规范优先流程,修改(或提议修改)相应规范,别让这项决策转瞬即逝。
标记的标准:**如果某项决策会影响未来的实现者如何处理某个细节选择,它就应该写入规范。**如果它只影响这一行代码,那就不必记录。
这为何至关重要:如果一项决策只存在于代码、提交说明或聊天记录中,那么一旦上下文窗口关闭,它就成了未明确规定的行为。下一个 Agent 会重新争论这项决策,而且可能得出不同结论,导致代码库逐渐偏离。正是这种警觉,让规范能够指导后续工作,而不只是描述现状。规范并非在功能启动时写好后就一成不变;它们会逐步积累项目已明确的判断,而其中大多数判断都是在处理其他事情的过程中作出的。
计划:连接规格与代码的工作 DAG
规格描述状态(哪些事情应当始终为真)。计划描述进展(接下来如何实现目标)。每项功能工作的每个部分都从 plans/ 中的计划文件开始,其中声明其范围、实现的规格、对其他计划的依赖,以及具体的验证标准。所有计划文件共同构成项目工作计划的微型 DAG。
计划具有时效性——合并后便冻结为历史记录。计划中的已合并 PR 链接和已完成的验证标准,共同构成项目的工作记忆,记录已构建的内容、实现方式以及延期的事项。
计划的 frontmatter:
---
status: planned # planned | in-progress | done | blocked | cancelled
depends: [other-plan-slug]
specs: # spec files in THIS repo that this plan implements
- specs/architecture.md
upstream-specs: # (optional) specs in OTHER repos this plan consumes
- other-repo:specs/behaviors/transactions.md
issues: [128]
pr: 42 # set at closeout
---
计划正文采用固定模板:范围、实现、方案、验证(关键的复选框列表——将“进行中”转变为“已完成”)、风险 / 未知事项、备注(在收尾时填写)、后续事项(在收尾时填写)。
完整协议——包括 frontmatter 架构、正文模板、状态生命周期、分支更新、收尾提交流程、后续事项分类(Issue / 延期至计划 / 作为……跟踪 / 无)以及延期吸收规则——见 references/plans-protocol.md。编写、实施或收尾计划前,请先阅读该文档。
**保持实现分支线性:**将集成分支变基到当前分支,而不是合并进来;重新运行受影响的验证,并确保收尾操作最后进行。请遵循分支更新规则,以了解仓库策略的优先级、共享分支协作、保留语义解决方案以及发布改写后的历史记录。
何时(以及何时不)编写计划
在 specops 项目中,plans/ DAG 就是规划系统。 不要用 Agent 内置的“计划模式”或临时规划草稿来替代它——这些内容会在轮次结束时消失,导致 DAG 没有记录已构建的内容或原因。如果你用草稿来梳理思路,最终产物仍必须落到计划文件中。尤其要警惕一种失败模式:起草一份临时计划,写着“编写规范 X,然后实现它”,接着照做——最后却既没有留下经过评审的规范变更,也没有留下计划。应将其拆开:规范变更走规范优先流程,执行这项工作的内容则写入计划文件。
何时编写计划,取决于用户正在做什么:
-
梳理一批规范——规划多个规范的目标状态,暂时不进行构建。不要边梳理边编写计划。 计划意味着行动;在目标状态尚未确定时,每个规范都对应一份计划只会造成反复改动,而且很少能合理划分工作。等这一批规范完成后,再退一步,提出一组计划,将工作划分为合理且按依赖关系排序的部分。合理的划分通常不会与规范文件一一对应。在目标状态确定期间,这一批内容应积累在草稿规划 PR 中,而不是主分支上——参见开发中的规范存放位置;待这一批规范及其计划集一并定稿后,再转换并合并该 PR。
-
在成熟项目中为一项范围明确的功能编写规范并进行构建——周边规范稳定,范围较小。同时编写规范变更及其计划: 一起编写规范更新和执行该更新的计划,提交两者供评审,并在两者获批后继续。
-
意图不明确——如果无法判断用户是在逐步梳理一批规范,还是正在编写一项要立即执行的规范,先询问,不要擅自决定:“我们是先梳理规范、之后再规划构建,还是现在就构建这一项?” 用户的回答将决定采用上述哪种模式。
即使是快速的一次性工作,也要留下计划。 因变更“很小”而想跳过计划,正是让 DAG 形同虚设的原因。范围明确的变更仍需有一份计划文件,并将状态冻结为 done——这份冻结记录(已合并的 PR + 已检查的验证结果)就是项目对已构建内容的工作记忆。跳过计划,就是用现在省下的几秒钟换取日后无记录的变更。(如果在撰写记录时,小变更已经过验证,也可以直接在收尾提交中将计划文件的状态设为 status: done——该文件仍会随同一个 PR 一起提交。)
执行计划 DAG
一批计划编写完成、经过评审并处于 planned 状态后,构建工作是单独且必须明确触发的步骤,不能并入同一轮。计划完成并不代表同意开始构建。 提出执行 DAG,并等待人工触发——触发语是 “drain the DAG”(或任何明确表示可以开始的等效说法);绝不能自行开始分派实现工作。
触发后,大规模执行多计划 DAG 的方式是:采用由依赖关系门控的工作波次,每项工作都由隔离工作树中的子 Agent 执行(每次派发都必须明确指定构建级模型,绝不能继承协调者使用的模型),并在波次之间设置评审/合并关卡:协调者计算就绪计划集合(specops next),为每个就绪计划从最新集成分支创建一个工作树,向每个工作树派发一个子 Agent 来实现 → 推送 → 开启 PR(绝不合并);随后评审每个 PR、直接修复问题、确认 CI,并进行合并——每次合并都会解锁下一波。完整协议——包括 Agent 简报、评审/合并关卡、并行冲突解决、每个 Agent 的实时依赖隔离,以及哪些计划(运维类或跨仓库计划)不得自动执行——见 references/parallel-execution-protocol.md。开始执行前请先阅读。
规范变更时,重新检查受影响的计划
规范编辑可能会让基于旧目标状态制定或正在执行的工作失去依据。每次修改规范时,都要检查实施该规范的计划,并提出更新计划。 通过在 frontmatter 的 specs: 中搜索你修改的文件来查找相关计划:
grep -l 'specs/path/to/changed.md' plans/*.md
对于每个匹配项:planned 计划可能需要调整范围、方法或验证方式;对于 in-progress 计划,应告知负责人目标已变更(不要悄悄修改他人正在实施的计划)。这与“先定规范”相呼应——规范变了,追随它的计划也要及时跟上。
查询计划 DAG
plans/README.md 有意不维护手绘 DAG 或状态表——只要有人忘了更新,它们很快就会过时。内置的 specops CLI 会按需查询权威的计划 frontmatter,并输出便于 Agent 使用的 TOON 格式:
计划
scripts/specops next [--include-in-progress] [--slugs-only] [--dir <path>]— 按就绪程度排列计划:先列出已就绪(依赖已满足、无待处理事项)的计划,再列出等待外部事项和受阻的计划,并优先显示能解除最多工作阻塞的项目。scripts/specops dag [--direction TB|LR|BT|RL] [--fence] [--include-cancelled] [--dir <path>]— 输出计划 DAG 的 Mermaid 图;节点按状态设置样式,外部阻塞项以虚线表示。
会话
scripts/specops hook install [--scope project|global] [--dir <path>] | hook status | hook uninstall [--scope project|global]— 管理 SessionStart hook,在每次 Agent 会话开始时加载此仓库的计划仪表板。
不带命令运行 scripts/specops,即可查看当前仓库的计划仪表板,其中包含就绪情况摘要、正在进行的计划、已就绪的计划、受阻的计划,以及最近完成的几个计划(如果仓库是 Git 检出,则从 Git 历史记录中读取完成日期)。卫生检查警告(悬空依赖项,或未记录任何阻塞原因的 status: blocked 计划)会输出到 stdout,方便 Agent 查看。
此 CLI 是基于文件优先工作流的轻量确定性层:它会跨所有计划文件计算就绪情况、排序、依赖关系图和警告——这些工作 Agent 无法可靠地仅凭目测完成。若要读取或编辑单个计划,请直接打开其文件;这里有意不提供 view/show 命令。
它以自包含 bundle 的形式随附于 scripts/specops.mjs(通过 scripts/specops shim 调用),运行需要 node ≥ 20,无需 npm install 或 node_modules,并通过 bun run build 从 src/cli/ 中的 TypeScript 重新构建。在仓库中运行一次 scripts/specops hook install,即可自动在每个 Agent 会话中加载计划仪表板。
在新项目中采用规范驱动开发
首先,将此技能引入目标项目,让这套方法随代码库一起流转。 在项目级别安装后,每位贡献者及其运行的每个 Agent 都会遵循相同的规范与计划实践,且打包的 specops CLI 无需任何配置,就能从仓库内部解析。请在项目根目录执行:
mkdir -p .claude && npx skills add JarvusInnovations/specops -y --skill specops --agent claude-code universal
这会将技能安装到 .agents/skills/specops/(Agent 中立的规范存储目录),并创建指向该目录的 .claude/skills/specops 符号链接,然后写入 skills-lock.json。请将这三项全部提交,以确保安装可复现。universal Agent 与 claude-code 一起使用时,会选择这种符号链接布局;单独为 claude-code 安装时,技能会直接复制到 .claude/skills/,不会有共享的 .agents/ 存储目录;mkdir -p .claude 可确保创建各 Agent 的符号链接,而不是跳过。之后若要添加其他 Agent(例如 Codex),请在命令中追加其名称重新运行,它就会链接到同一规范存储目录。只有在多个仓库中独自使用、无需按项目引入技能时,才优先使用 --global。
然后:
- 在项目根目录创建
specs/目录 - 编写
specs/README.md,说明工作流和目录结构 - 编写
specs/architecture.md,记录基础技术决策 - 编写
specs/principles.md,记录你已有的原则——将项目理念写成明确的“始终优先选择 X 而非 Y”的权衡取舍,以指导每位实现者。先写下目前已知的内容;随着决策逐步确定,持续完善(参见保持规范鲜活) - 对每个功能领域,在编写代码前创建相关规范文件
- 将 specops hook 添加到项目的 CLAUDE.md 中(参见下文CLAUDE.md hook)——这是始终加载的指导内容,可引导 Agent 使用该技能和计划协议
- 建立约定:凡是会改变行为的 PR,都应先提交
docs(specs):变更,再提交计划,然后是实现,最后是收尾工作;所有内容在同一分支上完成,并在计划完整后合并(参见 references/plans-protocol.md § 功能分支) - 设置规范漂移审计器(见下文)
- 设置计划协议(见下文)
CLAUDE.md hook
SKILL.md 和参考文档包含完整的方法论,但只有在技能触发时才会加载。项目的 CLAUDE.md 是每轮对话都会加载的唯一内容,因此应在这里纠正 specops 要覆盖的 Agent 默认倾向:不写规范就交付代码,以及进入内置的“计划模式”而不是编写计划文件。请将此区块保持精简——它的作用是引导这些行为,并将其他内容交给技能处理,而不是复述整套方法论。
请将此区块插入项目的 CLAUDE.md(将 <specops-skill-path> 调整为安装路径)。这是 CLAUDE.md 中唯一需要的 specops 内容;它已涵盖旧版安装步骤中单独说明的审计器和计划相关内容:
## Spec-driven development (specops)
This project uses spec-driven development. `specs/` is the source of truth for what
*should be true*; `plans/` is the work-in-flight DAG that bridges specs to merged code.
The **specops** skill carries the full methodology — invoke it (the skill triggers on
"spec", "plan", starting a feature, etc.) before writing specs, planning, or building.
- **Specs lead.** Before changing behavior, change the spec; bring code into conformance
after. Spec↔code drift is a bug, not debt. Specs merge implemented-or-planned; a spec
still being designed rides a draft planning PR, not the main branch.
- **Never a spec-only PR.** Open the branch and PR for the *feature*, start it with the
`docs(specs):` commits and the plan (draft PR is fine), add the implementation on the same
branch, and merge only when the plan is complete.
- **`plans/` is the planning system — not your built-in plan mode.** Every chunk of work
lands as a file in `plans/` that freezes to `done` as the durable record of what got
built. One feature branch carries spec → plan → code → closeout and merges with the plan
complete; the issue tracker, not `plans/`, is the backlog. Don't let an ephemeral plan
substitute for a plan file, and don't skip it for "small" changes. (Classic trap: an
ad-hoc plan of "write spec X, then build it" that ends with neither a reviewed spec nor a
plan file — split those into the two real artifacts.)
- **When to author a plan depends on intent:** mapping out a batch of specs → finish the
batch first, then propose a *set* of plans; speccing one bounded feature in a mature
project → draft the spec change and its plan in tandem; intent unclear → ask. The skill
details each mode.
- **A spec change ripples to its plans.** After editing a spec, review the plans that
implement it (`grep -l '<spec-path>' plans/*.md`) and offer to update them.
Query the DAG: `<specops-skill-path>/scripts/specops next` (what to work on next) and
`<specops-skill-path>/scripts/specops dag` (graph). Run `/audit-spec-drift` to compare
specs against the implementation.
配置规格漂移审计器
规格漂移审计器是一种专用 Agent,会将 specs/ 目录与实际实现进行详尽比对,并生成差距、未记录的实现和冲突的表格。要在项目中配置它:
-
复制 Agent 定义:将此技能的
references/spec-drift-auditor.md复制到项目的.claude/agents/spec-drift-auditor.md。根据项目结构自定义“方法论”各阶段,例如,更新阶段 3(“盘点实现”),列出代码库中的特定目录和关键文件(源代码目录、迁移路径、前端代码、基础设施文件等)。 -
复制命令定义:将此技能的
references/audit-spec-drift.md复制到项目的.claude/commands/audit-spec-drift.md。这样用户就能通过/audit-spec-drift斜杠命令启动审计器 Agent。 -
在 CLAUDE.md 中引用:
/audit-spec-drift指引已包含在「CLAUDE.md 钩子」部分,因此该部分就位后,无需另外添加内容。
参考文件位于:
references/spec-drift-auditor.md— Agent 定义(放入.claude/agents/)references/audit-spec-drift.md— 命令定义(放入.claude/commands/)
注意:审计器会检查计划文件中的 specs: 字段和 specs/ 目录树。它不会检查 upstream-specs:(根据设计,这些由其他仓库负责;请参阅计划协议)。
配置计划协议
计划协议为项目提供一种结构化的方式来跟踪进行中的工作,避免其逐渐失效。配置步骤如下:
- 在项目根目录创建
plans/目录。 - 编写
plans/README.md,简要说明计划是什么(动态还是状态),并指向 references/plans-protocol.md 查看完整规范。不要在其中维护 DAG 图或状态表,它们都会逐渐失效。specopsCLI 可按需重新生成该视图。 - 在项目的 CLAUDE.md 中记录协议 — 这已由「CLAUDE.md 钩子」部分涵盖,其中已说明“计划即规划系统”规则,并指向此技能以了解完整协议(状态、收尾提交、后续事项分类)。不要在 CLAUDE.md 中重复说明协议,保持内容精简,详细信息交由技能承载。
- 直接使用此技能中的
specopsCLI。scripts/specops是随此技能提供的独立工具包;从技能的安装目录运行它来操作项目的plans/— 无需复制、创建符号链接或引入代码,也无需运行npm install(它可在node ≥ 20上运行)。触发 specops 时,Claude 会自动解析技能路径;从项目根目录调用命令:<specops-skill-path>/scripts/specops next(或dag)。你也可以运行一次<specops-skill-path>/scripts/specops hook install,让仓库中的每个会话启动时都显示计划仪表板。 - 在团队中确立约定:新的工作内容从计划文件开始;合并前的最后一次提交将其状态改为
done;计划随工作一并合并,问题跟踪器则继续作为待办事项清单。收尾快速检查清单见 references/plans-protocol.md。
保持规范与时俱进
规范一旦偏离实际,就会逐渐失效。可以通过以下方式避免:
- 将更新规范纳入 PR 流程——如果代码改变了行为,规范也应该随之更新
- 定期对照运行中的软件审查规范
- 将规范与代码不一致视为 Bug,而不是技术债
- 让 Agent 在实现前阅读规范;如果规范有误,这会自然形成反馈闭环
- 在决策和原则确定时就及时记录下来(参见 始终:留意应纳入规范的决策和原则)——项目中大多数持久有效的判断都是在任务进行过程中确定的;只有将这些判断写入规范,而不是留在聊天记录中,规范才能保持与时俱进