mcpField
P
pr-and-issue-discipline

pr-and-issue-discipline

github.com/vivswan开发161 次安装1 天前更新
代码仓库

关于 pr-and-issue-discipline

pr-and-issue-discipline 是用于创建或更新拉取请求和问题的技能,面向变更作者,提供清晰展示变更、选择正文结构以及区分读者内容与工具细节的规则。

主要功能

  1. 01PR 标题和正文编写指导
  2. 02问题与错误报告规则
  3. 03以变更为中心的区块与正文结构
  4. 04面向读者内容的严格字数上限
  5. 05技术细节的折叠区段
  6. 06仓库模板选择流程

适用场景

  1. 01为代码或文档变更起草拉取请求
  2. 02撰写便于评估的问题报告
  3. 03发布前检查 PR 正文

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/vivswan/skills --skill pr-and-issue-discipline

安装后在 Claude Code 中输入/pr-and-issue-discipline确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

LICENSE.md
README.md
.codex-plugin/
plugin.json
agents/
openai.yaml
references/
redaction.md
release-please.md
shape-additive.md
shape-before-after.md
shape-contract.md
shape-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 中沿用:

  1. 在目标仓库中查找模板,不区分大小写和扩展名(.md、.txt 或无扩展名):仓库根目录、.github/ 和 docs/ 中的 pull_request_template* 和 PULL_REQUEST_TEMPLATE*,以及 .github/PULL_REQUEST_TEMPLATE/ 和 .github/ISSUE_TEMPLATE/。
  2. 未找到:直接采用以下结构。无需询问。
  3. 找到任意模板:用以下原话询问用户一次:“使用此仓库的模板,还是此技能的结构?”说明仓库名称、这是用户自己的仓库还是他人的仓库,并按文件名列出找到的模板。安装此技能的用户往往更偏好技能的结构,而第三方仓库的维护者通常更期待使用自己的模板,因此应先询问,不要擅自假设。
  4. 在本次会话的其余时间内,对其中的每个 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 个单词。规则如下:

  1. 对正文已有内容的修正,就地编辑对应的 ## How(或 ## Reasoning)或 ## Proof 项目符号。不要为同一内容再添加第二个项目符号。
  2. 变更中新增的事实(正文从未提及的机制或证明),只新增一行,并放在读者测试指引的区域。
  3. 数量(测试、关卡、行数)用最新总数覆盖。删除旧数字。
  4. 正文中不得提及内容来自哪一轮审阅。
  5. 更新 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 包含捕获的输出,上文的脱敏规则同样适用。

评论

支持 Markdown