get-shit-done 自定义 PR Body 章节详解:用 `ship.pr_body_sections` 为 `/gsd-ship` 追加 PRD 级发布上下文
导读
get-shit-done(GSD)在阶段验证通过后,会由 /gsd-ship 依据规划工件(planning artifacts)自动生成拉取请求(PR)正文。默认正文固定包含 Summary、Changes、Requirements Addressed、Verification、Key Decisions 五段核心内容,但很多项目还需要在 PR 上携带用户故事、验收标准、风险、发布标准或干系人审批等更完整的发布上下文。本文基于 docs/ship-pr-body-sections.md 讲解 ship.pr_body_sections 配置项的字段语义、接入方式与校验规则,并结合 ship 工作流、配置校验实现 与回归测试,让你能够在不修改 GSD 内置 ship 工作流的前提下,为每次发布的 PR 生成可追踪、可审批的 PRD 式增量说明。
为什么需要自定义 PR Body 章节
GSD 的 phase → execute → verify → ship 闭环中,/gsd-ship 会从 ROADMAP.md、SUMMARY.md、VERIFICATION.md、STATE.md 等规划工件自动组装 PR 正文。这套默认正文覆盖了“做了什么、改了哪些文件、验证了什么、关键决策是什么”,但它刻意保持核心结构不可配置——团队不应因为个别项目的特殊需求而随意改动内置 ship 工作流。
实际问题在于:面向用户的功能增量往往还需要「用户故事与验收标准」「风险与依赖」「成功指标与发布标准」「干系人审批记录」这类 PRD 风格信息。这些内容有两个共性:
- 必须随 PR 一起发布,供审查者与审批者阅读;
- 内容来源分散在既有规划工件中(需求文档的 User Stories、计划文档的 Risks、验证文档的 Release Criteria),重复手写成本高且容易与工件脱节。
ship.pr_body_sections 正是为解决这一矛盾设计的纯配置扩展点:它以「源头引用 + 兜底文本」的方式,把规划工件中的章节自动抽取进 PR 正文,全程不需要触碰 get-shit-done/workflows/ship.md。
GSD 内置的固定 PR 正文结构
无论是否配置自定义章节,/gsd-ship 生成的每一份 PR 正文都必然包含以下五段核心章节:
Summary—— 来自ROADMAP.md的阶段目标与SUMMARY.md的完成综述;Changes—— 逐 Plan 列出 one-liner 与关键文件(key-files.created/key-files.modified);Requirements Addressed—— Plan frontmatter 中的 REQ-ID,链接到REQUIREMENTS.md的条目描述;Verification——VERIFICATION.md中自动化验证与人工验证项的勾选清单;Key Decisions——STATE.md中累积的与本阶段相关的决策。
在 get-shit-done/workflows/ship.md 的 generate_pr_body 步骤中,这五段依次拼接完成之后,才会进入第 7 步「Configured project sections」——通过 gsd-sdk query config-get ship.pr_body_sections --default '[]' 读取配置并追加渲染。因此自定义章节具有严格的追加语义(append-only):
- 渲染位置固定在
Key Decisions之后; - 不能替换、删除或重排任何内置核心章节。
这一点同样被回归测试显式锁定:测试断言 ship 工作流文本中包含 append-only、cannot replace 以及五段核心标题按序出现(见 feat-3167-ship-pr-body-sections.test.cjs)。
方式一:在 /gsd-new-project 引导阶段选配
ship.pr_body_sections 是引导期扩展点(onboarding-time extension point)。执行 /gsd-new-project 时,GSD 会询问是否需要让 /gsd-ship 在生成的 PR 正文末尾追加可选的 PRD 风格章节,并推荐以下四个选项:
| 推荐选项 | 用途 | 建议 content source |
|---|---|---|
User Stories & Acceptance Criteria |
面向用户的用户故事与验收检查 | REQUIREMENTS.md 下的用户故事与验收标准 |
Risks & Dependencies |
发布风险、依赖与回滚说明 | PLAN.md 下的 Risks / Dependencies |
Success Metrics & Release Criteria |
可度量的 Done 定义与发布检查 | REQUIREMENTS.md 的 Definition of Done、VERIFICATION.md 的 Release Criteria |
Stakeholder Review & Approval |
需要签核追溯的项目审批记录 | 模板文本(如 {phase_name} 审批待办) |
实现细节见 get-shit-done/workflows/new-project.md 中 PR body onboarding 的步骤描述:
- 被选中的章节写入
.planning/config.json时"enabled": true; - 未被选中的章节也会被播种进去,但
"enabled": false——这样项目后续只需改一个布尔值即可启用,完全不需要重新编辑/gsd-ship工作流或重跑引导; - 如果用户一项都不选,则写入
"ship": { "pr_body_sections": [] }。
引导阶段最终通过 gsd-sdk query config-new-project '{"mode":"...",...,"ship":{"pr_body_sections":[...]}}' 一次性写入完整配置。
方式二:手动配置(CLI 或直接编辑 JSON)
对于已存在的项目,可通过 SDK 查询命令写入:
gsd-sdk query config-set ship.pr_body_sections '[{"heading":"Risks & Dependencies","enabled":true,"source":"PLAN.md ## Risks || PLAN.md ## Dependencies","fallback":"- No known high-risk rollout dependencies."}]'
也可以直接编辑项目根目录下的 .planning/config.json,一个完整的三段配置示例:
{
"ship": {
"pr_body_sections": [
{
"heading": "User Stories & Acceptance Criteria",
"enabled": true,
"source": "REQUIREMENTS.md ## User Stories || REQUIREMENTS.md ## Acceptance Criteria",
"fallback": "- Acceptance criteria are covered by the linked requirements and verification evidence."
},
{
"heading": "Risks & Dependencies",
"enabled": true,
"source": "PLAN.md ## Risks || PLAN.md ## Dependencies",
"fallback": "- No known high-risk rollout dependencies."
},
{
"heading": "Stakeholder Review & Approval",
"enabled": false,
"template": "- Product owner approval pending for {phase_name}."
}
]
}
}
需要注意,配置存放在项目的 .planning/config.json 中,由 sdk/src/config.ts 的 loadConfig 负责读取并与默认值合并;其中 ship: { pr_body_sections: [] } 是声明的默认形状(见 sdk/src/config.ts),默认模板文件中同样体现为空数组(get-shit-done/templates/config.json)。
Section 字段语义与校验规则
每个章节是一个 JSON 对象,支持如下字段:
| 字段 | 是否必填 | 说明 |
|---|---|---|
heading |
是 | 渲染为 Markdown ## {heading}。必须为单行文本,不能包含换行 |
enabled |
否 | 默认 true。设为 false 表示保留在配置中但不渲染 |
source |
否 | 规划工件标题的兜底选择链(fallback chain),命中后整段拷贝进 PR 正文 |
template |
否 | 字面量 Markdown,支持一组封闭的 token(见下文) |
fallback |
否 | 当 source 未找到内容且没有 template 时使用的字面量 Markdown |
每个 section 必须至少提供 source、template、fallback 三者之一,否则配置会被校验拒绝。
这些规则在 get-shit-done/bin/lib/config.cjs 的 validateShipPrBodySections 中有完整的代码级落地:
- 顶层必须是 JSON 数组,否则报
Expected a JSON array of section objects; - 每项必须是对象,且只允许预定义的字段白名单
SHIP_PR_BODY_SECTION_KEYS,出现未知字段即拒绝; heading必须是非空字符串,且通过/[\r\n]/检测禁止换行;enabled出现时必须为布尔值true/false,字符串"true"/"yes"会被拒绝;source/fallback/template若出现则必须是字符串;- 三者至少一个为非空字符串;
source的每个选择器都必须匹配SHIP_PR_BODY_SOURCE_RE:即以允许的工件文件开头、后跟##和标题文本。
违规时配置写入会整体失败,而不是部分生效——测试验证了畸形值不会写进 .planning/config.json(见 feat-3167-ship-pr-body-sections.test.cjs)。
Source 选择器:从规划工件抽取章节
source 指向规划工件中的标题,使用 || 提供逐级兜底:
REQUIREMENTS.md ## User Stories || REQUIREMENTS.md ## Acceptance Criteria
语义为:先从 REQUIREMENTS.md 的 ## User Stories 找内容,若为空则尝试 ## Acceptance Criteria,再不行才轮到 fallback。
允许作为 source 的工件文件(白名单,配置校验的正则即来源于此):
ROADMAP.mdPLAN.mdSUMMARY.mdVERIFICATION.mdSTATE.mdREQUIREMENTS.mdCONTEXT.md
这条白名单意味着 source 不可能引用 package.json、任意 .txt 或其他未经允许的文件——回归测试专门用 package.json ## Scripts 验证了这一点会被拒绝(见 feat-3167-ship-pr-body-sections.test.cjs)。从源码结构可以推断,这一限制是为了让 PR 正文始终可追溯到官方规划工件,避免引入无结构、易过期的内容源。
当所有选择器均未命中、而 template 与 fallback 也都不存在时,该 section 的最终正文为空,会在渲染后整体省略。
Template Token:受控的占位符命名空间
template 字段是字面量 Markdown,但出于安全与可预测性考虑,只支持以下 5 个 token:
{phase_number}{phase_name}{phase_dir}{base_branch}{padded_phase}
其余任何 {...} 形式——包括环境变量、shell 展开、项目自定义 token——都会被配置校验显式拒绝。校验实现遍历 template 中全部 \{([a-zA-Z][a-zA-Z0-9_]*)\} 匹配项,凡不在白名单内即报 Unsupported template token(见 get-shit-done/bin/lib/config.cjs)。
设计意图明确:封闭 token 命名空间可以避免意外的 prompt 注入或 shell 展开,保证 PR 正文生成过程的确定性。这些 token 的实际取值在 ship 流程初始化阶段已就绪——init.phase-op 会返回 phase_number、phase_name、padded_phase、phase_dir 等字段,base_branch 则由 config-get git.base_branch 或远端默认分支解析而来(见 get-shit-done/workflows/ship.md 的 initialize 步骤)。
典型用法示例:
{
"heading": "Stakeholder Review & Approval",
"enabled": true,
"template": "- Product owner approval pending for {phase_name}."
}
精益 Agile PRD 实战配置
对于需要「轻量 agile PRD 轨迹」的团队,推荐把章节映射到本次增量(increment)本身,让 PR 正文成为可直接使用的发布工件。下面是两个开箱即用的完整示例:
示例 1:用户故事与验收标准
{
"heading": "User Stories & Acceptance Criteria",
"enabled": true,
"source": "REQUIREMENTS.md ## User Stories || REQUIREMENTS.md ## Acceptance Criteria",
"fallback": "- Acceptance criteria are covered by the linked requirements and verification evidence."
}
示例 2:成功指标与发布标准
{
"heading": "Success Metrics & Release Criteria",
"enabled": true,
"source": "REQUIREMENTS.md ## Definition of Done || VERIFICATION.md ## Release Criteria",
"fallback": "- Release when automated verification and required manual checks pass."
}
这两个 section 组合的效果是:PR 正文在保持核心五段简洁可审的同时,把「功能增量从用户视角是什么、完成标准是什么、何时可以发布」的 Done 语义显式化。审查者不必翻阅整个工作区即可完成评审,而每一步都能向上追溯到需求与验证证据——这正是它被称为 release artifact 的原因。
生成与创建流程中的实际位置
自定义章节的真正落点可从 get-shit-done/workflows/ship.md 的生成链路确认:
- 五段内置章节按序拼接成
PR_BODY; - 通过
gsd-sdk query config-get ship.pr_body_sections --default '[]'读取配置(读取失败时安全回退到空数组,保证无配置项目不受影响); - 对每个
enabled !== false的 section 解析 source / template / fallback 并追加到正文末尾; - 若某 section 渲染后 trim 为空则省略;
- 把完整正文写入临时文件(
mktemp .../gsd-pr-body.XXXXXX.md)后执行gh pr create --body-file,以避免超大 PRD 段落撞上 shell 参数长度限制。
其中「用 --body-file 而非 --body」是关键工程细节:大段 PRD 内容可能超过命令行参数上限,而文件方式不受此约束;trap 保证临时文件在流程结束或异常时自动清理。
Troubleshooting:常见问题排查
ship.pr_body_sections 配置被拒绝
按以下清单逐项核验配置值:
- 必须是 JSON 数组(
[...]),不能是单个对象; - 每项的
heading是单行非空字符串; enabled必须是布尔值true或false,不能是字符串(如"true"、"yes");- 每项至少包含
source、template、fallback三者之一; - 只允许
heading、enabled、source、template、fallback这些受支持字段,其余字段名会被整体拒绝; source中的每个选择器必须是「白名单工件文件 +##+ 标题」的合法形式。
某个 section 没有出现在 PR 正文中
按顺序检查这些条件:
enabled不是false(配置了false的章节会被跳过,且不产生警告——这是为引导期预置预留的预期行为);- 所选
source标题确实存在于对应允许的工件中; - 当 source 内容可能缺失时,该 section 提供了
fallback或template; - 渲染后的正文 trim 后不为空——空正文的 section 会被省略。
template token 被拒绝
只使用上文列出的 5 个受支持 token。任意环境变量(如 $HOME、${VAR})、shell 替换与项目自定义 token 都刻意不支持,配置校验会直接报错,这正是为了把 PR 正文生成约束在可控范围内。
小结
ship.pr_body_sections 是 GSD 面向真实发布协作设计的纯配置、可追溯的 PR 正文扩展机制:
- 零侵入:不修改任何内置 ship 工作流,仅在核心五段之后追加内容;
- 来源可溯源:章节内容优先从
ROADMAP.md、PLAN.md、REQUIREMENTS.md、VERIFICATION.md等官方工件抽取,配以fallback兜底,杜绝无源文本; - 封闭与安全:字段白名单、工件白名单、token 白名单三层校验全部落在 get-shit-done/bin/lib/config.cjs 的
validateShipPrBodySections中,由 feat-3167-ship-pr-body-sections.test.cjs 全程守护; - 引导友好:
/gsd-new-project可一次播种四个 PRD 风格章节并以enabled开关控制,项目生命周期内随时启用,无需重跑引导。
如果你正在管理一个需要用户故事、审批签核或发布标准随代码一起评审的仓库,为 .planning/config.json 补上 ship.pr_body_sections,是最低成本的发布工件增强路径。相关完整工作流实现可继续查阅 ship 工作流、new-project 引导 以及 SDK 配置模块。
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 StartedRust0629
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python07
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00