write-pr

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

写 PR 描述

Writing a PR Description

为当前分支创建或更新 PR,描述要让 reviewer 明白这个改动为什么存在、实现长什么样、现有用户会失去什么。
Create or update a PR for the current branch. The description should help reviewers understand why this change exists, what the implementation looks like, and what existing users will lose.

工作流

Workflow

  1. 读 PR 模板:
    Read(.github/pull_request_template.md)
  2. 找到或创建 PR:
    • 先查当前分支有没有 PR:
      gh pr view --json url,number,title,state 2>/dev/null
      。
    • 没有的话,看
      git status --short --branch
      和当前分支上的提交。
    • 提交剩余改动,带 upstream 推送分支,用
      gh pr create
      创建 PR。
    • 遵守仓库的 git 安全规范。
  3. 收集解释改动所需的上下文:
    • 读关联的 issue 和相关任务产物。
    • 读完整 diff(
      git diff main...HEAD
      )和足够的周边代码,理解行为与归属。
    • PR 已存在时,用
      gh pr view
      拿元数据和改动文件列表。
  4. 按模板各节写描述。描述用用户当前使用的语言,行为变化表也一样;只有三样固定:PR 标题保持英文 Conventional Commit,changeset 保持英文(见
    gen-changesets
    skill),节标题沿用模板原文。
    • Requirement or Bug:一句话,或
      Resolve #<number>
      。不要多写。
    • Bug Reproduction Steps:只有 bug 类 PR 需要;feature 写
      N/A
      。步骤已在 issue 里的写
      See linked issue
      。
    • Root Cause:只有 bug 类 PR 需要;feature 写
      N/A
      。说明根因,以及这是根本修复还是绕过。
    • Code Changes:能用可视化大纲说清楚的就不要写散文,见"代码变更的可视化大纲"。
    • Behavior Changes and Affected Users:先填行为变化表,再列受影响模块与测试覆盖,见"行为变化与受影响人群"。
    • Checklist:勾上所有适用的项。
  5. 发布描述:
    • 先存到临时文件,再
      gh pr edit <number> --body-file <path>
      或
      gh pr create --body-file <path>
      。
    • 确认更新成功。
  1. Read the PR template:
    Read(.github/pull_request_template.md)
  2. Find or create the PR:
    • First check whether the current branch has a PR:
      gh pr view --json url,number,title,state 2>/dev/null
      .
    • If not, check
      git status --short --branch
      and the commits on the current branch.
    • Commit the remaining changes, push the branch with upstream tracking, and create the PR with
      gh pr create
      .
    • Follow the repository's Git safety conventions.
  3. Gather the context needed to explain the change:
    • Read the linked issue and relevant task artifacts.
    • Read the full diff (
      git diff main...HEAD
      ) and enough surrounding code to understand the behavior and ownership boundaries.
    • If the PR already exists, use
      gh pr view
      to get its metadata and the list of changed files.
  4. Write the description section by section according to the template. Use the language the user is currently using for both the description and the behavior-change table. Only three things are fixed: the PR title must remain in English and follow Conventional Commit, the changeset must remain in English (see the
    gen-changesets
    skill), and section headings must retain the template's original wording.
    • Requirement or Bug: One sentence, or
      Resolve #<number>
      . Do not write more.
    • Bug Reproduction Steps: Only needed for bug PRs; write
      N/A
      for a feature. If the steps are already in the issue, write
      See linked issue
      .
    • Root Cause: Only needed for bug PRs; write
      N/A
      for a feature. Explain the root cause and whether this is a fundamental fix or a workaround.
    • Code Changes: If a visual outline can explain it clearly, do not write prose; see "Visual Outline of Code Changes".
    • Behavior Changes and Affected Users: Fill in the behavior-change table first, then list the affected modules and test coverage; see "Behavior Changes and Affected Users".
    • Checklist: Check all applicable items.
  5. Publish the description:
    • Save it to a temporary file first, then use
      gh pr edit <number> --body-file <path>
      or
      gh pr create --body-file <path>
      .
    • Confirm the update succeeded.

行为变化与受影响人群

Behavior Changes and Affected Users

这一节回答一个问题:合入之后,现有用户会失去什么。这个仓库过去的回归大多来自没人回答这个问题,而不是逻辑错误。
判据:改动前能工作的任何输入(配置键、环境变量、命令行参数、provider 响应形态、旧版本写的会话数据、客户端请求、hook 载荷)改动后必须行为不变,除非这里明确声明了变化并给出退路。
写法:
  1. 列出 diff 改变的每一个可观测行为,一行一个。包括你认为"不变"但分支条件挪动了的:新增的条件会不会先于旧条件命中既有输入;删除或收窄的分支改动前谁在走。内部包会打进 CLI 发布包,"内部"不等于用户无感。表格用 PR 描述的语言,下面的示例用英文只是示意形状:
    BehaviorBeforeAfterWho relies on the old behaviorEscape hatch
    reasoning parsing when
    reasoning_details
    is an array
    string
    reasoning
    also read
    string ignoredOpenAI-compatible gateways that send both (OpenRouter dialect)none
  2. 人群要具名,不要写"部分用户"。从
    .agents/skills/review-pr/surfaces.md
    里取:客户端(TUI、print 模式、desktop 与 web、VS Code、ACP、SDK)、provider 方言、平台、配置状态、数据年代、外部脚本。
  3. 改了 prompt 文本(system prompt、工具描述、提醒)的,每一句单独成行,写清这句改动前约束了什么行为、谁依赖、现在由什么来约束。"没有测试引用这句"不是无影响的证据。
  4. 替换或绕过旧路径的(移植、runtime binding、协议替换),额外列出旧路径的功能清单:它认哪些环境变量、有哪些兜底、接受哪些输入,以及每一项在新路径里的位置。
  5. 确实没有可观测变化的,写
    None
    ,并说明证据:哪些分支、默认值、契约文件没动。
  6. 表后面列受影响模块与每一行对应的测试覆盖。默认翻转或删除行为的,必须有一条测试把未被改动的人群的旧行为钉住,并且 changeset 要写明用户失去了什么,见
    gen-changesets
    skill;没有退路的,在 PR 里请维护者显式拍板。
This section answers one question: after the change is merged, what will existing users lose? Most regressions in this repository have come from no one answering this question, rather than from logic errors.
Criterion: Any input that worked before the change (configuration keys, environment variables, command-line arguments, provider response shapes, session data written by older versions, client requests, hook payloads) must behave identically after the change, unless the change is explicitly declared here and an escape hatch is provided.
How to write it:
  1. List every observable behavior changed by the diff, one behavior per line. Include behaviors you consider "unchanged" but whose branch conditions have shifted: whether new conditions will match existing inputs before the old conditions do, and who was taking the removed or narrowed branches before the change. Internal packages are bundled into CLI release packages, so "internal" does not mean that users are unaffected. Use the PR description's language for the table; the example below uses English only to illustrate the shape:
    BehaviorBeforeAfterWho relies on the old behaviorEscape hatch
    reasoning parsing when
    reasoning_details
    is an array
    string
    reasoning
    also read
    string ignoredOpenAI-compatible gateways that send both (OpenRouter dialect)none
  2. Name the affected groups; do not write "some users". Take them from
    .agents/skills/review-pr/surfaces.md
    : clients (TUI, print mode, desktop and web, VS Code, ACP, SDK), provider dialects, platforms, configuration states, data vintages, and external scripts.
  3. If prompt text changes (system prompt, tool descriptions, reminders), put each sentence on its own line and state what behavior it constrained before the change, who relies on it, and what constrains it now. The absence of a test referencing this sentence is not evidence that it has no impact.
  4. When replacing or bypassing an old path (porting, runtime binding, or protocol replacement), additionally list an inventory of the old path's functionality: which environment variables it recognizes, what fallbacks it has, which inputs it accepts, and where each item appears in the new path.
  5. If there truly are no observable changes, write
    None
    and explain the evidence: which branches, defaults, and contract files were not changed.
  6. After the table, list the affected modules and the test coverage corresponding to each row. For behavior that is flipped or removed by default, there must be a test that pins the old behavior for unaffected groups, and the changeset must state what users lose; see the
    gen-changesets
    skill. If there is no escape hatch, ask maintainers to make an explicit decision in the PR.

代码变更的可视化大纲

Visual Outline of Code Changes

优先用结构化视图,少用散文。用能说清实现的最小组合,没变的类别不要列。
逻辑或算法变化用伪代码 diff:
diff
 on(save)
-  write content
+  if content is unchanged
+    return cached result
+  write new content
+  invalidate cache
运行时控制流用调用树 diff:
diff
 submitForm
   createSession
     persistPrompt
+    expandSkillMention
     launchAgent
-  navigateToSession
+  navigateToSession
+    subscribeToEvents
文件职责变化用浅层文件树 diff:
diff
 src/
 ├── commands/
+│   └── show-me.ts       # expands the slash command
 ├── sessions/
-└── transport.ts
+└── transport/
+    ├── client.ts
+    └── stream.ts
组件或 UI 结构变化用树 diff:
diff
 <SessionPage>
   useSessionEvents()
   <SessionToolbar>
+    <RunSkillButton />
   <SessionTimeline>
+    <SkillResultCard />
组件交互、控制流或数据流用 Mermaid,解释 bug 机制时尤其有用:
mermaid
sequenceDiagram
    participant User
    participant UI
    participant Daemon
    User->>UI: choose command
    UI->>Daemon: send expanded prompt
    Daemon-->>UI: stream result
关键数据结构或类型变化用对应语言的代码块:
ts
interface SessionEvents {
  onTurnStart(cb: (turn: Turn) => void): void;
  onTurnEnd(cb: (turn: Turn) => void): void;
}
可视化大纲的规则:
  • 重点是"变了什么"且周边形状已存在时,用
    diff
    块。
  • 大部分是新内容,或 diff 记法会掩盖归属和顺序时,用对应语言或
    text
    块给出完整目标形状。
  • 按最容易理解的顺序讲:先文件还是先数据结构,哪个合适用哪个。
  • 像一个人对另一个人讲话:简单、连贯、简洁。
Prefer structured views over prose. Use the smallest combination that makes the implementation clear, and do not include categories that have not changed.
For logic or algorithm changes, use a pseudocode diff:
diff
 on(save)
-  write content
+  if content is unchanged
+    return cached result
+  write new content
+  invalidate cache
For runtime control flow, use a call-tree diff:
diff
 submitForm
   createSession
     persistPrompt
+    expandSkillMention
     launchAgent
-  navigateToSession
+  navigateToSession
+    subscribeToEvents
For changes to file responsibilities, use a shallow file-tree diff:
diff
 src/
 ├── commands/
+│   └── show-me.ts       # expands the slash command
 ├── sessions/
-└── transport.ts
+└── transport/
+    ├── client.ts
+    └── stream.ts
For component or UI structure changes, use a tree diff:
diff
 <SessionPage>
   useSessionEvents()
   <SessionToolbar>
+    <RunSkillButton />
   <SessionTimeline>
+    <SkillResultCard />
For component interactions, control flow, or data flow, use Mermaid; it is especially useful for explaining bug mechanisms:
mermaid
sequenceDiagram
    participant User
    participant UI
    participant Daemon
    User->>UI: choose command
    UI->>Daemon: send expanded prompt
    Daemon-->>UI: stream result
For key data structure or type changes, use a code block in the corresponding language:
ts
interface SessionEvents {
  onTurnStart(cb: (turn: Turn) => void): void;
  onTurnEnd(cb: (turn: Turn) => void): void;
}
Rules for visual outlines:
  • When the focus is on "what changed" and the surrounding shape already exists, use a
    diff
    block.
  • When most of the content is new, or diff notation would obscure ownership and ordering, use a block in the corresponding language or a
    text
    block to show the complete target shape.
  • Explain in the order that is easiest to understand: start with files or data structures, whichever makes the explanation clearer.
  • Talk like one person to another: simple, coherent, and concise.