Windmill 本地代码审查工作流(local-review):在合并前用全新上下文复现 CI 的 PR 自动审查
【免费下载链接】windmillOpen-source developer platform to power your entire infra and turn scripts into webhooks, workflows and UIs. Fastest workflow engine (13x vs Airflow). Open-source alternative to Retool and Temporal.项目地址: https://gitcode.com/GitHub_Trending/wi/windmill
本地代码审查是 Windmill 仓库开发流程中关键的一环:GitHub 上的自动审查动作(Claude / Codex / Pi)会在每个 PR 上运行,而.claude/skills/local-review/SKILL.md提供了一套在本地复现同样审查的机制,让开发者在自己机器上、PR 合并之前就能获得与 CI 一致的质量把关。这篇文章将完整解析这套本地审查工作流:为什么审查必须运行在"全新上下文"中、如何确定审查范围、如何构造子代理提示词、如何解读和发布审查结论,并结合仓库中的审查策略文件REVIEW.md、子代理定义与 CI 工作流源码,讲清楚从分支 diff 到 PR 评论的完整链路。
一、为什么要用全新上下文运行审查
local-review技能的核心设计动机写在其 SKILL.md 中:审查必须在全新上下文中运行,而不是在当前会话内联执行。
原因是"锚定效应"(anchoring):当开发者在同一个会话里反复迭代 diff 时,主会话已经吸收了开发者的推理与合理化过程,会不自觉地认同这些决策,从而漏掉 CI 能够发现的问题。而子代理(subagent)以冷启动(cold start)方式运行,与 CI 一样不带任何先入为主的判断,因此能发现主会话会忽略的缺陷。
这与 Windmill 的 CI 配置完全一致。查看 .github/workflows/codex-pr-review.yml,CI 中的 Codex 审查同样通过独立的codex exec进程运行,每次都是全新进程,不会锚定于任何聊天会话。正如local-review-codex技能文档所述:"Fresh context is inherent:codex execis a separate cold process"。
二、审查策略基准:REVIEW.md
无论哪种工具执行审查,统一的策略都定义在仓库根目录的 REVIEW.md 中。该文件是"PR 审查共享策略",被 Claude、Codex、Pi 三条审查链路共同引用:
- 先读项目规则:审查前必须先读根目录 AGENTS.md 以及 diff 涉及目录中的任何
AGENTS.md,它们是权威贡献者指南。标记违规时必须引用 AGENTS.md 中的确切规则原文。 - 结论行(verdict):每条审查的第一行必须是单一结论,只有三种取值之一:
Good to merge—— 无阻塞问题也无值得提出的 nit;Mergeable, but should ideally address nits: <短列表>—— 无阻塞项,但有值得一看的 P2;Should address issues before merging: <短列表>—— 至少一个 P0 或 P1。
- @作者 ping:如果结论不是 "Good to merge" 且上下文提供了 PR 作者 GitHub 登录名,须在顶层评论的最上方(结论行之上)加一行
cc @<PR_AUTHOR>。 - 只报告确信的问题:只报告由本次 PR 引入的真实问题,聚焦 bug、安全、性能与明确的 AGENTS.md 违规;不报告风格 nit、推测性顾虑、既有问题或 linter/类型检查器能明显捕获的内容。每条发现张贴前都要自问:"这是资深工程师一定会标记的真实问题吗?"不确定就丢弃。
- 严重度分级:
- P0—— RCE、认证绕过、数据丢失、代码中的密钥、SQL 注入、路径穿越、公共接口上的认证破坏;
- P1—— 重大 bug、新公共接口缺少认证/授权检查、疑似异步路径上的阻塞 I/O、竞态条件、调用方可控参数缺少输入校验、可观测的性能回退;
- P2—— 模块放置错误、文档与代码不一致、半成品公共抽象(
pub fn+#[allow(dead_code)]+TODO)、AGENTS.md 风格违规、命名与函数行为矛盾。
- 新公共接口检查清单:对 PR 引入的任何新
pub fn/pub async fn/ 导出的 Svelte 组件 / 导出 prop,须验证:(a) 认证/授权预期已在文档注释中说明或在函数体内强制(涉及工作区数据、密钥、文件或进程的新pub fn若无认证检查或未文档化 "调用方必须验证" 契约,即 P1);(b) 模块放置是否与其声明用途匹配(检查//!模块级注释);(c) 是否半成品;(d) 每个可能由调用方控制的参数是否对注入/穿越/溢出/NUL 字节有输入校验。 - 测试覆盖评估:审查以简短的 "Test coverage" 部分结尾,针对 diff 实际触及的层:
- 后端(Rust,
backend/下)—— 期望新逻辑有 Rust 单元测试;涉及新 API handler、worker 步骤、队列/cron 行为或 DB 访问时,还须期望或指出集成测试的缺失; - 前端(Svelte/TS,
frontend/下)—— 代码库一般不测试 Svelte 组件,不要索要组件测试;只为新的纯逻辑工具(已有姊妹*.test.ts的那类文件)标记测试缺失; - CI / 工作流 / 文档 / 纯配置 —— 不期望自动化测试,明确说明即可。
- 然后说明合并前还需要哪些手动验证场景,或明确说明该 diff 没有可操作的应用内界面。
- 后端(Rust,
三、完整工作流:四个步骤
local-review技能的核心步骤在 SKILL.md 中定义得十分清晰:
1. 确定 PR 范围(在主会话中执行,成本低)
- 如果提供了参数,将其视为 PR 编号或分支名;
- 否则,根据当前分支与
main的差异自动检测; - 确认 PR/分支存在:
gh pr view <n>或git rev-parse <branch>。
2. 委托给全新上下文的子代理
使用自包含(self-contained)的提示词委托审查,提示词必须包含:
- 要审查的 PR 编号或分支名;
- 指示先读
REVIEW.md获取策略,再读 diff 触及目录中的AGENTS.md; - 精确的输出格式(见下节);
- 是否请求了
--comment(以便子代理在需要时生成内联评论载荷); - 用户提供的任何"附加审查者指令"。
针对不同 CLI 的委托方式:
- Claude Code:使用
Agent工具,subagent_type: branch-diff-reviewer(只读工具,为此专门构建)。不可用时回退到general-purpose。 - Codex / Pi:如果 CLI 暴露了全新会话的子代理机制则使用之;否则告知用户在全新 CLI 会话中运行该技能并停止——在当前会话内联运行会违背设计初衷。
3. 接收发现并原样转达
子代理完成后,将发现逐字转达给用户。不要重新总结、重新评判或过滤——全新上下文的全部意义就在于浮出主会话会忽略的内容。
4. 发布评论(若请求了--comment)
使用下面的gh命令以子代理输出作为正文发布。由主会话负责发布,因为子代理是只读的。
四、子代理提示词模板详解
SKILL.md 提供了完整的提示词模板,可直接粘贴使用:
Review <PR #N | branch X> against main per the policy in REVIEW.md. Steps: 1. Read REVIEW.md (repo root) for the full policy: severity triage, public-surface checklist, AGENTS.md compliance, test coverage assessment. 2. Read AGENTS.md (repo root) and any AGENTS.md in directories touched by the diff. 3. Get the diff: `gh pr diff <N>` (if PR) or `git diff main...<branch>`. 4. Get context: `gh pr view <N>` (if PR) or `git log main..<branch> --oneline`. 5. Read changed files only when the diff alone is insufficient to validate a finding. 6. Self-validate each finding: "is this definitely a real issue a senior engineer would flag?" Discard if uncertain. 7. Output findings in the exact format below. Do not modify any files. <输出格式,见下节> <如果请求了 --comment:> Additionally emit a JSON array of inline comments suitable for the GitHub reviews API, one per finding that maps to a specific line: [{"path": "...", "line": N, "side": "RIGHT", "body": "[P1] ..."}, ...]注意第 6 步与 REVIEW.md 的"Self-validate each finding"相互呼应,第 7 步的"Do not modify any files"则是审查代理的只读纪律。
五、输出格式
SKILL.md 规定的审查输出格式如下(与 REVIEW.md 的结论行要求一致):
## Code review <verdict line per REVIEW.md> Found N issues: 1. [P0|P1|P2] <description> <file_path:line_number> 2. [P0|P1|P2] <description> <file_path:line_number>以 "Test coverage" 部分结尾(依据共享策略)。如果没有发现问题:
## Code review Good to merge. No issues found. Checked for bugs, security, and AGENTS.md compliance.各 CLI 的输出格式在仓库中还有更具体的落点:
- Claude 的输出规范在 .claude/review-prompt.md:具体问题使用相关行的内联评论;摘要、带严重度标记的发现列表、AGENTS.md 合规检查与测试覆盖评估放在顶层评论中。
- Codex 的输出规范在 .github/codex/pr-review.prompt.md:返回以
## Codex Review开头的 markdown PR 评论;每条发现标注严重度(P0/P1/P2)、文件路径及可信的行号。
六、发布评论(--comment 模式)
SKILL.md 提供了两条发布命令:
顶层 PR 评论:
gh pr review --comment --body "<summary from subagent>"针对具体行的内联评论(使用子代理生成的 JSON):
gh api repos/{owner}/{repo}/pulls/{pr}/reviews \ -f body="<summary>" -f event="COMMENT" -f comments="<json from subagent>"内联评论 JSON 数组中每个元素对应一条映射到具体行的发现,结构为{"path": "...", "line": N, "side": "RIGHT", "body": "[P1] ..."}。
七、配套资产:子代理定义与兄弟技能
branch-diff-reviewer 子代理
.claude/agents/branch-diff-reviewer.md 定义了local-review调用的专用子代理。它使用 Glob、Grep、Read、Bash 等只读工具集,流程为:先用git diff main...HEAD与git log main..HEAD --oneline获取完整 diff 和提交历史,再逐个分析变更文件,按六类维度评估:Bug 与正确性、性能、安全、代码质量与风格、架构与设计、测试考虑。
它还包含项目专属规则,体现了 Windmill 的技术栈特点:
- Rust 后端:
SELECT必须列出显式列名(worker 代码中绝不用SELECT *);正确使用sqlx参数化查询;错误使用windmill-common::error的自定义Error枚举;确认异步代码不阻塞 tokio 运行时;检查 serde 属性的序列化最优性;API 变更须更新 openapi.yaml。 - Svelte 前端:Svelte 5 文件正确使用 Runes(
$state、$derived、$effect);{#each}块带key属性;事件处理器使用新语法(onclick而非on:click);snippets 代替 slots;用$props()声明 props。
local-review-codex:推前审查的 Codex 版本
.claude/skills/local-review-codex/SKILL.md 是local-review的 Codex 对应物,针对尚未推送的工作(已提交 + 未提交)在 push 前运行。它与 CI 中的 Codex 审查(.github/workflows/codex-pr-review.yml)保持"相同策略、相同推理强度":
- 策略同为
REVIEW.md;推理强度同为model_reasoning_effort="xhigh";输出同样以## Codex Review开头、发现标注 P0/P1/P2 及 file:line。 - 与 CI 的差异:模型为
gpt-6-astra(CI 用gpt-5.6-sol);范围是当前分支相对 merge-base 处的main,包含未提交改动;沙箱为read-only。 - 前置条件:
codexCLI>= 0.153.4且已通过codex login认证(升级命令:npm install --global @openai/codex@0.153.4);若 base ref 过期先git fetch。 - 运行方式:
bash .agents/skills/local-review-codex/run.sh # review vs main (default) bash .agents/skills/local-review-codex/run.sh <base> # review vs a different base ref脚本计算BASE_SHA = git merge-base HEAD <base>,向 Codex 喂入REVIEW.md与指向git diff <BASE_SHA>的 diff 上下文(其中折叠了未提交的编辑),并打印审查结果;只写临时文件,不落盘到工作树。结果同样要求逐字打印,不与当前会话的合理化相混合。
八、与 CI 自动审查的对应关系
Windmill 仓库在 CI 中运行着平行的自动审查动作,local-review的目的正是"在本地运行与 PR 上相同的审查"。除了 Codex,还有:
- .github/workflows/claude.yml 与 .github/workflows/pi-pr-review.yml,分别对应 Claude 与 Pi 的 PR 审查;
- .github/codex/pr-review.prompt.md 与 .github/pi/pr-review.prompt.md 是各自的提示词文件。
以codex-pr-review.yml为例,其安全设计值得借鉴:fork PR 运行不可信代码,自动触发从不审查 fork PR(仅通过维护者workflow_call注释触发);fork 场景下从 base ref 读取 REVIEW.md 与提示词(用git show),防止恶意 fork 重写审查者指令,并在网络禁用沙箱中运行以防密钥外泄;发布评论前还会对输出中的凭据做脱敏([REDACTED])。
九、在仓库中的集成方式
local-review的调用入口在 AGENTS.md 的 Documentation 一节中有明确说明:三个 CLI 自动发现同一份 SKILL——Claude 读取.claude/skills/(符号链接到规范的.agents/skills/文件),Codex 和 Pi 直接读取.agents/skills/。调用方式分别为:Claude Code 中/local-review,Codex 中$local-review(或/skills选择器),Pi 中pi --skill local-review或/skill:local-review。
仓库还在 .claude/settings.json 中为本地审查配置了配套的权限与 hooks:
- PreToolUse hooks:
guard-main-branch.sh(保护 main 分支)、guard-rm-outside-tmp.sh与allow-fileops-in-tmp.sh(限制文件删除/移动/复制操作于/tmp等安全范围)——这与审查代理"只读"的纪律相配合; - PostToolUse hooks:
format-frontend.sh与format-backend.sh在编辑后自动格式化; - 权限:
additionalDirectories指向../windmill-ee-private(企业版私有仓库,与 CI 中WINDMILL_EE_PRIVATE_ACCESS检查 EE 访问、执行substitute_ee_code.sh的机制对应);对.env、secrets/、*.pem、*.key等敏感文件一律 deny 编辑。
十、最佳实践要点
- 主会话只做轻量工作:确定 PR 范围这类低成本操作留在主会话,重审查永远交给冷启动子代理。
- 原样转达,不加工:子代理输出必须逐字转发,这是"新鲜上下文"价值的前提;
local-review-codex同样要求原样打印 Codex 输出。 - 先策略后代码:任何审查先读
REVIEW.md与相关AGENTS.md,再取 diff;取 diff 用gh pr diff <N>(PR)或git diff main...<branch>(分支),取上下文用gh pr view <N>或git log main..<branch> --oneline。 - 只读纪律:子代理绝不修改文件,评论发布由主会话用
gh完成。 - 发布前自检:每条发现都经过"资深工程师一定会标记吗"的自检,P0/P1 必报,P2 仅在 diff 邀请时(新
pub fn、新模块、新导出组件、有意义的重构)报告。 - 与 CI 对齐:本地结果与 CI 一致的可信度来源于同一份
REVIEW.md策略、同样的严重度分级与测试覆盖评估方法——这保证了"本地通过 = CI 大概率通过"。
这套工作流的最终效果是:开发者在推送前就能获得与 CI 同等严格度的代码审查,把 P0/P1 级别的缺陷(安全漏洞、竞态、公共接口缺失鉴权)挡在合并之前,同时让 AGENTS.md 中的项目规范真正成为可执行的质量门槛。
【免费下载链接】windmillOpen-source developer platform to power your entire infra and turn scripts into webhooks, workflows and UIs. Fastest workflow engine (13x vs Airflow). Open-source alternative to Retool and Temporal.项目地址: https://gitcode.com/GitHub_Trending/wi/windmill
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考