Writing a PR Description
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
-
Read the PR template:
Read(.github/pull_request_template.md)
-
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 .
- Follow the repository's Git safety conventions.
-
Gather the context needed to explain the change:
- Read the linked issue and relevant task artifacts.
- Read the full diff () and enough surrounding code to understand the behavior and ownership boundaries.
- If the PR already exists, use to get its metadata and the list of changed files.
-
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
skill), and section headings must retain the template's original wording.
- Requirement or Bug: One sentence, or . Do not write more.
- Bug Reproduction Steps: Only needed for bug PRs; write for a feature. If the steps are already in the issue, write .
- Root Cause: Only needed for bug PRs; write 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.
-
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
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:
-
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:
| Behavior | Before | After | Who relies on the old behavior | Escape hatch |
|---|
| reasoning parsing when is an array | string also read | string ignored | OpenAI-compatible gateways that send both (OpenRouter dialect) | none |
-
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.
-
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.
-
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.
-
If there truly are no observable changes, write
and explain the evidence: which branches, defaults, and contract files were not changed.
-
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
skill. If there is no escape hatch, ask maintainers to make an explicit decision in the PR.
Visual Outline of Code Changes
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 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 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.