关于 pr-and-issue-discipline
pr-and-issue-discipline 是用于创建或更新拉取请求和问题的技能,面向变更作者,提供清晰展示变更、选择正文结构以及区分读者内容与工具细节的规则。
主要功能
- 01PR 标题和正文编写指导
- 02问题与错误报告规则
- 03以变更为中心的区块与正文结构
- 04面向读者内容的严格字数上限
- 05技术细节的折叠区段
- 06仓库模板选择流程
适用场景
- 01为代码或文档变更起草拉取请求
- 02撰写便于评估的问题报告
- 03发布前检查 PR 正文
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ vivswan/ skills --skill pr-and-issue-discipline安装后在 Claude Code 中输入/pr-and-issue-discipline确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
LICENSE.mdREADME.md.codex-plugin/plugin.jsonagents/openai.yamlreferences/redaction.mdrelease-please.mdshape-additive.mdshape-before-after.mdshape-contract.mdshape-measured.md详细介绍
PR 和 Issue 规范
展示改动,不要描述改动:围栏代码块就是图片的文本形式,因此读者扫一眼就能看懂改动;先看流程,再看输出,各自放在发生变化的位置。之后只用最少的文字,并严格控制篇幅,采用适合这项改动的形式。为工具或其他 Agent 编写的内容,全部放在底部的单个折叠区块中。
这些规则适用于任何创建或更新 PR,或编写 Issue 的会话。下文中的“作者”指准备改动的人,无论是人还是 Agent,也无论是单人还是多 Agent 会话。PR 创建之后的事项(草稿状态切换、评审轮次、合并)由 /pr-landing-discipline 技能负责;他人发起的讨论(回复 Issue、评审他人的 PR)则由 /reply-and-review-discipline 技能负责。
适用时机
- 创建拉取请求,或编写、修改其正文或标题时
- 编写 Bug 报告或 Issue 时
- 将 PR 正文交给读者之前重新阅读时
所有 PR 都必须以草稿状态创建;之后由 /pr-landing-discipline 技能负责:草稿状态切换、跟进循环、合并人选以及合并前的门槛。
PR 正文:围绕改动展示内容
展示改动,而不是描述改动。PR 正文是文本,因此应以围栏代码块呈现其“图片”:展示流程和实际捕获的输出,各自放在发生变化的位置;对于无法运行的内容,则使用图示、表格或契约本身的形式。读者扫一眼这些区块,就能了解改动,无需阅读段落。正文形式应贴合改动;不要强迫所有 PR 都套用同一模板。
分为两部分。 第一部分供人快速浏览:展示改动(使用下列形式之一的开篇区块),然后用最少的文字说明。第二部分放在最底部,是默认折叠的单个折叠区块,用于放置为其他 Agent 或工具编写、而非供人阅读的内容:
<details>
<summary>Technical details</summary>
...
</details>
- 放入第二部分: 为 Copilot 等机器人评审者提供的评审指引、超出
## How范围的机制细节、已记录但未实现的事项和已接受偏差清单、超出## Proof总数的门槛细节、逐文件备注,以及符合所述用途的行数统计。 - 判断依据是读者,而非内容类型。 第一部分应包含人们了解或决定这项改动所需的一切;第二部分则包含其余内容。上面的清单只是默认分类,应逐项判断。评审意见若改变了改动的行为,或导致某项工作未完成,即使来自评审轮次,也应放在第一部分。
- 第一部分的内容不得依赖第二部分。 如果细节都能放进第一部分,PR 就不需要第二部分。
- 摘要行就是标题。 它受下文的可读性规则约束:“Technical details”只是内容名称。
篇幅预算。 第一部分有严格上限,发布前必须统计。项目符号数量为默认值:如果某项改动的机制需要 8 个项目符号,就用 8 个。第二部分没有长度上限,但必须遵守下文的格式规则。若 Agent 认为这项改动无法控制在上限内,必须在超出上限发布前询问用户,并提供字数统计和拟保留的行。应由用户决定,绝不能由 Agent 单独决定。
| 区域 | 预算 |
|---|---|
| 第一部分正文(围栏代码块之外的文字) | 最多 150 个词,严格上限;按测量型结构约为 200 个词 |
| 流程区块,展示流程变化之处 | 在 ## Before 和 ## After 下各放一个 ASCII 文本区块;或者在单个开篇区段下用一个区块同时展示两行,并置于输出之前。使用围栏,因此不计入正文词数 |
## How | 默认 3 到 6 个项目符号,每项一句,约 15 个词。也可使用一个小表格 |
## Proof | 默认 2 到 4 个项目符号,仅列最新总数 |
## Reasoning(测量型结构) | 3 到 4 个项目符号,每项一句,并以粗体引导语开头 |
## Results(测量型结构) | 一张包含指标前后对比的表格,以及一行页脚:评判者、运行次数、汇总方式 |
Technical details | 无长度上限。每行一项事实,每项一句 |
当差异添加、移动、接触、复用或依赖某类库(解析器、抓取器、重试循环,以及 /code-standards 技能的 references/design.md 所涵盖的其余类别)时,## How 中要多一条要点(按测量结果的形式,## Reasoning 的要点从 3 条增至 4 条):**Library:** <package>, covers <what> 或 **Library:** searched <where>; none fits because <reason>。如果没有这条内容,合并门禁会拒绝 PR(/pr-landing-discipline 技能)。 |
可读性是一项无障碍要求。 读者中有人吸收图片信息比阅读文字更快;一大堵文字会让他们无法处理 PR。/working-text 技能为所有页面规定的标准是:混合使用便于读者快速浏览的内容形式,并将细节放在简短段落中,供愿意阅读的读者查看。
这些规则同样适用于 PR 正文和 /reply-and-review-discipline 技能中的回复(该技能会指向这里,而不是重述这些规则):
- 段落、项目符号、表格和围栏代码块混合使用。 每种形式承载什么内容,由
/working-text技能的规则集决定(根据内容选择形式,列表使用项目符号,不做无益改动,以单调为信号重新分组,每个要点只用一种承载形式),并原样应用于 PR 正文。 - 页面结构也遵循该技能的规则。 段落和句子的长度、每条项目符号开头都加粗引导语、嵌套不超过一层,以及标题应说明内容而非读者的层级,这些都是
/working-text技能的结构规则,并原样应用于 PR 正文。正文包含多少个标题则由本技能决定,以下结构固定了标题数量,除非仓库自身的惯例另有规定。 - 不要用分号串联句子。 用分号连接分句,意味着把两句话硬塞进了一句话。请拆开。
- 改动由区块承载,文字只补充区块无法表达的内容。 上述默认结构适用于大多数改动。只有当这次改动确实需要时才超出默认结构,绝不要仅仅因为多了一轮就增加内容。
- 最后运行
/unslop(若已安装),检查剩余文字:在提交正文前先清除 AI 痕迹。
模板检查,每次会话一次,在计划阶段进行。 在会话中的第一个 PR 或 issue 之前,仍处于计划阶段时,确定一次选择,并在该会话中的每个 PR 和 issue 中沿用:
- 在目标仓库中查找模板,不区分大小写和扩展名(
.md、.txt或无扩展名):仓库根目录、.github/和docs/中的pull_request_template*和PULL_REQUEST_TEMPLATE*,以及.github/PULL_REQUEST_TEMPLATE/和.github/ISSUE_TEMPLATE/。 - 未找到:直接采用以下结构。无需询问。
- 找到任意模板:用以下原话询问用户一次:“使用此仓库的模板,还是此技能的结构?”说明仓库名称、这是用户自己的仓库还是他人的仓库,并按文件名列出找到的模板。安装此技能的用户往往更偏好技能的结构,而第三方仓库的维护者通常更期待使用自己的模板,因此应先询问,不要擅自假设。
- 在本次会话的其余时间内,对其中的每个 PR 和 issue 沿用用户的答复。若回答“此技能的结构”,则始终采用以下结构。若回答“此仓库的模板”,则根据每种产物的用途使用相应模板,不要再次询问;如果仓库没有某种产物的模板(例如只有 issue 模板而没有 PR 模板,或反之),则用以下结构补足。
无论选择哪种方式,仍须遵守仓库的 CONTRIBUTING 指引:在撰写的正文中遵循其关于标题惯例、必需章节和关联 issue 的规则。
仓库惯例决定标题和语气,不决定正文的可读性。 模板、“优先使用散文而非模板”的规则、“维护者语气”说明:这些都规定章节、必填字段和正式程度。读者没有改变,因此上述可读性规则仍适用于这些内容;区块和文字的比例应根据每篇正文判断,而一大堵文字永远不是答案。
结构
每种形状都是 references/ 下的一个文件。每个文件都是一份 PR 模板,水平分隔线以上包含标题、以 HTML 注释形式写出的形状规则(渲染正文时会消失)和占位符;分隔线以下是填写好的示例。根据变更的类型选择:
| 变更属于 | 形状 |
|---|---|
| 某个可运行的内容,其打印结果或执行路径发生了变化 | references/shape-before-after.md |
| 某个可运行的内容,但打印结果和执行路径都没有变化(纯重构) | 同一文件,以一个 ## What this changes 小节开头 |
| 在现有内容旁边新增某项内容 | references/shape-additive.md |
| 某项内容是供人阅读而非运行,其效果通过评估来衡量 | references/shape-measured.md |
| 一份契约或文档:没有内容可运行,也没有内容需要衡量 | references/shape-contract.md |
当变更既可运行又经过衡量时,优先选择经过衡量的形状:运行会展示一个字符串,评估会展示行为。新增内容如果也扩展了现有流程,则属于增量式;前后对比适用于对已有内容的变更。
这些行描述的是情形,而非文件类型。如果仍有两种形状都适用,请询问用户,并列出这两种形状;若无法询问用户,则自行判断,并在提交 PR 时说明所选形状。
如果仓库希望 GitHub 提供这些形状,可将每个文件中水平分隔线以上的部分复制到 .github/PULL_REQUEST_TEMPLATE/;分隔线以下是填写好的示例,不应包含在任何新 PR 中。上述模板检查会找到这些模板,而 gh pr create --template <file> 可用于选择其中一种。
适用于每种表单:
- 区块展示,文字说明。开头的区块是实际运行的流程,以及包含实际输出、足以独立理解的实际命令;只有变更确实改变了它们时才展示,绝不捏造输出,也不为了满足格式要求而添加区块。如果没有运行任何内容,区块就展示图示、表格或契约结构本身。对于形状有测量值的变更,
## Problem是唯一的文字开头。 - 每个状态内部先展示流程,再展示输出。在
## Before和## After下,流程区块排在输出区块之前,两者之间不插入文字。在一个开头章节(## What this adds、## What this specifies)中,before:和after:两行放在同一个区块里,位于输出或契约区块之前。 - 只有变更确实改变了内容时才添加相应区块:流程变了但输出未变,就只展示流程;输出变了但流程未变,就只展示输出。绝不添加区块或句子来说明没有变化,也不单独设置
## Pipeline章节。 - 流程使用纯 ASCII 文本区块表示,绝不使用 mermaid:步骤之间用箭头连接,分支单独缩进一行。After 流程必须反映代码当前的实际运行方式,并与 After 输出一样忠于事实。
## How默认包含 3 到 6 个项目符号;机制包含更多环节时可以增加。若小型表格能更快说明机制,可用一个表格替代,但绝不能重复展示流程。每个项目符号用一个句子,约 15 个词,并以粗体引导语开头。## Reasoning遵循相同的项目符号规则,包含 3 到 4 项。- 绝不针对每轮评审各写一段
## How。 ## Proof默认包含 2 到 4 个项目符号,列出有针对性的行为测试或稳定检查,并在有数字时注明最新总数。绝不按评审轮次逐行罗列(“第 3 轮:通过 20 项”“第 4 轮:通过 83 项”):新一轮运行会覆盖旧数字。不要把临时 CI、审批或评审状态写进去。- 面向程序员写作,说明改了什么、流程如何变化,并使用读者熟悉的技术术语,遵循下方的可读性规则。
- 差异内容承载具体细节。第一部分绝不叙述实现过程、删减历史、临时状态、未来工作或完整差异。只有行数与所述目的相矛盾时才提及行数;此时须按
/pr-landing-discipline技能的行数统计规则说明时机,并解释原因。 - 评审者指引放在第二部分,或完全不写。不要提评审轮数。范围限制说明应遵循读者测试:若读者必须据此采取行动,或不说明就会产生误解,则放在第一部分;否则放在第二部分。
Technical details 是事实清单,不限长度。 面向机器人评审者或接手任务的下一个 Agent,同时也让有意阅读它的人类读者能够看懂。所需事实有多少就写多少,并确保每一行都可以单独略过:
- 每行一个事实,每行一个句子。 如果一行需要第二个句子,就拆成两个事实。
- 保护条件和拒绝项列表使用统一格式:
**Refused: \--flag`.** one-clause reason`。 - 文件各占一行, 并用花括号分组:
scripts/{sweep.mts,probe.mts}、tests/skills/orchestrator-mode/sweep.test.ts。 - 不写轮数,不叙述过程。 “Copilot 第四轮”和“codex 第二轮”描述的是会话,不是变更。保留事实,删去它来自哪一轮的信息。
- 不重复第一部分已经说明的内容。 details 章节若复述
## How,只会让正文篇幅翻倍,对读者毫无帮助。
发布前须对捕获的输出进行脱敏,且任何地方都不得发布 PII:发布内容不能透露作者身份、工作方式或机器配置。定义以 references/redaction.md 为准,其中说明要删除的内容、PII 的范围、替代内容、脱敏方式以及需要保留的内容。
标题的类型表示行为变更,绝不表示差异的形式。 只要用户或集成方可观察到任何变化,类型就应是可见类型(fix、feat、perf、revert),即使工作最初是重构,或者大部分只是移动代码。refactor 表示所有现有预期仍然成立(可以重组测试,但不能改变测试预期),且没有任何可观察到的变化。
release-please 等变更日志工具会列出这些类型并隐藏 refactor,因此在这类仓库中,标记为 refactor 的修复会从发布说明中消失。
release-please 会读取正文。 在使用 release-please 发布的仓库中,Conventional Commit 页脚(BREAKING CHANGE、Release-As)会作为提交覆盖块放在 PR 正文里,位于 Technical details 部分的最后。release-please 会解析该块,而不是 squash 消息。
- 正文其他位置不得出现这些标记词。
- 每个提交只能有一条
BREAKING CHANGE说明: 多项不兼容变更共用一个多行页脚,每项各占一行;或者每项各用一个嵌套提交块。 - 错误的块通过编辑已合并的正文修复。
- 块的格式、各条规则的缘由以及修复方法:
references/release-please.md。
通过 stdin 将正文交给 gh,绝不要使用可被猜中的文件。 曾以 /tmp/<repo>-pr-body.md 为路径起草正文:同一台机器上的两个会话选中了相同的名称,后一个覆盖了前一个。gh pr create 和 gh pr edit 接受 - 作为正文文件并读取 stdin,因此带引号的 heredoc 可以传递正文,无需担心文件发生竞争或后续清理:
gh pr create --draft --title "<type(scope): subject>" --body-file - <<'EOF'
## What this changes
...
EOF
当沙盒拒绝 heredoc 时(Agent 工作树可能会拒绝包含 git 命令的文本,捕获输出通常也会导致拒绝),请将正文暂存到由 mktemp 创建的目录中,使用它打印出的字面路径,并且每一步只运行一条普通命令。相同的沙盒也会拒绝 trap,或拒绝将变量串接到发布命令中,因此删除操作必须作为最后一条独立命令运行,无论 gh 返回什么结果:
mktemp -d /tmp/pr-body-XXXXXX # 1. prints e.g. /tmp/pr-body-Kq3mZp; copy the printed path by hand
# 2. write the body to /tmp/pr-body-Kq3mZp/body.md with the harness's file-writing tool
gh pr create --draft --title "<type(scope): subject>" --body-file /tmp/pr-body-Kq3mZp/body.md # 3. one command
rm -rf /tmp/pr-body-Kq3mZp # 4. its own command, whatever gh returned
在用户阅读前重新审读
PR 正文在 PR 打开时撰写,在 PR 提交审阅时阅读;期间差异可能发生变化。两个关卡确保正文易读:每轮审阅后一次,提交前一次。
每轮审阅后:就地编辑,绝不追加。 有一份正文因为十二轮审阅每轮都新增一个 ## How 段落和一行 ## Proof,最终膨胀到 1,800 个单词。规则如下:
- 对正文已有内容的修正,就地编辑对应的
## How(或## Reasoning)或## Proof项目符号。不要为同一内容再添加第二个项目符号。 - 变更中新增的事实(正文从未提及的机制或证明),只新增一行,并放在读者测试指引的区域。
- 数量(测试、关卡、行数)用最新总数覆盖。删除旧数字。
- 正文中不得提及内容来自哪一轮审阅。
- 更新 PR 正文前,先运行下方的大小检查。超出上限时,先重新删减。
提交前(切换为就绪状态、报告“ready to merge”时),以未旁观整个过程的读者视角,对照最终差异重新审读正文。检查力度取决于 PR 变化幅度:只有一个提交的 PR,只需核对 Proof 中的数字;经过八轮审阅的 PR,则要重新核对每一项声明。先运行大小检查,再检查偏差清单:
# Part-one prose: words outside fenced blocks and HTML comments, above the <details> tag. Cap: 150, or 200 for the measured shape (set cap= below).
# Pipe the CANDIDATE body in through a quoted heredoc: the text about to be published, every round and before the first publish.
# `gh pr view "$n" --json body -q .body |` replaces the heredoc only for the final pre-offer read of what is already published.
# Never point awk at a file name, and keep pipefail on: a missing file or a failed gh read must stop the gate, not count as 0.
set -o pipefail
awk '
h { if (!/-->/) next; sub(/^([^-]|-[^-]|--[^>])*-->/, ""); h = 0 } # inside an HTML comment: fence markers are comment text; prose after the first closer counts
/^(```|~~~)/ { match($0, /^(`+|~+)/); d = substr($0, 1, 1)
if (!f) { f = 1; c = d; n = RLENGTH; next } # opening fence: remember its character and length
if (d == c && RLENGTH >= n && /^(`+|~+) *$/) { f = 0 } # closing fence: same character, at least as long, nothing else
next }
!f { gsub(//, ""); if (/<!--/) { sub(/<!--.*/, ""); h = 1 } } # HTML comments (template instructions) are not prose; the text around them is
!f && /^<details>/ { exit } # part two starts at a real tag, never one inside a fence
!f' <<'EOF' | awk -v cap=150 '{ for (i = 1; i <= NF; i++) if ($i ~ /[[:alnum:]]/) n++ } END { print n + 0; exit (n > cap) }' # counts tokens with a letter or digit, so `##`, `-`, and `|` are not words; exits 1 over the cap
<the candidate body>
EOF
超出上限就删减,而不是辩解。把细节移至第二部分(那里有足够空间),或删掉差异中已有的内容。如果删减会导致读者失去必须了解的信息,就停下来,向用户说明字数以及建议删减的行。是否超出上限发布,由用户决定。常见的偏差包括:
- 所有声明仍然属实。 开头各段仍准确(After 流程和 After 输出反映当前代码的行为),Proof 和 Results 中的数字是最终运行结果,每个被称为当前存在的文件也仍以该名称存在。
- 遗漏了已变化的方面,或写入了未变化的方面。 如果变更改变了某个状态,状态部分却没有说明流程;或者变更改变了输出,状态部分却没有说明输出,这都未通过重新审读;同样,如果某个方面并未变化,却有对应段落,也未通过。切换状态前修正。
- 范围偏差。 正文应包含审阅轮次中新增或移除的工作,或者明确有意不写。
- 内容排序。 第一部分包含读者了解当前变更所需的信息。变成细节的内容移至后面;变得重要的内容(改变变更内容的审阅发现、与目的矛盾的行数)移至前面。
- 标题。 类型和主题应描述最终落地的内容,而非最初计划;类型遵循上文的行为规则(只要任何可观察行为发生变化,就应使用可见的类型,绝不使用
refactor)。 - 篇幅。 第一部分不得超过上限(150 个单词;按当前结构测量时约为 200 个),且不得用分号连接两个分句。
## How(或## Reasoning)和## Proof应保持默认长度,除非此次变更需要更多内容。
正文不再匹配实际情况,或不再符合篇幅要求,就应在切换状态前编辑,绝不能等读者发现后再改。
Issues:同一原则
先展示故障,再提供最低限度的相关内容,并遵循上述可读性规则。
在上文规划阶段确定的本次会话模板答案也适用于 Issues:填写所选 issue 模板的字段,并在字段内遵循此原则;如果答案采用了该技能提供的结构,或不存在模板,则使用下方结构。
## What breaks
```text
$ npx skills add example-org/skills --skill some-skill
installed: SKILL.md, README.md (metadata.json silently missing)
```
## Repro
1. Add a `metadata.json` inside any skill folder.
2. Install with `npx skills add`.
## Expected vs actual
- **Expected:** every file in the skill folder installed
- **Actual:** `metadata.json` dropped without a warning
只有在环境信息重要时才写入:特定版本的解析器错误应注明版本,纯逻辑错误则不必。如果 issue 包含捕获的输出,上文的脱敏规则同样适用。