关于 skill-code-review
该 Skill 通过包含 15 个状态的 FSM 编排基于 git diff 的代码审查,调度专业审查器并给出 GO、CONDITIONAL 或 NO-GO 结论。它面向需要确定性去重、发布就绪门槛和持久化报告的代码审查流程。
主要功能
- 01通过 15 状态 FSM 编排审查
- 02分批调度专业审查器
- 03确定性合并重复发现
- 04综合八项发布就绪门槛
- 05生成 Markdown、JSON 与清单报告
- 06跟踪各状态的验证事件
适用场景
- 01审查不同 git 版本间的变更
- 02协调并行的专业审查任务
- 03依据明确门槛评估发布就绪度
- 04通过保存的报告和事件审计审查运行
MCP 相关
该 Skill 会引导注册 MCP 服务与客户端,并通过 `fsm.*` MCP 工具族驱动审查。它使用 FSM 工具启动运行、获取简报并提交工作者输出。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ ctxr-dev/ skill-code-review --skill skill-code-review安装后在 Claude Code 中输入/skill-code-review确认已加载。
详细介绍
skill-code-review
一个包含 15 个状态的 FSM,可对 git diff 执行代码审查并给出 GO /
CONDITIONAL / NO-GO 结论,具备确定性去重、8 道门禁的发布就绪度综合评估,以及持久化的磁盘运行目录
(report.md + report.json + manifest.json)。
引导(首先执行)
在开展任何审查工作之前,请按照
@.ctxr-fsm/memory/bootstrap.md 中的说明,确保已安装
ctxr-fsm、已初始化项目、已向此客户端注册 MCP 服务,并且监督进程正在运行。
引导流程具有幂等性,在预热路径上速度很快(监督进程和 MCP 服务已运行时约需 1.5–1.8 秒)。
如果缺少该软件包,请先询问用户,然后再运行安装命令。 在聊天中逐字打印拟执行的命令(即引导表格中的确切
uv add 'ctxr-fsm[all]' / pipx install 'ctxr-fsm[all]' 行),并要求用户明确同意后再继续。不要自动安装。不要串联多次安装尝试。这是原则 1(需求预检查,询问是否满足)的软件包缺失分支,应用于技能启动。
然后为每个项目注册此技能的规范和内联处理程序一次:
uv run python -m code_review.install
安装程序会输出一个简短的 JSON 信封,总结结果:
{
"db_path": ".ctxr-fsm/fsm.db",
"handlers_registered": 9,
"spec_created": true,
"spec_id": "code-reviewer",
"spec_version": 1
}
信封中的路径相对于项目根目录,因此该制品在推送到 git 或在不同机器之间移动后仍能保留。
当规范正文未发生变化时,重新运行安装程序不会产生任何操作(spec_created 将变为 false;沿用相同版本)。内联处理程序始终会重新注册,以便新的 Python 进程能够加载它们。
运行审查
引导流程完成且规范已注册后,通过 fsm.* MCP 工具系列运行一次审查:
-
启动运行。 调用
fsm.start_run(spec_id="code-reviewer", args={"base": "<sha>", "head": "<sha>"})。 根据需要在args下添加可选字段:full(bool)、scope-dir、scope-lang、scope-framework、scope-reviewer、scope-severity、scope-gate、max-reviewers、format(markdown|json|auto)。记录返回的run_id。 -
循环处理。 重复调用
fsm.get_brief(run_id),并根据 返回的 brief 作出响应:-
终态 brief。 从运行的最后状态读取
verdict+run_dir_path。 原样打印<run_dir_path>/report.md的内容。至此完成。 -
工作器 brief(
brief.has_worker == true)。派发一个 子 Agent,设置prompt = brief.worker.prompt_template和inputs = brief.inputs。子 Agent 返回的结构化 JSON 即为工作器输出。调用fsm.commit_outputs(run_id, outputs=<sub-agent-response>, signature=<cosignature>)。 继续循环。 -
循环 brief(
brief.has_loop == true)。派发方式与工作器 brief 相同,brief.iteration_n表示当前迭代索引。提交本次迭代的输出;引擎 决定是继续推进,还是发起下一次迭代。完成所有迭代——绝不要提前结束循环。 引擎发出循环 brief 时, 它要求你在每次提交后继续调用
fsm.get_brief(run_id),直到返回其他状态的 brief。循环 是否终止由引擎决定(依据工作器的loop_done标志和规划器的total_batches)。一次提交即一次迭代;如果有 N 个批次,就必须完成 N 次迭代。第一个循环 brief 的
iteration_n = 1。提交第 1 次迭代的输出后, 引擎会重新进入同一状态,设置iteration_n = 2并返回新的 brief;继续运行 循环,直到fsm.get_brief返回state_id不再是dispatch_specialists的 brief。编排器绝不能根据自己的计数器 退出派发循环;只有引擎知道规划器的批次何时全部处理完毕。此 bug 的表现:最终的
report.md中,专家显示status: fail和skip_reason: "no per-leaf output written"或"no output written for shard <n>",尽管编排器认为每个派发的子 Agent 都已成功。原因:编排器提交第 1 次迭代的输出后,没有继续轮询下一个 brief, 而是直接越过了dispatch_specialists(例如直接调用merge_specialist_outputs)。因此,合并器在loop_iters中只看到第一个批次的单元,为所有尚未派发的单元生成失败行, 运行最终以 NO-GO 结束,且大多数审查者都被默默标记为失败。现在,运行器会在这种情况下直接抛出DispatchLoopExitedEarlyError(而不是 默默生成降级报告),让故障作为验证后的错误显现。 -
内联 brief。 你绝不会看到它们。内联状态 (
risk_tier_triage、activate_leaves、collect_findings、verify_coverage、synthesize_release_readiness、write_run_directory、emit_stdout、short_circuit_exit、stage_a_empty)会在 ctxr-fsm 内由服务端推进。工作器提交后返回的下一个 brief,可能已经是一个或多个内联步骤之后的 brief。
-
-
停止。 当 brief 为终态时停止;或者,如果任何一次提交返回 错误封装(参见
.ctxr-fsm/memory/principles.md中的原则 4–5),也停止。
Worker 分派——并发
dispatch_specialists 状态的 worker 是唯一负责扇出的 worker。它是一个 Loop 状态:上游的 plan_specialist_batches 内联处理器会将每个选中的叶节点划分为一个或多个确定性批次(通常每批 3–5 个单元,由 tier 决定),引擎会针对每个批次驱动一次 Loop 迭代。每次迭代的说明包含:
iteration_n— 从 1 开始的迭代计数器。inputs.specialist_batches[]— 完整计划。inputs.total_batches— 规划器预期的 Loop 长度。
每次迭代中:使用客户端的并行工具调用机制,并发分派 specialist_batches[iteration_n - 1].units[] 中的每个单元(Claude Code:在一条消息中发起多个 Task / Agent 调用;Codex:使用等效机制),收集每个子 Agent 的输出,然后将聚合载荷({batch_index, iter_outputs[], loop_done})提交到 fsm.commit_outputs,并匹配 worker 的 response_schema。
Loop 的终止由引擎决定,而不是由你决定。 在最后一次迭代中设置 loop_done = (iteration_n == total_batches)——但绝不要自行推进到 dispatch_specialists 之后。每次提交后,都要再次调用 fsm.get_brief(run_id)。只要下一份说明仍包含 state_id = "dispatch_specialists",就还有一次迭代需要运行。只有当下一份说明进入后续状态(通常是 merge_specialist_outputs)时,分派才算完成。
循环直至为空的示例(伪代码)
while True:
brief = fsm.get_brief(run_id)
if brief.terminal:
print(brief.run_dir_path)
break
if brief.has_loop and brief.state_id == "dispatch_specialists":
# One iteration = one planner batch. Drain every unit IN PARALLEL.
current_batch = brief.inputs["specialist_batches"][brief.iteration_n - 1]
iter_outputs = dispatch_units_in_parallel(current_batch["units"])
loop_done = brief.iteration_n == brief.inputs["total_batches"]
fsm.commit_outputs(run_id, outputs={
"batch_index": brief.iteration_n,
"iter_outputs": iter_outputs,
"loop_done": loop_done,
})
# Do NOT break here. Continue the WHILE loop so we re-poll
# fsm.get_brief; the engine reissues another dispatch_specialists
# iteration (with iteration_n + 1) until total_batches is reached.
continue
if brief.has_worker:
outputs = dispatch_single_agent(brief.worker)
fsm.commit_outputs(run_id, outputs=outputs)
continue
单次迭代内并行执行的专家数量上限取自 risk_tier_triage 的 cap 字段:trivial=3、lite=8、full=20、sensitive=30;也可以通过 args["max-reviewers"] 覆盖(限制在 [3, 50] 范围内)。迭代次数则独立计算,取决于规划器给出的 total_batches。对一个包含 100 个叶节点的评审任务,在 full tier 下使用 batch_size 5,会产生 20 次迭代,每次并行分派最多 5 个单元。
诊断:DispatchLoopExitedEarlyError
如果合并器检测到 loop_iters[] 涵盖的 (leaf_id, sub_index) 单元少于 specialist_batches[] 计划的数量,就会抛出 DispatchLoopExitedEarlyError,而不是生成一份专家静默失败的 NO-GO 报告。错误消息会包含缺失的单元 ID,操作人员可以立即查看编排器跳过了哪些迭代。修复始终在编排器一侧进行:继续运行循环,直到 fsm.get_brief 不再返回 dispatch_specialists。
各状态的工具范围
每个工作状态都会在 FSM 规范中固定一个 allowed_tools 允许列表。
该列表是为该状态分派的子 Agent 可以调用的工具的准确集合。工具 ID 使用 Claude Code 权限格式(作用域 shell 命令使用 Bash(<prefix>:*),其他工具使用裸工具名称);其他执行框架会在分派时进行转换。
| 状态 | allowed_tools |
|---|---|
scan_project | Bash(git diff:*)、Bash(git log:*)、Bash(git status:*)、Bash(git ls-files:*)、Bash(cat:*)、Read、Glob |
tree_descend | Read |
llm_trim | (无 — 仅根据简述进行推理) |
tool_discovery | Bash(eslint:*)、Bash(ruff:*)、Bash(mypy:*)、Bash(npm test:*)、Bash(pytest:*)、Bash(cargo:*)、Bash(go test:*)、Bash(which:*)、Read |
dispatch_specialists | Read、Grep、Glob、WebFetch、Bash(git diff:*)、Bash(git log:*) |
内联状态(risk_tier_triage、activate_leaves、
collect_findings、verify_coverage、synthesize_release_readiness、
write_run_directory、emit_stdout、short_circuit_exit、
stage_a_empty)以及 terminal 状态的允许列表均为空 —
它们在 ctxr-fsm 内由服务端运行,不会分派给子 Agent。
为工作状态分派子 Agent 时,将该状态的 allowed_tools 原样
传递到子 Agent 的工具权限格式中(Claude Code:--allowedTools=<list>;Codex 对应参数:--tools;
Cursor:对应参数)。然后,对于子 Agent 发出的每次非 fsm.* 工具调用,都要调用
fsm.observe_tool_call,以便漂移检测器进行审计。违规会触发 off_allowlist_tool_call(权重 5.0);
累计值 > 10 时会自动暂停运行。
此技能的产出
在
<project>/.skill-code-review/<yyyy>/<mm>/<dd>/<shard>/<rest>/ 下生成
report.md(Markdown)、report.json(机器可读)和
manifest.json(技能侧运行元数据)。具体格式见 report-format.md。
判定结果:GO、CONDITIONAL 或 NO-GO。
可观测性
该技能的逐状态验证器面板会在每次工作状态提交时,向 FSM 事件流发出
verifier_passed 和 verifier_rejected 事件。要实时查看这些事件:
- 在
http://localhost:7475/runs/<run_id>打开 fsm UI(该 URL 由编排器在start_run时输出;端口与ctxr-fsm监督程序配置的 UI 端口一致)。 - 打开此运行的 AdminSheet;漂移部分会显示逐状态验证器结果时间线。
- 点击任一工作状态(
scan_project、tree_descend、llm_trim、tool_discovery、dispatch_specialists),然后切换到 此状态的事件选项卡 — 该状态的每个verifier_passed/verifier_rejected事件都会与面板中各投票者给出的原因一并列出。
当同一工作状态达到连续拒绝上限
(目前为 3,定义于
code_review.handlers._VERIFIER_REJECTION_LIMIT)时,编排器会将运行推进到内联的 verifier_stuck 状态。
该状态会发出 degraded_run 信封,供
synthesize_release_readiness 使用,以降低判定结果(覆盖不完整的运行不会得到 GO)。fsm UI 会在受影响状态的 Sheet 上以黄色标记显示这一僵局。
另请参阅
code-reviewer.md— 11 步编排器 设计文档。release-readiness.md— 8 道关卡 谓词规范。report-format.md— 清单 + 报告架构。reviewers.wiki/— 约 476 个叶级 审查器组成的语料库。CHANGELOG.md— 发布历史。
程序化运行器(生产级编排)
code_review/runner.py::run_review(args, dispatch_worker, dispatch_specialist, ...)
在进程内驱动 FSM,并通过受控、容错的线程池调度各叶级专家——这是实现并行处理 + 韧性的核心:
- 有界、自适应并行度(AIMD)。
_AdaptiveLimiter将实时 worker 数量限制在[min_workers, max_workers];收到速率限制信号时数量减半,持续成功时则增加 1(线程由 ThreadPoolExecutor 负责)。 - 可容忍速率限制。 单元引发
RateLimitError时 → 乘法退避 + 重试,并缩小线程池。 - 可容忍上下文溢出。 单元引发
ContextOverflowError时,会进一步拆分为多个子分片(文件均分),然后重新调度;无法拆分的单个文件会成为一个failed单元——绝不丢弃。 - 100% 覆盖率。 每个计划中的单元都会被调度;仍然失败的单元会标记为
status: "failed"(合并阶段会确保没有遗漏文件)。 - 与模型无关。 每个状态 / 叶级的 LLM 调用均通过注入的钩子实现
(
dispatch_worker/dispatch_specialist,或环境变量CTXR_SCR_WORKER_DISPATCH/CTXR_SCR_SPECIALIST_DISPATCH)。
本 SKILL.md 中的 LLM 编排路径与此程序化运行器共用相同的 FSM + 内联处理程序;运行器是通过代码确定性、并行且容错地驱动审查的方式。