Deno PR Review Skill:一套五步自动化 Pull Request 审查工作流的设计与实现
本文围绕 Deno 仓库内为 AI Agent 编写的 PR 审查技能定义 .claude/skills/review-pr/SKILL.md,完整拆解其“收集上下文 → 门禁检查 → 代码审查 → 类型专项检查 → 撰写评审”的五步工作流。读完后,你可以理解 Deno 项目对贡献者 PR 的具体质量要求(标题规范、测试分层、primordials、权限系统等)如何在自动化审查中被逐条落实,并能参考这套模式为任意开源仓库设计自己的 Agent 审查流程。
一、Skill 是什么:一个面向 Agent 的 PR 审查器
SKILL.md 是 Claude Code 风格的技能(skill)文件:YAML frontmatter 声明元信息,正文是给 Agent 的逐步操作指令。其 frontmatter 定义了:
name: review-pr:技能名;description:审查 Deno 运行时 PR 的正确性、测试、安全性与规范,当被要求审查 PR 或提供 PR 编号/URL 时触发;argument-hint: <pr-number-or-url>:调用时需传入 PR 编号或 URL;allowed-tools: Bash(gh *) Bash(git *) Read Glob Grep Agent:仅允许gh/git命令、文件读取与检索类工具——即整个审查流程完全基于ghCLI 与本地仓库文件系统完成。
该技能位于 .claude/skills/ 目录下,与 fmt、lint-all、lint-js、issue-triage、node-compat 等技能并列,构成 Deno 仓库内一组可复用的 Agent 工作流。下文按文档原始步骤逐一展开,并结合仓库源码核实每条规则的实际依据。
二、Step 1:收集 PR 上下文(Gather PR context)
在审代码之前,Agent 先用 gh 命令拉取四类信息,文档中给出的原始命令为(! 前缀表示执行型代码块,$ARGUMENTS 即传入的 PR 编号或 URL):
# PR 元数据:编号、标题、正文、作者、标签、状态、评审决定、提交、文件列表
gh pr view $ARGUMENTS --json number,title,body,author,labels,state,reviewDecision,commits,files,isDraft,createdAt,url
# 完整 diff
gh pr diff $ARGUMENTS
# PR 评论区内容
gh pr view $ARGUMENTS --comments --json comments
# CI 检查结果(无检查时降级为空输出,避免命令报错中断流程)
gh pr checks $ARGUMENTS --json name,state,conclusion 2>/dev/null || echo "No checks found"
这四组输出分别服务于后续步骤:元数据用于门禁 6(外部贡献者需关联 issue)与合并就绪评论;diff 是代码审查的输入;评论区用于理解讨论上下文;CI 结果直接决定门禁 1 是否通过。
三、Step 2:六道门禁检查(Gate checks)
文档明确要求:任何门禁失败时,必须把问题显著地列在评审意见最顶部,且不得 approve。六道门禁如下,每一条都能在仓库中找到对应的执行依据。
1. CI 状态
所有检查必须通过;失败时应指出具体是哪个检查挂了。标注为 ci-test-flaky 的已知不稳定测试可以重跑。这一门禁与 CLAUDE.md 中 “PR 必须经 CI 合入 main” 的标准 git 工作流一致。
2. PR 标题格式
标题必须遵循 type(scope): description。技能文档列出的类型包括 feat、fix、perf、refactor、chore、docs、test、revert、BREAKING,scope 示例如 ext/node、ext/fetch、cli、lsp、runtime。
这一规则在 CI 侧由 tools/verify_pr_title.js 强制校验。从源码结构看,实际被接受的合法前缀比技能文档列出的更宽,还包括 ci、cleanup、bench、build、Revert 、Reland (用于在 changelog 中标记被回退后又重新合入的提交),以及形如 x.y.z 的发布 PR 标题;另外该脚本还有一条专门针对 chore: ... upgrade deno_core/v8 的细化规则——要求把 deno_core/V8 升级归类为 feat:、fix: 或 refactor:,并在标题中说明修复/新增的具体问题,而不是一句 fix: upgrade deno_core。PR 模板 .github/PULL_REQUEST_TEMPLATE.md 也给出了好/坏标题对照示例(如 fix(ext/net): fix race condition in TCP listener 为合格,fix #7123、update docs 为不合格)。
3. 禁止 force push
Deno 采用 squash-merge,贡献者应持续追加新提交而非重写历史。CLAUDE.md 的 Git workflow 一节对此有原文级说明:追加提交“allows reviewers to see the incremental changes you made in response to feedback”,评审人因此能看到针对反馈的增量修改。
4. 聚焦的改动范围
不允许夹带无关的顺手清理(drive-by cleanups),那些应拆到独立 PR。CLAUDE.md 同样规定 “Keep your changes minimal, don't do drive-by changes in a PR”。
5. AI 使用披露
如果 PR 疑似 AI 生成(模板化措辞过多、注释泛泛、改动范围可疑地广)但没有任何披露,应主动询问。仓库侧有硬性要求:PR 模板 .github/PULL_REQUEST_TEMPLATE.md 顶部注明 “If you used AI tools ... you MUST disclose it in the PR description. PRs will be rejected if there is suspicion of undisclosed AI usage.”——门禁 5 是对该模板条款的人工/Agent 复核。
6. 外部贡献者需关联 issue
若作者不是 denoland 组织成员,PR 必须链接到一个 issue;没有时应当 request changes,要求作者先开 issue 讨论方案。PR 模板第 2 条(“Ensure there is related issue and it is referenced in the PR text”)与此呼应。
四、Step 3:代码审查准则
文档要求“读遍 diff 中每一个被修改的文件”,并在需要时用仓库工具(Read、Grep、Glob)理解周边上下文。审查标准按语言与关注面分为四组。
Rust 代码
- 正确性:边界情况是否处理?对用户可控数据不能
.unwrap(); - 错误处理:合适的错误类型、有意义的错误消息、不吞掉错误;
- 性能:无不必要的分配/拷贝,async 代码中不阻塞;
- 安全性:无强理由不得
unsafe;杜绝命令注入、路径穿越、权限绕过; - 权限:新增能力必须走 Deno 的权限系统;要特别盯防
ext/node/——Node.js API 有时假设拥有完全访问权。权限系统的核心实现在 runtime/permissions.rs,这也是下一步“安全敏感区”列出的第一个文件; - 依赖:新增 Cargo 依赖必须有强理由,优先复用现有依赖或标准库。Deno 的 crate 划分(
cli/、runtime/、ext/、libs/)可在根 Cargo.toml 与 CLAUDE.md 的 “High Level Overview” 中对照理解。
JavaScript / TypeScript 代码
- Node.js 兼容性(
ext/node/):实现必须与 Node.js 的实际行为一致,需对照 Node.js 文档甚至源码,而不是“看起来对”; - Primordials:内部 JS 应使用 primordials(
globalThis.__bootstrap.primordials)以避免原型污染——对用户可控对象不得直接调用内置方法,必须经 primordial 包装。这在仓库中有完整的实现与执法链条:- libs/core/00_primordials.js 是 primordials 的源头实现,文件头注明其思路基于 Node.js 的同名内部模块,并按构造函数/迭代器等方式批量构造
ArrayPrototypeIncludes、SafeMap等安全引用,注释还提到“对性能有显著影响,应优先使用”; - tools/lint_plugins/prefer_primordials.ts 是
tools/lint.js专用的自定义 lint 插件,定义prefer-primordials规则并维护一份GLOBAL_TARGETS黑名单(JSON、Math、Array等全局),在runtime/与ext/的引导代码上强制该约定; - 实际用法可对照 ext/node/polyfills/01_require.js:其头部即从
ext:core/mod.js解构primordials并引入ArrayPrototypeIncludes、ObjectGetOwnPropertyDescriptor等安全引用,而非裸调Array.prototype.includes。
- libs/core/00_primordials.js 是 primordials 的源头实现,文件头注明其思路基于 Node.js 的同名内部模块,并按构造函数/迭代器等方式批量构造
- Web 标准:Web API 实现应遵循相应 spec,优先补充 WPT 覆盖(WPT 相关测试组织在
tests/wpt/); - 懒加载:所有代码应尽可能使用 lazy-loaded imports 以降低启动开销。
测试
- 每个 bug fix 都必须附一个“能抓到这个 bug”的测试;每个 feature 需要 happy-path + 边界用例;
- 测试层级优先级:单元测试 > spec 测试 > 集成测试,只有当行为必须依赖 CLI 级验证时才使用 spec 测试;
- Spec 测试位于
tests/specs/,以__test__.jsonc声明测试步骤;非确定性输出用[WILDCARD],顺序不确定的输出用[UNORDERED_START]/[UNORDERED_END]包裹; - 测试必须确定性:无竞态、无计时依赖、无端口冲突。
这部分规范在 CLAUDE.md 的 “spec tests” 章节有更详细的展开,包括 __test__.jsonc 的完整 schema(“tests” 对象、args/steps/output 字段)、期望文件 .out 的匹配语言([WILDCARD]、[WILDLINE]、[WILDCHAR]、[WILDCHARS(5)]、[UNORDERED_START]/[UNORDERED_END]、[# 注释]),以及测试目录划分(tests/specs/、tests/unit/、tests/integration/、tests/wpt/)。评审时可直接引用这些标准判断新增测试是否规范。
安全敏感区
文档列出的需加倍警惕的改动位置:
- runtime/permissions.rs 及散布各处的权限检查;
- ext/net/、ext/fs/ —— 网络与文件系统访问;
- ext/node/ —— Node 兼容层需要自己补权限检查(因为上游 API 假设完全访问);
- cli/tools/compile.rs —— 独立二进制(standalone binary)编译;
- 任何 shell 外呼或处理用户可控路径/URL 的代码。
五、Step 4:按 PR 类型的专项检查
在通用标准之上,文档要求识别 PR 类型并追加专项检查:
- Node.js 兼容(
ext/node/):必须对照 Node.js 文档/源码验证行为。新增 polyfill 必须注册进 ext/node/polyfills/01_require.js——从源码看,该文件是require机制的核心(3500+ 行),集中导入op_require_*系列 ops 并实现模块解析、CJS/ESM 判定等逻辑,新内置模块不在此注册就无法被require到; - 性能:必须附带改动前后的 benchmark 数据,或给出清晰的收益论证,同时警惕正确性回退;仓库在
cli/benches/、tests/bench/等目录维护基准,PR 模板还支持添加ci-bench标签在 CI 上跑基准; - 依赖更新:检查 changelog 中的破坏性变更,安全类更新优先处理;
- WPT 改动:确认“通过”是真通过而非断言被跳过;expectation 文件的更新必须与实际结果一致;若未打标签,建议补上
ci-wpt-test; - CI/发布工具:必须 @ 维护者
@bartlomieju审查,Agent 不得自行 approve。
六、Step 5:撰写评审意见
结构
文档规定评审意见固定分四段:
- Summary(1–2 句):PR 做了什么、总体评价;
- Gate issues(如有):必须修复的阻塞问题;
- Code comments:具体、可执行的反馈,指向精确的文件与行号;非阻塞建议用
nit:前缀;尽量给出修复方案而非仅说“这里错了”; - Verdict:approve / request changes / comment。
语气
- 直接:说 “This needs a test”,而不是 “It would be wonderful if we could add a test here.”;
- 友善:感谢贡献者,尤其首次贡献者,假定善意;
- 有帮助:拒绝时展示“好的版本”应该是什么样;
- 简洁:如果贡献者明显经验丰富,就长话短说。
提交评审
优先在具体行内联评论,一次 review 同时包含摘要正文与内联评论:
gh api repos/denoland/deno/pulls/{number}/reviews \
-f event=COMMENT \
-f body="summary" \
-f comments='[{"path":"file.rs","line":42,"body":"comment"}]'
结论为通过或要求修改时,将 event=COMMENT 换成 event=APPROVE 或 event=REQUEST_CHANGES。若无需内联评论的简单评审,退回 gh pr review $ARGUMENTS --comment --body "review text"。
合并就绪(Merge readiness)
Agent 没有合并权限。PR 就绪时按贡献者身份发不同评论:
- 首次贡献者:
@bartlomieju LGTM, needs maintainer signoff (first-time contributor); - 常规贡献者:
@bartlomieju this is ready to merge。
这解释了为什么 CI/发布类 PR 也要交给同一维护者把关——最终合并权集中在人工维护者一侧。
七、硬性规则(Rules)与能力边界
文档末尾列出 Agent 审查的不可越界项:
- 绝不 approve 一个 CI 失败的 PR;
- 绝不 approve 绕过权限系统的 PR;
- 大型架构变更必须在拉出给维护者讨论之后才能推进;
- 不要为 lint 已经放行的风格问题纠缠(bikeshed);
- 不要对自动化检查已强制的事项重复 request changes;
- 任何发布到 GitHub 的评审评论,必须先与用户确认——这是 Agent 侧的最后护栏,保证自动化审查不会产生未经授权的公开行为。
八、小结
.claude/skills/review-pr/SKILL.md 把 Deno 的社区贡献规范沉淀成了一条可执行的 Agent 流水线:它用 CLAUDE.md、tools/verify_pr_title.js、.github/PULL_REQUEST_TEMPLATE.md 等仓库内的既有约定作为事实来源,用 gh CLI 完成信息获取与评论发布,并用 libs/core/00_primordials.js、tools/lint_plugins/prefer_primordials.ts、runtime/permissions.rs 等核心源码作为审查深度的锚点。对读者而言,它既是理解 Deno 工程文化的窗口(标题规范、测试分层、primordials、权限优先、squash-merge 与集中式合并权),也是一份可直接借鉴的模板:如何把“项目价值观”翻译成 Agent 能逐步执行、且每步都有仓库证据支撑的审查清单。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00