spec-kit Review 扩展实战:获取、离线安装、指令解读与实测效果

概要:spec-kit 的 review 扩展将实现完成后的 PR 自审拆分为 6 个专项审查指令和 1 个调度指令,通过钩子接入 /speckit.implement 之后的环节。该扩展无法通过 specify extension add review 直接安装,与网络是否可用无关。

内容范围:指令获取 → 指令安装(含 4 类报错及处理方法)→ 7 条指令逐条解读 → 使用方法 → 在预置缺陷的示例仓库上的实测结果 → 注意事项与 FAQ。

版本:spec-kit(specify CLI)1.0.7;review 扩展 v1.0.1(作者 ismaelJimenez,MIT 许可,2026-04-04 发布)。文中命令输出均为实测结果或已逐行对照源码核对;个别未经实测、依据源码推断的结论,在相应位置单独注明。

一、review 扩展概述

1.1 在 spec-kit 流程中的位置

spec-kit 的主流程为「宪章 → 需求 → 方案 → 任务 → 实现」。review 扩展不修改主流程,仅在 implement 之后注册一个可选钩子:实现阶段结束时,提示用户是否执行代码审查。

 /speckit.constitution → /speckit.specify → /speckit.plan → /speckit.tasks → /speckit.implement
                                                                                   │
                                                                     after_implement 钩子(可选)
                                                                                   ▼
 /speckit.review.run:读取配置 → 探测改动文件 → 选择适用的审查 → 派发 → 汇总
   ├─ code       始终执行
   ├─ comments   注释或文档有改动时执行
   ├─ tests      测试文件有改动时执行
   ├─ errors     异常处理有改动时执行
   ├─ types      新增或修改了类型时执行
   └─ simplify   其余审查通过后执行

1.2 来源与设计

扩展仓库为 github.com/ismaelJimenez/spec-kit-review。其 README 说明,该扩展参照 Anthropic 为 Claude Code 提供的 PR Review Toolkit 插件改写:每个审查维度对应一个专项 agent,由一个调度指令统一编排。不同之处在于,它将各 agent 的提示词封装为 spec-kit 扩展命令,因此 Claude、Copilot、Cursor 等 spec-kit 支持的 agent 均可使用;同时与 spec-kit 的 constitution.md 集成 —— code、tests、simplify 三条指令会读取项目宪章,作为审查依据的项目规范。

1.3 指令一览

指令 功能 是否修改代码
speckit.review.run 调度:探测改动文件、确定执行哪些审查、汇总为一份 PR Review Summary 取决于所派发的子审查
speckit.review.code 通用代码审查:项目规范符合度、缺陷、代码质量;按 0–100 置信度评分,仅报告 ≥80 的问题 否
speckit.review.comments 注释准确性、文档完整性、注释过时(comment rot) 否(提示词明确限定为仅提供反馈)
speckit.review.tests 测试覆盖质量:以行为覆盖而非行覆盖为标准,对关键缺口按 1–10 分评级 否
speckit.review.errors 异常处理:静默失败、过宽的 catch、缺乏依据的降级处理 否
speckit.review.types 类型设计:封装、不变量表达、不变量有用性、不变量强制,四项各按 1–10 分评级 否
speckit.review.simplify 在不改变行为的前提下简化代码 描述与正文不一致,见 4.7

二、指令获取

2.1 在扩展目录中检索

spec-kit 1.0.7 内置两个扩展目录(catalog),均从 GitHub 获取:

目录 地址 属性
default raw.githubusercontent.com/github/spec-kit/main/extensions/catalog.json 可安装(install_allowed: true)
community raw.githubusercontent.com/github/spec-kit/main/extensions/catalog.community.json 仅供检索,不可安装(install_allowed: false)

review 收录于 community 目录。条目内容如下(摘自 spec-kit 1.0.7 源码包自带的 extensions/catalog.community.json):

"review": {
  "name": "Review Extension",
  "id": "review",
  "author": "ismaelJimenez",
  "version": "1.0.1",
  "download_url": "https://github.com/ismaelJimenez/spec-kit-review/archive/refs/tags/v1.0.1.zip",
  "repository": "https://github.com/ismaelJimenez/spec-kit-review",
  "license": "MIT",
  "category": "code",
  ...
}

在可访问外网的环境中,也可通过 specify extension search review 或 specify extension info review 查询同样的信息。

2.2 community 目录中的扩展不能按名称安装

这一点最容易被忽视。在网络完全正常的环境中按名称安装,实测输出如下:

$ specify extension add review
Error: 'review' was found in the 'community' catalog, which is discovery-only — a search surface, not an install
source.

Discovery-only catalogs are intentionally not installable so unvetted extensions can't be pulled in without review.
Don't flip such a catalog to install_allowed. Instead, once you've vetted this extension:
  • install it directly from its archive URL:
      specify extension add review --from <archive-url>
  • or add it to a catalog you curate and control (install_allowed: true).

这是 spec-kit 有意设置的安全边界:社区扩展未经官方审核,使用者须自行审阅后显式指定来源进行安装。因此,无论网络是否可用,都需要先获取扩展的归档包。

2.3 获取归档包

在可访问 GitHub 的机器上下载该版本的 tag 归档:

# Linux / macOS / Git Bash
curl -L -o spec-kit-review-1.0.1.zip \
  https://github.com/ismaelJimenez/spec-kit-review/archive/refs/tags/v1.0.1.zip

# Windows PowerShell
Invoke-WebRequest -OutFile spec-kit-review-1.0.1.zip `
  https://github.com/ismaelJimenez/spec-kit-review/archive/refs/tags/v1.0.1.zip

解压后的顶层目录为 spec-kit-review-1.0.1/,结构如下(tests/、.github/ 与运行无关):

spec-kit-review-1.0.1/
├── extension.yml                  ← 扩展清单:命令、脚本、钩子、默认配置
├── config-template.yml            ← 安装时复制为 review-config.yml
├── commands/
│   ├── run.md  code.md  comments.md  tests.md  errors.md  types.md  simplify.md
├── scripts/
│   ├── bash/detect-changed-files.sh
│   └── powershell/detect-changed-files.ps1
├── tests/ (bats + pester)
├── README.md  CHANGELOG.md  LICENSE

安装前建议通读 commands/*.md:这 7 个文件即全部指令,本质上是提供给 AI agent 的提示词,不含可执行代码;唯一会被执行的是 scripts/ 下的改动文件探测脚本,该脚本只读取 git 状态。这些文件即 2.2 中 spec-kit 要求使用者审阅(vet)的内容。

三、指令安装

3.1 三种安装方式对比

方式 命令 在 review 1.0.1 + spec-kit 1.0.7 组合下是否可用
按名称从目录安装 specify extension add review 否。community 目录仅供检索(2.2)
从 URL 安装 specify extension add review --from <zip-url> 要求本机可访问 GitHub,且同样会触发 3.3 第 ④ 类报错(清单校验失败)。注:本行结论依据源码推断,未经实测 —— 1.0.7 中 URL 安装最终同样调用 install_from_directory,适用同一套清单校验
从本地目录安装 specify extension add --dev <解压后的目录> 是。支持离线安装,且可在安装前修改清单。推荐采用

3.2 推荐安装步骤(适用于无外网环境)

# 0) 在可访问外网的机器上下载 zip,复制到目标服务器,例如 ~/pkgs/
cd ~/pkgs
unzip -q spec-kit-review-1.0.1.zip          # 解压得到 spec-kit-review-1.0.1/

# 1) 修正清单中两个不符合命名规则的脚本名(原因见 3.3 第 ④ 类)
sed -i \
  -e 's/name: "detect-changed-files.sh"/name: "detect-changed-files-sh"/' \
  -e 's/name: "detect-changed-files.ps1"/name: "detect-changed-files-ps1"/' \
  spec-kit-review-1.0.1/extension.yml
grep -n 'detect-changed-files' spec-kit-review-1.0.1/extension.yml   # 确认 name 已修改、file 未改动

# 2) 切换到 spec-kit 项目根目录(包含 .specify/ 的目录)后安装
cd ~/project/xxx
specify extension add --dev ~/pkgs/spec-kit-review-1.0.1

# 3) 验证安装结果
specify extension list

第 1 步完成后,extension.yml 中的 provides.scripts 应如下所示(仅修改 name,file 路径保持不变):

  scripts:
    - name: "detect-changed-files-sh"
      file: "scripts/bash/detect-changed-files.sh"
      executable: true
    - name: "detect-changed-files-ps1"
      file: "scripts/powershell/detect-changed-files.ps1"
      executable: true

安装成功时的输出(节选,较长的描述行已截断):

✓ Extension installed successfully!

Review Extension (v1.0.1)
  Post-implementation comprehensive code review with specialized agents for code quality, comments, ...

Provided commands:
  • speckit.review.run - Comprehensive code review using specialized agents
  • speckit.review.code - General code quality review — project guideline compliance, bug detection, code quality
  • speckit.review.comments - Code comment accuracy verification, documentation completeness, comment rot detection
  • speckit.review.tests - Test coverage quality analysis — behavioral coverage, critical gap identification, ...
  • speckit.review.errors - Error handling review — silent failure detection, catch block analysis, error logging
  • speckit.review.types - Type design analysis — encapsulation, invariant expression, usefulness, and enforcement
  • speckit.review.simplify - Code simplification suggestions — clarity, unnecessary complexity, redundant ...

Config scaffolded:
  • .specify/extensions/review/review-config.yml

specify extension list 的输出如下(格式依据 1.0.7 源码 extensions/_commands.py 第 519–528 行):

Installed Extensions:

  ✓ Review Extension (v1.0.1)
     review
     Post-implementation comprehensive code review with specialized agents for ...
     Commands: 7 | Hooks: 1 | Priority: 10 | Status: Enabled

提示:--dev 安装采用复制而非软链接:扩展会被完整复制到项目的 .specify/extensions/review/ 目录。安装完成后,~/pkgs/spec-kit-review-1.0.1 可以删除。多个项目需分别安装,彼此独立。卸载命令为 specify extension remove review。

3.3 常见报错与处理

以下四类报错均在实际安装过程中出现过,按出现顺序列出。

① 查询扩展目录失败:Errno 99

$ specify extension add review
... <urlopen error [Errno 99] Cannot assign requested address> ...
Error: Could not query extension catalog ...

Errno 99(EADDRNOTAVAIL)表示建立连接时无法分配可用的本地地址。常见原因有两类:域名解析返回 IPv6 地址,但服务器未配置可用的 IPv6 地址或路由;或所在网段须经代理访问外网,而当前 shell 未设置 https_proxy。排查命令:

env | grep -i proxy                                        # 检查代理环境变量
getent ahosts raw.githubusercontent.com                    # 检查解析结果为 IPv4 还是 IPv6
curl -4 -sSI https://raw.githubusercontent.com | head -1   # 强制使用 IPv4 测试连通性
curl -6 -sSI https://raw.githubusercontent.com | head -1   # 强制使用 IPv6 测试连通性

需要注意:即使网络问题解决,该命令也只会转为 2.2 所示的 discovery-only 报错。因此对 review 扩展而言,无需在网络问题上投入过多时间,直接采用离线 --dev 安装即可。

② 长选项误写为单横杠

$ specify extension add -dev ./spec-kit-review-1.0.1
No such option: -d

specify 基于 Typer/Click 实现,长选项须使用双横杠 --dev。-dev 会被解析为短选项组合 -d -e -v,第一个短选项 -d 未定义,因此报错。

③ 向 --dev 传入 zip 文件

$ specify extension add --dev ./spec-kit-review-1.0.1.zip
Error: No extension.yml found in /.../spec-kit-review-1.0.1.zip

--dev 的参数必须是目录,且须为 extension.yml 所在的那一级。应先解压,再传入 spec-kit-review-1.0.1/(而非其上级目录)。

④ 清单校验失败:脚本名不符合命名规则

$ specify extension add --dev ./spec-kit-review-1.0.1
Validation Error: Invalid script name 'detect-changed-files.sh': must be lowercase alphanumeric with hyphens only

该报错属于版本兼容问题,而非操作错误。spec-kit 1.0.7 对扩展声明的脚本名和模板名执行严格校验,规则定义于 src/specify_cli/extensions/__init__.py 第 67 行:

VALID_EXTENSION_ARTIFACT_NAME_PATTERN = ^[a-z0-9-]+$     # 仅允许小写字母、数字和连字符,不允许点号

review 1.0.1 的清单中,两个脚本名带有 .sh / .ps1 后缀,不符合该规则。处理方法即 3.2 第 1 步的 sed 命令:将 name 中的点号替换为连字符。

同类问题此前已出现过一次:据 review 的 CHANGELOG,1.0.1 版本正是为修复一个同类校验问题而发布 —— Removed invalid alias speckit.review (two-segment name) … fixes Validation Error: Invalid alias on specify extension add。由此可见,spec-kit 的清单校验规则在持续收紧,社区扩展的适配存在滞后。在较新版本的 spec-kit 上安装较早发布的扩展时,应首先检查清单校验报错。

仅修改 name 不影响功能,原因是命令文件并不通过 name 引用脚本,而是在文件头部直接声明了脚本路径:

---
description: Comprehensive code review using specialized agents — ...
scripts:
  sh: scripts/bash/detect-changed-files.sh
  ps: scripts/powershell/detect-changed-files.ps1
---

安装时,spec-kit 根据项目的脚本类型(--script sh 或 ps)将正文中的 {SCRIPT} 占位符替换为对应路径。实测安装后生成的 skill 中,该占位符被替换为 .specify/extensions/review/scripts/bash/detect-changed-files.sh(sh 项目)或 .specify/extensions/review/scripts/powershell/detect-changed-files.ps1(ps 项目),与 name 无关。

使用 --from <zip-url> 安装时适用同一套清单校验,因此同样会报第 ④ 类错误,且安装过程中无法修改清单文件。这也是推荐采用 --dev 的原因之一。

3.4 安装后的项目结构

以 Claude Code 集成(specify init --integration claude)为例:

<项目根目录>/
├── .claude/skills/
│   ├── speckit-review-run/SKILL.md          ← 7 条指令,每条对应一个 skill
│   ├── speckit-review-code/SKILL.md
│   ├── speckit-review-comments/SKILL.md
│   ├── speckit-review-errors/SKILL.md
│   ├── speckit-review-simplify/SKILL.md
│   ├── speckit-review-tests/SKILL.md
│   └── speckit-review-types/SKILL.md
└── .specify/
    ├── extensions.yml                        ← 已安装扩展列表 + after_implement 钩子
    └── extensions/review/
        ├── extension.yml  commands/  scripts/ ...   ← 扩展文件(完整复制)
        └── review-config.yml                 ← 由 config-template.yml 生成,可修改

.specify/extensions.yml 中写入的钩子配置(实际内容):

installed:
- review
settings:
  auto_execute_hooks: true
hooks:
  after_implement:
  - extension: review
    command: speckit.review.run
    enabled: true
    optional: true
    priority: 10
    prompt: Run PR review on implemented changes?
    description: Comprehensive review after implementation
    condition: null

optional: true 表示 /speckit.implement 结束时会提示「Run PR review on implemented changes?」,由用户决定是否执行,不会强制运行。

四、指令解读

4.1 speckit.review.run:调度指令

该指令本身不执行审查,仅负责编排。按提示词原文,执行过程分为 8 步:

 1 读取配置      读取 .specify/extensions/review/review-config.yml 中的 agents 开关;
                 文件不存在时使用 extension.yml 中的 defaults
 2 确定范围      解析参数;显式指定的审查一定执行(优先于配置开关);
                 无参数时执行所有「已启用且适用」的审查
 3 可选维度      comments / tests / errors / types / code / simplify / all
 4 探测改动文件  必须执行 {SCRIPT} --json,不得以直接执行 git 命令代替
                 (用户已提供文件列表或范围时除外)
 5 选择审查      code 始终执行;tests 仅在测试文件有改动时执行;comments 仅在注释或文档有改动时执行;
                 errors 仅在异常处理有改动时执行;types 仅在新增或修改类型时执行;simplify 在审查通过后执行
 6 派发          默认串行执行;参数包含 parallel 时并行执行
 7 汇总          按 Critical / Important / Suggestions / Positive 分级
 8 输出行动计划  生成 PR Review Summary

参数说明:

参数 含义
(无参数) 执行所有已启用且适用的审查,串行
tests errors 仅执行这两项审查,不受配置开关限制
comments 仅执行注释审查
simplify 仅执行代码简化
all parallel 并行派发全部审查;耗时最短,但 token 消耗最集中

最终输出模板:

# PR Review Summary

## Critical Issues (X found)
- [agent-name]: Issue description [file:line]

## Important Issues (X found)
- [agent-name]: Issue description [file:line]

## Suggestions (X found)
- [agent-name]: Suggestion [file:line]

## Strengths
- What's well-done in this PR

## Recommended Action
1. Fix critical issues first
2. Address important issues
3. Consider suggestions
4. Re-run review after fixes

被配置禁用的审查会在汇总中注明,例如 simplify: skipped (disabled in config)。

4.2 speckit.review.code:通用代码审查

审查范围包括三方面:项目规范符合度(读取 .specify/memory/constitution.md、CLAUDE.md、.github/copilot-instructions.md 等)、缺陷检测(逻辑错误、空值处理、竞态条件、资源泄漏、安全、性能)、代码质量(重复代码、关键路径缺少异常处理、测试不足)。

其核心机制是置信度过滤。提示词定义的评分区间如下:

置信度 含义
0–25 很可能是误报,或问题在本次改动之前已存在
26–50 细枝末节,且项目规范未作要求
51–75 问题成立,但影响较小
76–90 需要关注的重要问题
91–100 严重缺陷,或明确违反项目规范

报告规则:仅报告置信度 ≥80 的问题,并分为 Critical(90–100) 与 Important(80–89) 两组。注意,提示词中评分区间的边界(76–90 / 91–100)与报告分组的边界(80–89 / 90–100)并不完全一致,此处按原文列出。

该指令以减少误报为设计取向:不存在 ≥80 的问题时,仅输出一句符合标准的简要结论。

4.3 speckit.review.comments:注释审查

检查维度共五项:事实准确性(函数签名、行为、边界条件是否与注释一致)、完整性(前置条件、副作用、错误条件)、长期价值(复述代码的注释应删除;解释「为什么」优于解释「做什么」)、误导性(歧义表述、过时引用、已完成的 TODO)、改进建议。

输出结构固定为五部分:Summary / Critical Issues / Improvement Opportunities / Recommended Removals / Positive Findings。

提示词中有明确约束:You analyze and provide feedback only. Do not modify code or comments directly. 即只提供建议,不修改文件。实测结果与此一致(见第六章)。

4.4 speckit.review.tests:测试覆盖审查

该指令关注行为覆盖而非行覆盖,重点检查:未测试的错误路径、边界条件、关键业务分支、缺失的反例,以及并发和异步场景。每条建议按 1–10 分评级:

分数 含义
9–10 可能导致数据丢失、安全问题或系统故障
7–8 可能引发用户可见错误的业务逻辑
5–6 可能造成困惑或轻微问题的边界情况
3–4 有助于完整性,非必需
1–2 可选

输出结构为:Summary、Critical Gaps(8–10 分,应补充)、Important Improvements(5–7 分)、Test Quality Issues(与实现细节耦合过紧、重构后易失效的脆弱测试)、Positive Observations。低于 5 分的建议在输出结构中没有对应分组。

4.5 speckit.review.errors:异常处理审查

该指令的要求在 7 条指令中最为严格。提示词开篇列出五条不可妥协的原则:

  1. 不允许静默失败
  2. 用户应获得可据以采取行动的错误信息
  3. 降级处理(fallback)必须显式且有充分理由
  4. catch 块必须捕获具体的异常类型
  5. mock 和伪实现只能出现在测试代码中

严重度分为三级:CRITICAL(静默失败、过宽的 catch)、HIGH(错误信息质量差、缺乏依据的降级处理)、MEDIUM(缺少上下文信息、捕获范围可进一步收窄)。每个问题固定输出 7 个字段:Location、Severity、Issue Description、Hidden Errors(该 catch 块可能掩盖的异常类型,逐一列出)、User Impact、Recommendation、Example(修改后的示例代码)。

4.6 speckit.review.types:类型设计审查

该指令先识别类型的不变量(数据一致性、合法的状态迁移、字段间约束、前置与后置条件),再从四个维度分别按 1–10 分评级:

维度 评估内容
Encapsulation(封装) 内部实现是否被充分隐藏;外部代码能否破坏不变量
Invariant Expression(不变量表达) 不变量能否通过类型结构清晰表达;能否在编译期得到保证
Invariant Usefulness(不变量有用性) 这些约束能否防止实际缺陷;是否过严或过松
Invariant Enforcement(不变量强制) 构造时是否校验;所有修改路径是否都维持不变量;能否构造出非法实例

其指导原则为 Types should make illegal states unrepresentable(通过类型设计使非法状态无法被表示)。重点识别的反模式包括:贫血模型、暴露可变的内部状态、仅靠文档约定不变量、构造边界缺少校验。

4.7 speckit.review.simplify:代码简化

基本原则是只改变实现方式,不改变功能。具体包括:减少嵌套、消除冗余、改进命名、删除复述代码的注释、禁止嵌套三元表达式、清晰性优先于简洁性;同时避免过度简化(不应为减少行数而写出难以调试的紧凑代码)。默认仅处理最近修改的代码。

注意:该指令的描述与正文不一致。 命令文件 commands/simplify.md 头部的 description 写明 Advisory only(仅提供建议),而正文第 61 行写的是 You operate autonomously and proactively, refining code immediately after it's written or modified without requiring explicit requests.(自主、主动地在代码编写或修改后立即进行优化)。实际行为取决于 agent 对两处指示的取舍,结果不确定。执行前应先提交或暂存(stash)当前改动,执行后通过 git diff 检查实际修改内容。

4.8 改动文件探测脚本 detect-changed-files

所有审查指令都必须通过该脚本确定审查范围(提示词要求不得以直接执行 git 命令代替),从而保证 7 条指令的审查范围一致。脚本有两种模式:

 判断条件:当前分支 ≠ 默认分支,且能确定远端默认分支
 (依次尝试 origin/HEAD、origin/main、origin/master)

 条件成立 → Mode A(特性分支模式)
     merge-base(origin/<默认分支>, HEAD)...HEAD 的差异
   + git diff --cached(已暂存的改动)
   + git diff(未暂存的改动)

 条件不成立 → Mode B(工作区模式)
     git diff --cached(已暂存的改动)
   + git diff(未暂存的改动)

 两种模式均去重,且只保留 A/C/M/R(新增/复制/修改/重命名)的文件;已删除的文件不纳入审查
退出码 含义
0 检测到改动文件
1 执行出错:未安装 git,或当前目录不是 git 仓库
2 未检测到改动,无需审查

实测 --json 输出(特性分支 001-order-discount,以本地 bare 仓库作为 origin):

{"branch":"001-order-discount","default_branch":"main","mode":"Feature branch diff (main...HEAD) + uncommitted changes","changed_files":["order.py","test_order.py"]}

以下两项边界行为为实测或分析所得,扩展文档中未作说明:

  • 未跟踪(untracked)的新文件不在审查范围内(实测)。在工作区新建未执行 git add 的文件 untracked_new.py,脚本输出中不包含该文件。新文件至少须先执行 git add。
  • Mode A 依赖远端分支 origin/main 或 origin/master,不使用本地的 main 分支。依据脚本逻辑,未配置 remote 的纯本地仓库会进入 Mode B,此时已提交到特性分支的改动不在审查范围内(此为对 bash 版的分析结论;PowerShell 版在该情况下直接报错退出,见 FAQ Q4)。

4.9 配置文件 review-config.yml

# .specify/extensions/review/review-config.yml
agents:
  code: true
  comments: true
  tests: true
  errors: true
  types: true      # 动态类型语言、自定义类型较少的项目可禁用
  simplify: true   # 若不希望代码被自动修改,可禁用(见 4.7)

配置开关仅作用于 speckit.review.run 的无参数执行。以下两种情况不受开关限制:直接调用子指令(如 /speckit.review.errors);调用 run 时通过参数显式指定(如 run types)。

五、使用方法

5.1 指令名称与所用 agent 的对应关系

Agent 安装形式 调用示例
Claude Code 安装为 skill,名称以连字符分隔 /speckit-review-run、/speckit-review-comments
其他 agent(Copilot、Cursor 等) 安装为斜杠命令,名称以点号分隔 /speckit.review.run、/speckit.review.comments

下文统一采用点号形式,Claude Code 用户请替换为连字符形式。

5.2 调用示例

/speckit.review.run                           # 提交 PR 前执行全部适用的审查(串行)
/speckit.review.run all parallel              # 并行执行全部审查,缩短耗时
/speckit.review.run tests errors              # 仅审查测试与异常处理
/speckit.review.errors                        # 单独执行某一维度,报告最为详尽
/speckit.review.comments 只看 src/io/ 目录     # 以自然语言限定审查范围
/speckit.review.code 只审已暂存的改动          # 同上;指定范围后不再调用探测脚本

最后两种写法之所以有效,是因为每条指令的提示词中都包含如下规定:If the user provided a file list or explicit instructions on how to retrieve files (e.g., only staged, only unstaged, a specific folder, etc.), follow those instructions directly.

5.3 推荐流程

 /speckit.implement
        │  钩子提示 "Run PR review on implemented changes?",选择 y
        ▼
 git add -A(使新文件纳入审查范围)
        ▼
 /speckit.review.run  →  PR Review Summary
        │
        ├─ Critical     必须修复
        ├─ Important    应当修复
        └─ Suggestions  视情况采纳
        ▼
 修复后仅重新执行相关维度,例如 /speckit.review.run errors tests
        ▼
 git commit  →  /speckit.review.simplify(可选,执行前须先提交)  →  提交 PR

实践要点:在提交 PR 之前执行审查;优先修复 Critical 级问题;修复后针对相关维度重新审查,避免每次都执行全部审查。

5.4 精简注释的实现方式

review 扩展没有专门用于删除注释的指令,但可以通过以下步骤实现:

  1. 执行 /speckit.review.comments。报告中的 Recommended Removals 部分即建议删除的注释清单,附行号和理由;该指令本身不修改文件。
  2. 人工审核清单,确定需要删除的注释。
  3. 由 agent 按审核后的清单执行删除;或执行 /speckit.review.simplify,其规则包含删除复述代码的注释,但该指令可能同时修改其他代码,见 4.7。

六、实测结果

6.1 测试设置

  • 环境:spec-kit 1.0.7,specify init --integration claude,按 3.2 所述步骤离线安装 review 1.0.1(已修正清单)。
  • 仓库:在 main 分支提交项目脚手架,推送到作为 origin 的本地 bare 仓库;新建特性分支 001-order-discount,提交下列两个文件。
  • 执行方式:在 Claude Code 中依据生成的 SKILL.md,分别执行 speckit-review-comments、speckit-review-errors、speckit-review-code 三条指令。为观察各项审查的原始输出,未经 run 汇总,且未执行 tests / types / simplify。
  • 项目宪章 constitution.md 保持模板状态,未填写规则,因此 code 审查依据的是通用 Python 最佳实践。

被审代码 order.py(左侧为行号,其中预置了缺陷):

 1  import json
 2
 3
 4  def load_config(path):
 5      # Load the config file                          ← 缺陷 5:复述函数名的冗余注释
 6      try:
 7          with open(path) as f:
 8              return json.load(f)
 9      except Exception:                              ← 缺陷 1:过宽的 catch,且静默返回 {}
10          return {}
11
12
13  def calc_discount(price, level):
14      """Return discounted price. level: 1=silver(5%), 2=gold(10%)."""   ← 缺陷 2:gold 实际为 15%;缺陷 3:未说明 level 3
15      # gold gets 15%                                ← 缺陷 4:位置错误,其后是 silver 分支
16      if level == 1:
17          return price * 0.95
18      else:
19          if level == 2:                             ← 缺陷 6:三层嵌套 if/else
20              return price * 0.85
21          else:
22              if level == 3:
23                  return price * 0.8
24              else:
25                  return price
26
27
28  class Order:
29      def __init__(self, items):
30          self.items = items  # list of (name, qty, price)
31          self.total = 0
32
33      def compute_total(self):
34          # loop over items                          ← 缺陷 5:冗余注释
35          t = 0
36          for i in range(len(self.items)):           ← 缺陷 7:range(len()) 遍历及硬编码下标
37              t = t + self.items[i][1] * self.items[i][2]
38          self.total = t
39          return t

test_order.py 仅包含两个用例:单件商品的总价计算、silver 等级折扣(缺陷 8:测试覆盖不足)。

6.2 结果汇总:8 处预置缺陷均被检出

# 预置缺陷 comments errors code
1 except Exception 静默返回 {}(:9-10) — CRITICAL Critical,置信度 95
2 docstring 称 gold 为 10%,代码实际为 15%(:14) Critical — Critical,置信度 91
3 docstring 未说明 level 3 Critical(与缺陷 2 合并报告) — —
4 # gold gets 15% 位于 silver 分支之前(:15) Critical(位置具有误导性) — —
5 两条复述代码的冗余注释(:5、:34) Recommended Removals,两条均列出 — —(低于 80 阈值,未报告)
6 三层嵌套 if/else(:16-25) — — Important,置信度 85,建议改用字典映射
7 range(len()) 遍历及硬编码下标(:36-37) — — Important,置信度 82,建议改用元组解包
8 测试仅覆盖 silver 等级和单件商品 — — Important,置信度 85,列出 6 类应补充的用例

此外,errors 在预置缺陷之外报告了两条 MEDIUM 级问题:calc_discount 未校验入参(负价格;未知等级静默返回原价),Order.__init__ 未校验元组结构。这两条属于更严格的防御性要求,是否采纳取决于项目的编码规范。

6.3 报告原文节选

以下均为英文原始输出,仅作截断,未作改写。

speckit.review.comments(节选)

**Summary**: Reviewed 2 changed files (order.py: 40 lines, test_order.py: 11 lines) for comment accuracy,
completeness, and long-term value. Found 2 critical inaccuracies, 2 improvement opportunities, and 2 comments
that should be removed.

**Critical Issues**
- Location: order.py:14
- Issue: Docstring states `1=silver(5%), 2=gold(10%)` but the actual code at order.py:19-20 applies 15%
  (0.85 multiplier) for level 2. The docstring also omits level 3 (20% discount) entirely.
- Suggestion: Rewrite to `"""Return discounted price. level: 1=silver(5%), 2=gold(15%), 3=platinum(20%).
  No discount for unrecognized levels."""`

- Location: order.py:15
- Issue: Comment `# gold gets 15%` sits on the line immediately before `if level == 1:` (the silver branch).
  A reader scanning line-by-line will believe gold logic follows, but the code handles silver first.
- Suggestion: Delete this inline comment and fold the information into the corrected docstring at order.py:14.

**Recommended Removals**
- Location: order.py:5
- Rationale: `# Load the config file` restates the function name `load_config` verbatim. ...
- Location: order.py:34
- Rationale: `# loop over items` describes the `for` loop on the very next line ... Pure noise that duplicates the code.

speckit.review.errors(节选)

**Location**: order.py:9-10
**Severity**: CRITICAL
**Issue Description**: `except Exception:` catches every possible exception type and silently returns `{}`.
This is functionally equivalent to an empty catch block. The caller receives an empty dict with no way to
distinguish "file was empty" from "file does not exist" from "file contains invalid JSON" from "permission
denied." There is no logging, no stderr output, and no re-raise.
**Hidden Errors**: FileNotFoundError, PermissionError, IsADirectoryError, json.JSONDecodeError,
UnicodeDecodeError, OSError, MemoryError, RecursionError, KeyboardInterrupt -- literally every Python
exception inheriting from Exception.
**User Impact**: A corrupted or missing config file causes the entire application to proceed with
default/empty configuration silently. ...
**Recommendation**: Catch only the specific exceptions that represent recoverable config-loading failures,
log the error with the file path, and either re-raise or return a clearly distinguishable sentinel.

    def load_config(path):
        try:
            with open(path) as f:
                return json.load(f)
        except FileNotFoundError:
            print(f"WARNING: config file not found: {path}", file=sys.stderr)
            return {}
        except (json.JSONDecodeError, PermissionError) as e:
            print(f"ERROR: cannot load config {path}: {e}", file=sys.stderr)
            raise

speckit.review.code(节选)

**Reviewing**: order.py (load_config, calc_discount, Order class), test_order.py (test_total,
test_discount_silver). Project constitution (.specify/memory/constitution.md) is a template with no
populated rules; review is against general Python best practices.

**Critical (90-100)**
- Confidence: 95 -- order.py:9-10 -- Broad `except Exception` silently swallows all errors and returns `{}`. ...
- Confidence: 91 -- order.py:14 -- Docstring says `2=gold(10%)` but the implementation at order.py:19-20
  applies a 0.85 multiplier (15% discount). ...

**Important (80-89)**
- Confidence: 85 -- order.py:16-25 -- `calc_discount` uses three levels of nested `if/else` for a simple
  level-to-multiplier mapping. ...
  - Fix: Use a dictionary lookup: `discounts = {1: 0.95, 2: 0.85, 3: 0.80}; return price * discounts.get(level, 1.0)`.
- Confidence: 85 -- test_order.py:1-11 -- Test coverage is minimal. Only one item in the order test, only
  silver level tested for discount. No tests for: empty order, multiple items, gold/platinum levels,
  unrecognized level fallback, negative prices, malformed item tuples. ...
- Confidence: 82 -- order.py:36-37 -- `compute_total` iterates via `range(len(self.items))` and indexes with
  `self.items[i][1]` and `self.items[i][2]`. This is non-idiomatic Python ...
  - Fix: `for name, qty, price in self.items: t += qty * price`.

6.4 分析与评价

方面 结果
检出率 8 处预置缺陷均被至少一条指令检出,报告的行号全部准确。
分工 各指令职责边界清晰:注释类问题主要由 comments 报告;异常处理问题由 errors 分析得最深入(逐一列出被掩盖的异常类型);code 覆盖其余缺陷和结构性问题。
重复报告 最严重的两个问题(过宽的 catch、docstring 与实现不符)被两条指令重复报告。单独执行子指令时需自行去重;通过 run 执行时由汇总步骤合并。
阈值过滤 code 的 ≥80 过滤规则生效:两条冗余注释未被其报告(由 comments 覆盖),报告中也没有无关紧要的风格类意见。
是否修改文件 三条指令执行完毕后,均未修改任何文件,与提示词约定一致。
事实性错误 errors 在 Hidden Errors 中列出了 KeyboardInterrupt,该结论有误:KeyboardInterrupt 继承自 BaseException 而非 Exception,不会被 except Exception 捕获。审查结论总体正确,但具体细节须人工核对。
成本 3 条子指令审查 2 个文件、约 50 行改动,共消耗约 2.75 万 token,耗时约 3.8 分钟。通过 run 执行时最多派发 6 项审查,改动规模越大,成本越高。
可复现性 以上为单次执行结果。LLM 输出具有随机性,重复执行时措辞、置信度数值以及是否报告 MEDIUM 级问题均可能不同。

七、注意事项与 FAQ

Q1:为什么 specify extension add review 安装失败?

community 目录仅供检索,按名称安装必然失败(见 2.2)。应离线下载 zip,解压并修正清单后,执行 specify extension add --dev <目录>(见 3.2)。

Q2:安装时报 Invalid script name 'detect-changed-files.sh',如何处理?

review 1.0.1 的清单不符合 spec-kit 1.0.7 的命名规则。将 extension.yml 中两个 name 值里的点号替换为连字符,file 保持不变(见 3.3 第 ④ 类)。扩展作者发布修复版本后,此步骤可省略。

Q3:审查未执行、结果为空或提示「No changes detected」,可能是什么原因?

可能原因有三:当前目录不是 git 仓库(脚本退出码为 1);改动均为未跟踪文件(须先执行 git add);改动已提交到特性分支,但仓库中不存在 origin/main 或 origin/master,脚本进入仅检查工作区的 Mode B(见 4.8)。

Q4:在 Windows 上执行 PowerShell 版探测脚本时直接报错退出,原因是什么?

在 Windows PowerShell 5.1 下实测:仓库中不存在 origin/main 时,detect-changed-files.ps1 在探测默认分支的步骤(git rev-parse --verify origin/main 2>$null)抛出 NativeCommandError,以退出码 1 终止。原因是脚本设置了 $ErrorActionPreference = 'Stop',而 PowerShell 5.1 会将原生命令写入 stderr 的内容包装为错误记录,2>$null 无法阻止这一行为。为仓库配置 origin 并使 origin/main 存在(通过 push 或 fetch)后,脚本恢复正常。bash 版本不受此问题影响。

Q5:token 消耗是否较大?

是。每项审查都会加载一份完整的提示词,并通读改动文件。建议:日常使用 run 的无参数形式(自动跳过不适用的维度),或只指定 1–2 个维度;all parallel 仅用于提交 PR 前的最终审查;动态类型语言项目可在配置中禁用 types。

Q6:审查指令是否会修改代码?

code、comments、tests、errors、types 五条指令不会修改代码。simplify 是否修改代码取决于 agent 对提示词中两处矛盾指示的取舍(见 4.7),执行前应先提交当前改动。

Q7:审查依据的项目规范来自哪里?

code、tests、simplify 会读取 .specify/memory/constitution.md、CLAUDE.md、.github/copilot-instructions.md。宪章为空模板时,审查依据退化为通用最佳实践(6.1 的测试即属此情况)。将团队编码规范写入宪章,可显著提升审查结果的针对性。

Q8:团队如何统一分发,避免每人手工修改清单?

有两种方式:将修正后的 spec-kit-review-1.0.1/ 目录放在内网共享位置,统一通过 add --dev 安装;或自建一个 install_allowed: true 的内部扩展目录,通过环境变量 SPECKIT_CATALOG_URL 或项目级 .specify/extension-catalogs.yml 引用。spec-kit 官方推荐后者,并明确不建议将 community 目录改为可安装。

八、总结

  • 功能定位:review 扩展由 1 个调度指令和 6 个专项审查指令组成,接入 implement 之后的环节,按 git 改动范围执行审查,输出分级的 PR Review Summary。
  • 安装:community 目录中的扩展不能按名称安装;在 spec-kit 1.0.7 下还须先修正清单中的两个脚本名。推荐的安装路径为:下载 zip → 解压 → 用 sed 修正 name → specify extension add --dev <目录>,支持离线环境。
  • 使用:Claude Code 中调用 /speckit-review-run,其他 agent 中调用 /speckit.review.run;支持指定维度、并行执行以及用自然语言限定范围。新文件须先执行 git add,远端须存在 origin/main。
  • 效果:实测 8 处预置缺陷全部检出,行号准确,三条审查指令均未修改文件;不足之处在于 token 消耗较大,且个别细节存在事实性错误。
  • 使用建议:在提交 PR 前执行,优先处理 Critical 级问题;报告中涉及的具体事实(如异常类型、语言机制)应经人工核对后再采纳。
posted @ 2026-09-30 13:21  起飞的乌龟  阅读(13)  评论(0)    收藏  举报