PR writing
Full rules: METHODOLOGY.md. Before/after: EXAMPLES.md. Chat shape: RESPONSE.md.
These are requirements, not preferences. A message that breaks one gets rewritten, not shipped.
Operating order
1. Read the diff first
git diff main...HEAD --stat then the real hunks. You cannot state why from a file list.
2. Write the subject (§1)
Under 50 characters. Capitalized. No period. Imperative mood.
Test every subject: "If applied, this commit will ___." If the sentence breaks, the subject is wrong.
Add retry guard to the token refresh path
Banned first words: Added, Adding, Adds, Fixed, Fixes, Updated, Changes, WIP, Misc, Various. Banned anywhere in a subject: emoji, ticket IDs, [tags], trailing ..
3. Blank line, then body wrapped at 72 (§1)
No exceptions — rebase, format-patch, and git log all break without the blank line, and the default pager does not wrap.
4. Body says what and why, never how (§2)
The diff already says how. The body says: the problem that existed, why this solution, what you rejected, what it costs.
5. Apply the language contract (§3–4)
Every sentence, in commits and PR bodies both:
| Rule | Source | Test |
|---|---|---|
| Active voice, present tense | Who does it? Name them. | |
| ≤20 words per instruction, ≤25 per statement | STE | Count it. |
| One instruction per sentence | STE | Two verbs → two sentences. |
| One word, one meaning, everywhere | STE | Same thing, same noun. No synonyms. |
Keep articles (the, a) |
STE | Telegraph style is a defect. |
| ≤3 words per noun cluster | STE | user account creation failure → rewrite. |
Second person you, never we |
we refactored → this change refactors. |
|
| Conditions before instructions | If X, do Y — never Do Y if X. |
|
| Sentence case headings, serial commas | — | |
| Code font for identifiers, paths, flags | — | |
ISO dates (2026-08-12) |
Never 08/12/26. |
Banned words: simply, just, easily, obviously, please, leverage, utilize, in order to, various improvements, under the hood, out of the box, low-hanging fruit. Banned opener: This PR ... — do not pre-announce.
6. Fill the PR body template (§5)
## What changed
<1–3 sentences. Active voice, present tense.>
## Why
<The problem. The reason for this solution. What you rejected.>
## How to verify
1. <One action per step.>
2. <Expected result, stated concretely.>
## Risk
<What breaks if this is wrong. How to roll it back.>
Closes ABC-123
Drop a section only when it is genuinely empty, and say so: Risk: none — docs only.
7. Gate before you push
bash scripts/pr-lint.sh
Exit non-zero → fix the message. Do not run gh pr create on a failing message.
Non-negotiables
- Never
git commit -mfor a change that needs a body. Use a message file or a heredoc. - The PR title obeys the subject rules exactly — 50 characters, imperative, no period.
- A squash-merge message is a commit message. Same rules.
- Never let a template heading survive with placeholder text under it.
- If you cannot state the why, you do not understand the change yet. Go read the diff again.