关于 review-diff
review-diff 是用于 Claude Code 和 Codex 的代码审查技能,检查相对 main 的提交与工作区变更。它将审查分为九个视角,并通过脚本汇总、排序和验证发现。
主要功能
- 01检查相对 main 的完整变更
- 02九个视角并行审查
- 03校验并重新派发失败审查
- 04脚本汇总、合并、排序与验证
适用场景
- 01合并前审查提交和未提交改动
- 02从架构、安全、测试等角度查找问题
- 03生成可供后续 review-tickets 使用的审查结果
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ jimweller/ clanker-code-review-plugin --skill review-diff安装后在 Claude Code 中输入/review-diff确认已加载。
详细介绍
STARTER_CHARACTER = ⚡
差异审查
从 9 个视角审查所有与 main 不同的内容,每个视角由一个子 Agent 负责。随后,九个领域的发现会经过与 review-deep 相同的脚本化汇总、合并、排序和隔离裁判验证链。无需参数。
可在 Claude Code(通过此插件)和 Codex 上使用。在 OpenCode 和 Hermes Agent 上会按名称在预检阶段失败,因为这两者都无法将子 Agent 派发给指定类型的审查者。
此技能以 context: fork 运行,并作为子 Agent 派发,此时没有用户在场回答提示词。派发前绝不要暂停以确认范围、成本或模型开销;差异就是当前的差异。
第 1 步:预检
确定你的运行环境。在 Claude Code 中,HARNESS=claude,PLUGIN_ROOT 是此插件的根目录,即向上两级到达此 SKILL.md 所在的位置。在 Codex 中,HARNESS=codex;PLUGIN_ROOT 不适用,因为九个 Codex 审查者 Agent 位于固定路径,而非插件内。
S="${CLAUDE_SKILL_DIR}/../review-deep/scripts" # replace ${CLAUDE_SKILL_DIR} with this SKILL.md's own directory on a non-Claude harness
[ -f "$S/init_run.py" ] || { echo "scripts not found at $S"; exit 1; }
HARNESS=claude
PLUGIN_ROOT="$(cd "${CLAUDE_SKILL_DIR}/../.." && pwd)"
OUT=$(python3 "$S/preflight.py" --tier diff --harness "$HARNESS" --plugin-root "$PLUGIN_ROOT")
STATUS=$?
echo "$OUT"
[ "$STATUS" -eq 0 ] || exit 1
LABEL=$(echo "$OUT" | sed -n 's/^LABEL=//p')
AGENT_PREFIX=$(echo "$OUT" | sed -n 's/^AGENT_PREFIX=//p')
preflight.py 会检查此技能所需的每个工具、Agent 文件和引用(包括确认 origin/main 或 main 可以解析),为每项检查打印一行 PASS 或 FAIL,并在任何一项为 FAIL 时以状态码 1 退出。成功时,它还会打印 LABEL($LABEL-<area>.md 背后的审查者来源名称)和 AGENT_PREFIX(九种子 Agent 类型的命名空间前缀;在 Claude Code 中为 clanker-code-review:,在 Codex 中为空)。$S 守卫可检测不完整或损坏的插件或技能安装。
第 2 步:解析基准
PROJECT_ROOT=$(git rev-parse --show-toplevel)
BASE_REF=$(git rev-parse --verify --quiet origin/main || git rev-parse --verify --quiet main)
if [ -z "$BASE_REF" ]; then
echo "No main branch found (tried origin/main and main)"
exit 1
fi
BASE=$(git merge-base HEAD "$BASE_REF")
# On main itself the merge base is HEAD, which would hide committed work.
# Fall back to the previous commit so the branch tip is still under review.
if [ "$BASE" = "$(git rev-parse HEAD)" ]; then
BASE=$(git rev-parse --verify --quiet HEAD~1 || echo "$BASE")
fi
echo "BASE=$BASE"
第 3 步:收集差异
git log --oneline "${BASE}"..HEAD
git diff "${BASE}" --find-renames --stat
git diff "${BASE}" --find-renames
git status --porcelain
git ls-files --others --exclude-standard
git diff "$BASE" 不带 ..HEAD,因此会涵盖从合并基点到工作树的差异。已提交、已暂存和未暂存的更改都会纳入同一个差异中。--find-renames 会将重命名显示为同时包含两个路径的 R<score> 条目,因此纯重命名不会折叠为空差异。git status --porcelain 是所有已修改、新增、删除、重命名、复制和未跟踪条目的权威列表。ls-files --others 会列出未跟踪文件,这些文件没有差异表示形式。匹配 .gitignore 的文件会被排除。
当五项信号(提交日志、差异统计、差异、状态和未跟踪列表)都为空时停止。报告 No changes against main 并停止。
第 4 步:启动运行
python3 "$S/init_run.py" --kind diff --base "$BASE" "$PROJECT_ROOT" "$PROJECT_ROOT" "$PROJECT_ROOT/.llmtmp/review-diff"
会打印 RUN_DIR 和 COMMIT。RUN_DIR 是仓库之外的 ${XDG_CACHE_HOME:-~/.cache}/review-diff/<repo>-<commit12>。工作树干净时,COMMIT 为 HEAD。工作树存在未提交更改时,init_run.py 会将工作树快照保存为一个基于 HEAD 的无引用提交,因此审查者、下方的 git diff 以及脚本化链中的裁判都会看到完全相同的未提交编辑。run.json 包含 kind: diff、base: $BASE 和 ticket_label: review-diff。
第 5 步:生成输入
将整个变更集写入一个文件。审查者可以使用 Read,但不能使用 Bash,因此无法自行运行 git。将差异通过九个提示词传递,会让编排器输出中包含九份副本;将其写入一次,再让每位审查者读取,只需一份。
STATE_DIR="$PROJECT_ROOT/.llmtmp/review-diff"
mkdir -p "$STATE_DIR"
find "$STATE_DIR" -mindepth 1 -delete
INPUT="$STATE_DIR/input.md"
{
echo "# Change set vs merge-base ${BASE}, reviewed at commit ${COMMIT}"
echo; echo "## Commits"; git log --oneline "${BASE}"..HEAD
echo; echo "## Status"; git status --porcelain
echo; echo "## Diffstat"; git diff "${BASE}" "${COMMIT}" --find-renames --stat
echo; echo "## Diff"; git diff "${BASE}" "${COMMIT}" --find-renames
} > "$INPUT"
for f in $(git ls-files --others --exclude-standard); do
{ echo; echo "## Untracked file: $f"; cat -n "$f"; } >> "$INPUT"
done
wc -c "$INPUT"
git diff "$BASE" "$COMMIT" 会取代旧的、针对工作树运行的 git diff "$BASE":审查者必须看到与脚本化链中的裁判之后检出并验证的内容完全一致的差异,而 $COMMIT(工作树有未提交更改时为快照,否则为 HEAD)就是这个固定点。未跟踪文件没有差异表示形式,因此会将其完整内容附加并标注行号。
使用 mkdir -p,然后使用 find -delete,而不是 rm -rf。PATH 中的 safe-rm 替代命令(某些 dotfiles 配置中会出现)会将路径移至废纸篓,并且即使使用 -f,遇到不存在的路径也会以非零状态码退出,这会导致首次运行时清理失败。
第 6 步:构建清单
python3 "$S/ledger.py" "$STATE_DIR" --diff "$PROJECT_ROOT" "$BASE" "$COMMIT"
python3 "$S/partition.py" "$STATE_DIR"
ledger.py --diff 会在 $BASE 和 $COMMIT 之间运行 git diff --name-only --no-renames --diff-filter=d,因此重命名只会产生一次新路径,而删除项会被丢弃。审查者直接使用 $INPUT 工作,而不是使用 partition.py 的组成部分;真正读取这些组成部分的是 report.py 的覆盖范围部分。
步骤 7:并行派发 9 个审查 Agent
在单个工具块中发起全部 9 个 Agent 调用,并设置 run_in_background: false。
子 Agent 默认在后台运行。后台扇出会在后续轮次才返回结果,因此步骤 8 将没有内容可供汇总。在一个块中同步派发,才能让整个 Agent 群并行运行,并在本轮生成报告。
| Agent 类型 | 领域 |
|---|---|
${AGENT_PREFIX}reviewer-architecture | 架构 |
${AGENT_PREFIX}reviewer-correctness | 正确性 |
${AGENT_PREFIX}reviewer-data | 数据 |
${AGENT_PREFIX}reviewer-ops | 运维 |
${AGENT_PREFIX}reviewer-performance | 性能 |
${AGENT_PREFIX}reviewer-quality | 质量 |
${AGENT_PREFIX}reviewer-security | 安全 |
${AGENT_PREFIX}reviewer-solid | SOLID |
${AGENT_PREFIX}reviewer-testing | 测试 |
每次运行都要派发全部 9 个。不要根据变更文件跳过任何审查视角。
每个提示词完全相同,不作任何改动。发送以下内容,并将 <INPUT> 和 <PROJECT_ROOT> 替换为实际值:
Read <INPUT>. It holds the commit log, porcelain status, diffstat, full diff
against the merge-base with main, and the full contents of every untracked
file. That is the complete change set under review.
The project root is <PROJECT_ROOT>. Every path in the diff is relative to it.
Open any file you need in that tree to confirm a finding and to confirm the
line number you cite.
Audit this change set. Apply the Ownership table in your instructions: report
only defect classes you own, and stay silent on the rest.
Write your findings to <STATE_DIR>/<LABEL>-<area>.md. Use an H2 header
followed by findings or exactly "No findings."
简报有意保持简短。严重性、引用格式、输出形式和职责范围都由 Agent 定义决定,因此只需编辑定义,就能影响所有调用方。
不要打包 repomix。输入文件已包含所有内容。
步骤 8:检查并重新派发
python3 "$S/check_reviews.py" "$RUN_DIR" "$LABEL"
每个领域会输出一行 PASS 或 FAIL;任何检查失败时都会以状态码 1 退出:文件缺失、没有 H2、没有发现项且内容并非恰好为 No findings.,或其中的条目无法解析为 normalize.FULL 或 normalize.BARE。这里常见的失败原因有两个:Agent 遇到临时 API 错误后退出,未写入任何内容;或者钩子阻止其读取 $INPUT,导致它写入拒绝响应。对每个失败领域重新派发一次对应的 Agent,使用与步骤 7 相同的提示词,然后再次运行 check_reviews.py。第二次失败将在步骤 9 中报告为未审查,不再重试。
编辑 Agent 定义不会影响已在运行的会话。Claude Code 会检测到新增或移除 Agent 文件,但会话会保留启动时加载的正文;通过符号链接(如 dotbot 安装的链接)访问的定义在编辑后也不会重新读取。更改审查 Agent 后,请重启会话。
步骤 9:运行脚本化流程并报告
将每个模型阶段作为后台 Bash 调用运行;池中的调用全部完成后,池才会返回,完成通知即为继续执行的信号。切勿使用 sleep 轮询正在运行的阶段。直接将阶段命令作为后台调用运行。切勿使用 nohup 或在命令末尾追加 & 将其分离,也不要使用 tail -f | grep -m1 等待日志行。tail 只有在下一次写入时才会退出,因此日志写入最后一行后,调用会一直挂起,直到超时。
python3 "$S/checkout.py" "$RUN_DIR"
python3 "$S/normalize.py" "$RUN_DIR"
python3 "$S/collate.py" "$RUN_DIR" # one model call per component, background
uv run --with scikit-learn --with scipy --with numpy python "$S/windows.py" "$RUN_DIR"
python3 "$S/merge.py" "$RUN_DIR" # one model call per similarity window, background
python3 "$S/rank.py" "$RUN_DIR"
python3 "$S/verify.py" "$RUN_DIR" # one model call per Critical or High issue, background
python3 "$S/report.py" "$RUN_DIR"
diff 的范围通常足够小,也可以核实严重性为 Medium 的问题:将 --floor Medium 传给 verify.py(python3 "$S/verify.py" "$RUN_DIR" --floor Medium),即可把核验范围扩大到 Critical/High 默认级别之外。
向操作人员报告 report.md 中的数量、已确认的问题以及 RUN_DIR。该运行目录可作为 review-tickets 技能的有效输入,工单标签为 review-diff。
测试
请参阅 review-deep 的 Tests 部分。此插件仓库根目录下的同一 evals/ 涵盖这里的所有技能,包括本技能预检阶段的 unit/preflight。