Astro PR 写作规范技能:Changes / Testing / Docs 三段式结构与审阅者友好的 PR 标题
在 Astro monorepo 中向核心仓库提交代码时,一份审阅者(reviewer)能快速理解的 PR 描述与提交流程同等重要。本文基于 Astro 仓库中的仓库级 Agent 技能文档 .agents/skills/astro-pr-writer/SKILL.md,完整拆解该技能定义的 PR 标题规则、三段式正文结构、简洁性标准、Changeset 强制约束与提交前自检清单,并结合仓库中的技能评估配置(evals.json、vitest.skills.config.ts)说明这套规范如何被自动化验证。读完后你可以为任何 Astro 贡献者 PR 写出符合该仓库惯例、信噪比高的标题与描述正文。
1. 技能定位与触发场景
该技能是一个"仓库级技能"(repository skill),存放在 .agents/skills/astro-pr-writer/ 目录下,以 Markdown 文件加 YAML front matter 的形式定义,其元数据声明了名称(astro-pr-writer)与触发描述:
name: astro-pr-writer
description: Write and update Astro pull requests with reviewer-friendly titles and high-signal bodies. Trigger whenever the user asks to create a PR, open a PR, draft a PR, update PR title/body, or write PR notes/summary/description.
技能文档明确列出了所有应当激活该技能的 PR 写作任务,覆盖"从零起草"与"修订已有 PR"两种场景:
- 创建/打开一个 pull request;
- 创建/打开一个 draft pull request;
- 更新 PR 标题;
- 更新 PR 正文/描述;
- 撰写 PR notes / summary。
这类技能文件并非面向最终用户的文档,而是面向 AI Agent 的行为规范:当用户在 Astro 仓库上下文中提出 PR 写作请求时,Agent 按该文档的标题规则、正文模板与自检清单产出内容。仓库中同目录的 evals/evals.json 则为这些规范提供了可执行的验收用例(见第 7 节)。
2. 核心原则:讲清楚"改了什么、怎么改、为什么重要"
文档给出的核心原则(Core Principle)只有一句话:描述变更本身(change)、它的工作原理(how it works)以及它为什么重要(why it matters)。
在这条原则下,三段式正文各有严格分工:
Changes解释这个修复/功能做了什么(what the fix/feature does);Testing列出新增或修改了哪些测试代码(what test code was added or changed);Docs说明是否需要面向用户的文档变更(whether user-facing docs changes are needed)。
文档还特别强调一条反向约束:不要把 PR 的各小节当作任务日志来写(Do not use PR sections as a task log)。也就是说,正文不是"我今天做了 12 件事"的流水账,而是围绕行为变更组织的信息摘要。
3. PR 标题规则:用自然语言,禁用 conventional commit 前缀
标题必须"面向人、对审阅者友好",具体规则有三条:
- 用平实语言描述结果(Describe the outcome in plain language);
- 简洁且具体(Keep it concise and specific);
- 优先采用审阅队列中一个开发者会自然写出的措辞(Prefer phrasing a person would naturally write in a review queue)。
同时文档明确禁止两类 commit 风格标题:
- conventional commit 前缀,如
fix:、feat:、docs:; - 带 scope 的 commit 式标题,如
fix(cloudflare): ...。
这一规则在评估用例中得到了精确验证:evals.json 第 3 条用例给出的输入标题是 fix(examples): sort RSS posts,预期产出是一行纯文本、直接描述"blog RSS 条目按发布日期倒序排列"这一结果的标题,断言明确检查输出不得以 fix:、fix(、feat:、docs: 开头。
4. 正文模板:固定的三段式结构
技能文档给出了正文必须使用的标准模板(原文即如此,可原样复制使用):
## Changes
- <行为变更以及它为什么重要>
- <实现细节及其影响>
## Testing
- <新增/修改的测试及其覆盖点>
- <某条既有断言变更的原因>
## Docs
- <无需更新文档,因为……>
三个小节各有明确的"应包含 / 不应包含"清单,下面逐节展开。
4.1 Changes:聚焦行为、实现方式与影响
该小节聚焦行为(behavior)、实现思路(implementation approach)和影响(impact)。
应包含:
- 修复后"以前不工作、现在工作"的能力;
- 修复/功能的工作原理——以审阅者有用的颗粒度说明(reviewer-useful level);
- 面向用户的可靠性、兼容性或性能方面的行为变化。
不应包含:
- "added test"、"updated fixture" 之类内容——这些属于
Testing小节; - "added changeset"——这是流程噪音,不是行为变更;
- 没有行为影响的内部流程说明。
4.2 Testing:只描述测试代码的变化,不报告测试结果
审阅者阅读该小节的目的是了解测试覆盖面的变化,而不是"你跑过测试套件"这一事实。
应包含:
- 新增的测试文件或测试用例,并简短说明它们覆盖什么;
- 被更新的既有测试,以及断言为什么改变。
不应包含:
- "测试通过"之类的陈述——CI 会展示这一点,属于噪音;
- 你运行了哪些命令;
- 通过了多少个测试。
4.3 Docs:显式说明文档影响
文档影响必须被明确交代,二选一:
- 如果不需要文档更新,用一句话说明原因(例如"没有公共 API 或配置变更");
- 如果需要文档更新,链接对应的 docs PR。
5. 简洁性标准:30 秒读完原则
文档给出了量化目标:默认保持简短,每个小节 1~2 个 bullet 是常态,只有当变更确实复杂时才允许更多。检验标准是"一位扫视 PR 队列的审阅者应在 30 秒内读完典型 patch 的整个正文"。
为了校准"啰嗦"与"恰当"的边界,文档内置了一组对照示例,以一次 Zod 4.4.0 兼容性修复为例:
过于冗长的版本(Too verbose):
- Moves
.optional().prefault({})outsidez.preprocess()for theserverconfig property in bothbase.tsandrelative.ts, matching theintegrationsfix from #16531. Zod 4.4.0 rejects missing properties wrapped inz.preprocess()before the preprocessor or inner defaults can execute — moving.optional().prefault({})outside the preprocess call resolves this. Fixes theserverproperty issue reported there by @rururux.- Adds
invalid_key,invalid_element, and discriminated unionoptionshandlers to both Astro and DB error maps for Zod 4.4.0 compatibility. Zod 4.4.0 surfaces record key refinement failures (e.g. env schema variable names) as structuredinvalid_keyissues with nested errors instead of a flat message. The handlers extract the actual refinement message for clear user-facing errors.- All changes are backward-compatible with Zod 4.3.x. New error map branches only activate on issue codes that 4.4.0 starts emitting.
更好的版本(Better):
- Moves
.optional().prefault({})outsidez.preprocess()for theserverconfig, matching theintegrationsfix from #16531. Fixes the issue reported there by @rururux.- Adds
invalid_key,invalid_element, and discriminated unionoptionshandlers to both error maps for Zod 4.4.0 compat.- Backward-compatible with Zod 4.3.x.
对比可以看出精简手法:保留"改了什么 + 为什么 + 兼容性结论",删掉 Zod 内部机制的展开解释、重复的文件路径罗列和过程性细节。这与第 2 节"Changes 讲实现方式但控制在 reviewer-useful 颗粒度"的要求一致。
6. Changeset:改包必带的强制配套
技能文档规定:任何修改了 package 的 PR 都必须附带 changeset,仅 examples/* 的变更可以豁免。
写作 PR 正文时的配套要求:
- 发布前检查 changeset 是否存在;如果 PR 修改了 package 却没有 changeset,先创建再发布,不得在没有 changeset 的情况下提交 PR;
- 不要在
Changes小节中写"added changeset"——那是流程噪音。
创建 changeset 的具体操作由配套技能 .agents/skills/changeset/SKILL.md 承接,核心流程是:在仓库根目录运行 pnpm changeset --empty,它会在 .changeset/ 下创建一个随机命名的 .md 文件(含空 front matter),无需自拟文件名,再编辑该文件补充包版本声明与消息。文件格式为:
---
'<package-name>': patch
---
<changeset message>
要点包括:包名必须与对应 package.json 的 name 字段完全一致(如 'astro'、'@astrojs/node');bump 类型只能是 patch / minor / major;一个 changeset 文件可覆盖多个包;针对核心 astro 包的 major 和 minor bump 会被 CI 拦截,需要维护者审核。changeset 消息本身是公开的 CHANGELOG 条目,要面向 Astro 用户撰写,以现在时动词开头(Adds、Fixes、Refactors、Deprecates 等),patch 级一句话即可,new feature(minor)应给出 API 名称与代码示例,breaking change(major)必须包含迁移指引。
当前仓库中 .changeset/ 目录保留了可参考的真实样例,例如 .changeset/better-lines-show.md 声明 @astrojs/cloudflare 的 patch bump:"Fixes cold astro dev crashes by adding astro/app/manifest and @astrojs/cloudflare/cache/provider to the optimizeDeps.include list"——这正是"以用户可感知的行为影响开头"的写法。changeset 的仓库级配置见 .changeset/config.json:changelog 由 @changesets/changelog-github 生成(repo 为 withastro/astro),内部依赖默认以 patch 联动更新。根目录 package.json 中的脚本则体现了 changesets 在发布链路中的位置:release 脚本执行 changeset publish,version 脚本执行 changeset version 后同步示例项目版本号。
7. 提交前自检清单
技能文档定义了发布前必须核对的五条 Self-Check:
- 标题是审阅者友好风格(不是 commit 风格);
Changes的 bullet 描述的是行为/实现/影响;Testing列出的是新增/修改的测试代码,而不是测试运行结果;Docs的决策是显式的;- 凡是修改 package 的 PR,
.changeset/下都存在 changeset 文件——缺失就先创建再发布。
8. 规范的自动化验证:skills evals 机制
这套 PR 写作规范并不是"写出来就完事"的软文档,仓库为其配备了可执行的验收层:
- 评估清单存放在 .agents/skills/astro-pr-writer/evals/evals.json,包含 3 条隔离式评估用例。每条用例给定一段"变更上下文"(例如 trailing slash 重定向循环修复、
@astrojs/node新增gracefulShutdownTimeout选项、examples下的 RSS 排序修改),要求模型仅凭上下文产出标题和正文,并用一组断言逐条校验。以第 1 条为例,断言同时验证:标题不带fix:前缀且描述"阻止 trailing-slash 重定向循环";正文恰好包含## Changes、## Testing、## Docs三个二级标题且无多余 H2;Changes小节不超过两个 bullet、解释路径规范化与重定向循环的影响,但不提及测试文件、命令、通过数或 changeset;Testing小节点明回归用例却不出现pnpm、passed、18 tests等运行结果字样;Docs小节显式说明"公共 API 与配置未变,故无需文档更新"。这些断言与第 4~5 节的规则一一对应。 - 运行器配置为 vitest.skills.config.ts:以
.agents/evals/**/*.eval.ts为入口,禁用文件并行、单并发执行。 - 运行方式由 .agents/evals/README.md 说明:这些是"live-model 测试",与
pnpm test独立、不接入 CI(每条用例消耗模型 token 且可能非确定性)。根目录 package.json 提供两个脚本——pnpm eval:skills:validate可在不调用模型的情况下校验全部评估清单,pnpm eval:skills配合-t "astro-pr-writer"过滤运行单个技能。每条用例执行一次"受试模型 + 一次评审模型(judge)"的两段式判定,每次运行都在一个运行后删除的临时工作区中进行,并且 runner 在挂载技能资源时会排除 evals 清单本身,避免预期答案泄露给受试模型。
9. 小结
.agents/skills/astro-pr-writer/SKILL.md 用不到两百行的篇幅定义了一套完整、可验证的 Astro PR 写作契约:标题走自然语言、禁用 conventional commit 前缀;正文固定为 Changes / Testing / Docs 三段并各有"应写 / 不应写"边界;整体以 30 秒可读为简洁性目标;改包必附 changeset 且不得把"加了 changeset"写进正文;发布前过五问自检。配合 evals/evals.json 的断言式评估与仓库内真实的 .changeset/ 样例,这套规范既约束人的写作习惯,也能直接约束 Agent 的输出质量,是观察大型 monorepo 如何将"PR 描述规范"工程化、可测试化的一个具体样本。
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 StartedRust0623
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