文章

在 CI 中用规格检查器检查规格

规格检查器是一个程序,它检查规格里的结构错误,发现错误时以失败码退出。持续集成(CI,continuous integration)是对每一项提议变更的自动检查。持续集成与持续交付(CI/CD,continuous integration and continuous delivery)是运行这项检查、并让通过的变更保持可发布的流水线。规范驱动开发(SDD,spec-driven development)是在写代码之前写下规格,并把规格当作事实来源。产品需求文档(PRD,product requirements document)是陈述问题和范围的散文。在 SpecScore 里,需求(REQ)是功能内部一条有名字的规则,验收标准(AC,acceptance criterion)是可选的抽象条件,指向其中一条或多条规则。这项检查是命令行界面(CLI,command-line interface)命令 specscore spec lint,来自 specscore/specscore-cli(Apache-2.0)里的 CLI。EARS(Easy Approach to Requirements Syntax)是一条需求的句式。这个检查器检查标题、必需的节和引用。它不给英语打分。

最近更新:2026年11月4日

检查一份规格是什么意思

检查一份规格,和检查代码是同一类检查。一个确定性的程序读取文件并报告规则违规。它不判断产品是不是个好主意,也不把需求改写成更好的散文。验证器页面把那项结构检查和借助 AI 的人工复查分开。specscore spec lint 就是那项结构检查。

命令的说明写在 internal/cli/spec.go,位于 CLI 标签 v0.55.1,以及本仓库工作流所安装的 v0.39.1 标签。说明写的是:对照结构约定的违规来验证规格树。一次干净的运行打印 0 violations found 并以 0 退出。发现违规的运行为每条发现打印一行,并以 1 退出。这个退出码会让 CI 作业失败。无效参数以 2 退出。缺少 specscore.yaml 时以 3 退出,消息让你运行 specscore init。

规格检查器检查什么

规则属于 CLI,不是另一项云服务。生成的规则一览 docs/lint-rules.md 在标签 v0.55.1 列出 183 条规则。本网站的工作流安装的是更早的发行版 v0.39.1,因此只存在于更晚标签里的规则,并不是那个作业所运行的。本节所点名的规则,两个标签里都有。默认的 --severity 是 error。只有在传入 --severity warning 或 info 时才会打印警告,默认命令不会因此失败。规则一览把 dogfood-version-bump 标为警告,所以当工作流的钉扎落后于二进制时,默认命令不会失败。

必需的文件和节

规则 readme-exists(readme_exists.go)要求规格的每个目录里都有 README.md。规则 oq-section(oq_section.go)要求功能 README 包含 ## Open Questions 节。旧式标题 ## Outstanding Questions 是另一条发现,--fix 会就地改写该标题。下面示例里的消息「Open Questions section not found」,是从一个删掉了该节的功能 README 得到的发现。

索引行与子目录

规则 index-entries(index_entries.go)把功能索引和磁盘上的子目录相对照。未列入的子目录是违规,链接指向一个不存在的子目录的行也是违规。--fix 可以删掉那条幽灵行,并插入缺少的行。这是目录和索引的完整性。它不是去爬散文里的每一个 URL。

验收标准标题的形态

规则 ac-heading-format(ac_heading.go)适用于功能 README,也就是标题为 # Feature: 的文件。看起来像验收标准标题的一行,必须恰好是 ### AC: <id>,冒号后有一个空格,id 为 kebab-case。### AC: <id> (verifies ...) 这种标题也被接受。--fix 只修复空格。带大写字母或下划线的 id 会被报告,并留给人来处理。这条规则不要求 **Requirements:** 行,不为「graceful」或「fast」这类词打分,散文里出现 Given、When 或 Then 时也不警告。标准本身怎么写,见怎样写出 AI 代理能够验证的验收标准。

计划对这些标识符的引用

在点名了来源功能的计划上,plan_rules.go 读取该功能 README 里的 ### AC: 标题。规则 P-002 报告:任务的 **Verifies:** 值没有解析到这些标题之一的 <feature-slug>#ac:<ac-slug>、空的 **Verifies:** 行、缺失或无法识别的来源行,或者来源功能没有解析到一份功能 README。规则 P-001 报告:没有任何任务覆盖、并且没有列在 ## Deferred AC Coverage 之下的标题。以来源为构想的计划(**Source:** idea:<slug>)和带有 **Source:** none 的计划免于这些规则,处于终态处置状态的计划也同样免除。P-002 在规则一览里的一行文字是「valid dependency references」;那个文件里的检查器,就是刚才描述的 AC 引用检查。

一次通过的检查不是什么

同一条命令不判断一条需求是否解决了所陈述的问题,不判断一个名字是否说得通,也不判断两个功能是否在意义上互相矛盾。验证器页面把这些列在 CLI 检查器之外。它也不检查场景步骤的关键词。specscore rehearse 运行场景文件。本仓库的工作流运行 specscore spec lint,并不调用 rehearse。规则一览还点出更多类别——构想、决策、实体、属性、教训、议题,以及其余的计划规则——每条规则适用于它负责的文件。规则一览就是那份清单。本页不重述全部 183 条说明。

在 CI 中运行 specscore spec lint

命令从工作目录向上查找 specscore.yaml。没有这个文件时以 3 退出,并点名 specscore init。因此 CI 作业需要检出内容里有这份配置文件。scripts/install.sh 读取 SPECSCORE_VERSION,变量未设置时默认使用 latest。如果希望每次运行都是同一套规则,就钉住一个标签。

本仓库的检查是 dogfood.yml。它把 SPECSCORE_VERSION 设为 v0.39.1 来安装 CLI,然后不加额外标志运行 specscore spec lint,触发于 pull request 以及向 main 的 push。该进程以非零退出时,GitHub Actions 让这个步骤失败。下面的摘录保留了那些安装和检查步骤。该文件还设置 permissions: contents: read、一个并发组,以及一条说明为何钉扎不是 latest 的注释。

dogfood.yml 里的安装与检查步骤
name: Dogfood lint

on:
  push:
    branches: [main]
  pull_request:

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
      - name: Install specscore CLI (pinned)
        env:
          SPECSCORE_VERSION: v0.39.1
        run: |
          curl -fsSL https://specscore.md/install/get-cli | \
            SPECSCORE_INSTALL_DIR="$HOME/.local/bin" sh
          echo "$HOME/.local/bin" >> "$GITHUB_PATH"
          specscore --version
      - name: Lint spec tree
        run: specscore spec lint
失败报告(specscore 0.55.0,v0.39.1 的行形态相同)
features/apply-discount/README.md:0 [error] oq-section: Open Questions section not found
features/apply-discount/README.md:0 [error] index-entries: Child directory not listed in index: refunds
features/apply-discount/refunds:0 [error] readme-exists: README.md not found

3 violations found (3 errors)
干净的报告
0 violations found

每条发现都是 file:line [severity] rule: message。摘要是 N violations found,再加上括号里的计数,例如 (3 errors)。退出码是进程状态,不是报告里的一行。上面三行取自 specscore 0.55.0,当时一份功能的 Open Questions 节已被删除,索引也漏了一个空的子目录。它们和 CLI 页面展示的是同一份报告。--format 接受 text(默认)、json 或 yaml。--rules 和 --ignore 用来选择规则,不能同时使用。--fix 会改写带有修复器的发现,包括 Outstanding Questions 标题。dogfood 作业不传入 --fix。

不在 CI 中检查这种格式的工具

在这个 CLI 里,需求质量检查就是上面的结构检查。它不是给散文打分。其他规范驱动的工具公布的是不同的检查。下面各段只用那些项目自己的页面所说的内容。工具综述 把同样的页面记为 2026年10月30日读过,例外是印着 2026年9月28日的 Spec Kit 文档首页,以及印着 2026年8月4日的 Kiro 功能规格页。

GitHub Spec Kit 是一套代理工作流,写出 Markdown 产物。代理式 SDD 参考 把 /speckit.analyze 描述为跨规格、计划和任务的不一致报告,并且不编辑文件。你在代理里运行它。文档首页还点名社区扩展,其中包括一个叫 CI Guard 的扩展,它们加上合规门禁。那不是一条会检查 SpecScore 功能 README 的命令。

OpenSpec 确实公布了一项结构检查。openspec validate,记载于CLI 参考,检查 OpenSpec 的变更和规格结构,验证失败时以非零退出,参考里还包含一段 CI 作业可以运行的 shell 片段。那项检查是 OpenSpec 的形态,不是 ### AC: 标题,也不是 SpecScore 的索引。

Kiro 的功能规格页 把需求分析(Analyze Requirements)描述为 Kiro 内部、设计之前的一项检查,查找不一致、歧义、互相冲突的约束和缺口。它不是 dogfood.yml 里的命令。Kiro 所写的句式在EARS 需求语法。

BMAD Method 的 README 描述该方法的产物和代理工作流。它没有记载一条在 CI 里检查固定规格纲要的命令。Task Master 的 README 描述用 task-master parse-prd 把 PRD 解析成任务。它没有描述那个 PRD 的检查器。PRD 仍然可以是 SpecScore 功能的输入,而随后检查该功能文件的是 specscore spec lint。

常见问题

什么是规格检查器?

规格检查器读取规格文件并报告结构违规。specscore spec lint 就是针对 SpecScore 树的那条命令。在所选严重级别下什么都没发现时以 0 退出,发现违规时以 1 退出。

规格检查器会从措辞判断需求质量吗?

不会。ac-heading-format 检查的是 ### AC: 标题。它不为「graceful」或「fast」这类词打分,一条标准里出现 Given、When 或 Then 时也不警告。措辞是写作的工作。验证器页面把那项确定性检查和借助 AI 的人工复查分开。

怎样在 CI 里检查规格?

安装 CLI 时把 SPECSCORE_VERSION 设为一个发行标签,然后运行 specscore spec lint。检出内容需要一份 specscore.yaml。dogfood.yml 是一个能用的 GitHub Actions 示例。它钉住 v0.39.1。

失败的一次运行会打印什么?

每条发现一行,file:line [severity] rule: message,然后是类似 3 violations found (3 errors) 的摘要。进程以 1 退出。一棵干净的树打印 0 violations found 并以 0 退出。

其他规范驱动的工具会在 CI/CD 里验证规格吗?

OpenSpec 的 openspec validate 可以让 CI 作业失败,它检查的是 OpenSpec 自己的变更结构。Spec Kit 的 /speckit.analyze 在代理会话里运行。Kiro 的需求分析(Analyze Requirements)在 Kiro 内部运行。BMAD Method 和 Task Master 的 README 没有记载用于 CI 的格式检查器。SpecScore 的 dogfood 工作流在 SpecScore 树上运行 specscore spec lint。

在 CI 里检查规格。

发现翻译问题或有改进此页面的想法?