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

Canonical: https://specscore.md/zh-cn/articles/lint-specs-in-ci/

最近更新：2026年11月4日

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

## 检查一份规格是什么意思

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

命令的说明写在 [internal/cli/spec.go](https://github.com/specscore/specscore-cli/blob/v0.55.1/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](https://github.com/specscore/specscore-cli/blob/v0.55.1/docs/lint-rules.md) 在标签 v0.55.1 列出 183 条规则。本网站的工作流安装的是更早的发行版 v0.39.1，因此只存在于更晚标签里的规则，并不是那个作业所运行的。本节所点名的规则，两个标签里都有。默认的 `--severity` 是 `error`。只有在传入 `--severity warning` 或 `info` 时才会打印警告，默认命令不会因此失败。规则一览把 `dogfood-version-bump` 标为警告，所以当工作流的钉扎落后于二进制时，默认命令不会失败。

### 必需的文件和节

规则 `readme-exists`（[readme_exists.go](https://github.com/specscore/specscore-cli/blob/v0.55.1/pkg/lint/readme_exists.go)）要求规格的每个目录里都有 `README.md`。规则 `oq-section`（[oq_section.go](https://github.com/specscore/specscore-cli/blob/v0.55.1/pkg/lint/oq_section.go)）要求功能 README 包含 `## Open Questions` 节。旧式标题 `## Outstanding Questions` 是另一条发现，`--fix` 会就地改写该标题。下面示例里的消息「Open Questions section not found」，是从一个删掉了该节的功能 README 得到的发现。

### 索引行与子目录

规则 `index-entries`（[index_entries.go](https://github.com/specscore/specscore-cli/blob/v0.55.1/pkg/lint/index_entries.go)）把功能索引和磁盘上的子目录相对照。未列入的子目录是违规，链接指向一个不存在的子目录的行也是违规。`--fix` 可以删掉那条幽灵行，并插入缺少的行。这是目录和索引的完整性。它不是去爬散文里的每一个 URL。

### 验收标准标题的形态

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

### 计划对这些标识符的引用

在点名了来源功能的计划上，[plan_rules.go](https://github.com/specscore/specscore-cli/blob/v0.55.1/pkg/lint/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](https://github.com/specscore/specscore-cli/blob/v0.55.1/scripts/install.sh) 读取 `SPECSCORE_VERSION`，变量未设置时默认使用 `latest`。如果希望每次运行都是同一套规则，就钉住一个标签。

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

### dogfood.yml 里的安装与检查步骤

```yaml
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 的行形态相同）

```text
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)
```

### 干净的报告

```text
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 里，需求质量检查就是上面的结构检查。它不是给散文打分。其他规范驱动的工具公布的是不同的检查。下面各段只用那些项目自己的页面所说的内容。[工具综述](https://specscore.md/zh-cn/spec-driven-development/tools/) 把同样的页面记为 2026年10月30日读过，例外是印着 2026年9月28日的 Spec Kit 文档首页，以及印着 2026年8月4日的 Kiro 功能规格页。

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

[OpenSpec](https://github.com/Fission-AI/OpenSpec) 确实公布了一项结构检查。`openspec validate`，记载于[CLI 参考](https://openspec.dev/docs/cli)，检查 OpenSpec 的变更和规格结构，验证失败时以非零退出，参考里还包含一段 CI 作业可以运行的 shell 片段。那项检查是 OpenSpec 的形态，不是 `### AC:` 标题，也不是 SpecScore 的索引。

[Kiro 的功能规格页](https://kiro.dev/docs/specs/feature-specs/) 把需求分析（Analyze Requirements）描述为 Kiro 内部、设计之前的一项检查，查找不一致、歧义、互相冲突的约束和缺口。它不是 `dogfood.yml` 里的命令。Kiro 所写的句式在[EARS 需求语法](https://specscore.md/zh-cn/articles/ears-requirements/)。

[BMAD Method](https://github.com/bmad-code-org/BMAD-METHOD) 的 README 描述该方法的产物和代理工作流。它没有记载一条在 CI 里检查固定规格纲要的命令。[Task Master](https://github.com/eyaltoledano/claude-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](https://github.com/specscore/specscore/blob/main/.github/workflows/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`。

## 来源

CLI 行为已于 2026年11月4日对照 specscore-cli 标签 v0.55.1 和 v0.39.1 检查。其他项目的页面就是下面链接的那些；工具综述把它们记为 2026年10月30日读过，页面自己印有日期的除外。

- [specscore/specscore-cli](https://github.com/specscore/specscore-cli)
- [specscore-cli — Apache-2.0 许可证](https://github.com/specscore/specscore-cli/blob/main/LICENSE)
- [specscore/specscore](https://github.com/specscore/specscore)
- [specscore-cli v0.55.1 — lint 规则一览（183 条规则）](https://github.com/specscore/specscore-cli/blob/v0.55.1/docs/lint-rules.md)
- [specscore/specscore — dogfood.yml（CLI v0.39.1）](https://github.com/specscore/specscore/blob/main/.github/workflows/dogfood.yml)
- [specscore-cli — install.sh（SPECSCORE_VERSION）](https://github.com/specscore/specscore-cli/blob/v0.55.1/scripts/install.sh)
- [specscore-cli v0.55.1 — readme-exists](https://github.com/specscore/specscore-cli/blob/v0.55.1/pkg/lint/readme_exists.go)
- [specscore-cli v0.55.1 — oq-section](https://github.com/specscore/specscore-cli/blob/v0.55.1/pkg/lint/oq_section.go)
- [specscore-cli v0.55.1 — index-entries](https://github.com/specscore/specscore-cli/blob/v0.55.1/pkg/lint/index_entries.go)
- [specscore-cli v0.55.1 — ac-heading-format](https://github.com/specscore/specscore-cli/blob/v0.55.1/pkg/lint/ac_heading.go)
- [specscore-cli v0.55.1 — 计划规则 P-001 和 P-002](https://github.com/specscore/specscore-cli/blob/v0.55.1/pkg/lint/plan_rules.go)
- [SpecScore 验证什么](https://specscore.md/zh-cn/validators/)
- [怎样写出 AI 代理能够验证的验收标准](https://specscore.md/zh-cn/articles/acceptance-criteria/)
- [EARS 需求语法详解与示例](https://specscore.md/zh-cn/articles/ears-requirements/)
- [GitHub Spec Kit 文档（页面日期 2026年9月28日）](https://github.github.io/spec-kit/)
- [GitHub Spec Kit — 代理式 SDD 参考（/speckit.analyze）](https://github.github.io/spec-kit/reference/agentic-sdd.html)
- [OpenSpec CLI 参考 — openspec validate](https://openspec.dev/docs/cli)
- [Fission-AI/OpenSpec](https://github.com/Fission-AI/OpenSpec)
- [Kiro — 功能规格（更新于 2026年8月4日）](https://kiro.dev/docs/specs/feature-specs/)
- [bmad-code-org/BMAD-METHOD](https://github.com/bmad-code-org/BMAD-METHOD)
- [eyaltoledano/claude-task-master](https://github.com/eyaltoledano/claude-task-master)
- [规范驱动开发工具](https://specscore.md/zh-cn/spec-driven-development/tools/)

## 相关

- [用 Claude Code 和 Cursor 做规范驱动开发](https://specscore.md/zh-cn/articles/claude-code-specs/)
- [面向 AI 编程的 Markdown PRD 模板](https://specscore.md/zh-cn/articles/feature-spec-template/)
- [怎样写出 AI 代理能够验证的验收标准](https://specscore.md/zh-cn/articles/acceptance-criteria/)
- [EARS 需求语法详解与示例](https://specscore.md/zh-cn/articles/ears-requirements/)
- [SpecScore 验证什么](https://specscore.md/zh-cn/validators/)
- [CLI](https://specscore.md/zh-cn/cli/)
- [安装 CLI](https://specscore.md/zh-cn/cli/install/)
- [规范驱动开发](https://specscore.md/zh-cn/spec-driven-development/)
- [规范驱动开发工具](https://specscore.md/zh-cn/spec-driven-development/tools/)
- [功能规格](https://specscore.md/feature-specification)
- [验收标准规格](https://specscore.md/acceptance-criteria-specification)
