PR create
Compose before opening. The body is the squash-merge commit
context — write it for the reviewer first, the future reader of
git log second.
Pre-flight
# REST reads — see ~/.claude/CLAUDE.md "GitHub API budget".
branch=$(git branch --show-current)
gh api repos/:owner/:repo/pulls \
--jq ".[] | select(.head.ref==\"$branch\") | {number, state, url}" # existing PR for this branch?
git log --oneline main..HEAD # what this PR actually contains
gh api repos/:owner/:repo/pulls/<N> --jq '.body' # iterating? read the current body
- Existing PR for the branch → iterate on it, don't open a second.
- Find the issue this resolves (branch name, commit trailers, the
task). A PR that closes one carries
Closes #<N>in the body.
Detect repo template
ls .github/pull_request_template.md \
.github/PULL_REQUEST_TEMPLATE.md \
.github/PULL_REQUEST_TEMPLATE/ \
docs/pull_request_template.md 2>/dev/null
Template present → fill its sections; don't swap its structure for ours. Absent → use the structure below.
Body structure (no template)
Three short blocks. A reviewer should grasp all three in one read; a block that runs past a few lines is carrying detail the diff already shows.
- Summary — why this change. Prose, 1-2 sentences leading with
the user-visible outcome ("X now works"), not the diff ("set Y to
Z"). Surface mechanism only when the choice isn't obvious. Link the
issue; don't re-explain it.
Bad: "Set
format_space \"#[bg=16]\"in pair.kdl." Good: "Bar paints uniformly black across the format gap, closing the lighter strip from #68." - Gotchas — what'll surprise the reviewer. A bullet per pointer:
where to spend attention and why, not an exhaustive risk dump.
Typical: off-diff state (a label/secret/setting changed remotely), a
silent-failure mode, a non-obvious constraint, something that reads
like a typo. Litmus: a gotcha completes "watch out —
___", not "I chose___because___"; rationale goes to Summary or gets cut. Omit when nothing surprises. Bad: "Split into two workflows so each trigger is self-documenting." Good: "Labeling pins.../autolabeler@<sha>, a subpath of the same action — not a typo." - Verification — how we know it's correct. A bullet per material check beyond CI, past tense ("ran X, confirmed Y"). Skip trivial steps. Omit the section when CI covers everything; unverified items go in Gotchas, not here.
Optimise for tokens — no filler, no "this PR..." preamble, no restated headings.
House rules
- Draft only.
draft: true; the user promotes to ready. - Regenerate, don't append. Adding commits to an open PR → rewrite
the body from scratch for the new merge state, via
mcp__github__update_pull_request. Appending each round drifts toward changelog narration. - Description, not comments. Carry updates in the body — the single source of truth. The only allowed PR comment is a direct reply to an existing comment on that PR.
- External repos use a different voice. On a repo the user doesn't
own, the description follows
~/.claude/voice.md(conversational, hedged, first-person) — not the structured blocks above, which are for our own repos.
Open the PR
Propose the body before submitting — a PR is shared state.
Push the branch, then open with mcp__github__create_pull_request:
title— imperative subject.body— the blocks above, ending withCloses #<N>.head,base— this branch and the repo's default branch; neither is inferred.draft: true—pr-draft-guard.shblocks the call without it.
Scaffold a repo template
When asked to add a PR template to a repo, write
.github/pull_request_template.md — the same three blocks as
HTML-comment prompts the author fills in and deletes:
## Summary
<!-- Why this change. Lead with the user-visible outcome, not the diff.
Link the issue. -->
## Gotchas
<!-- One bullet per surprise: where to spend attention and why.
Completes "watch out — ___", not "I chose ___ because ___".
Delete this section if nothing surprises. -->
-
## Verification
<!-- One bullet per material check beyond CI, past tense.
Delete this section if CI covers everything. -->
-
Commit and PR it like any change. Match the repo's existing casing if
it already uses PULL_REQUEST_TEMPLATE.md for other GitHub files.
Procedure
- Pre-flight: existing PR? what's in
main..HEAD? which issue closes? - Detect a repo template; fill it, else use the standard structure.
- Compose the three blocks; surface non-obvious choices.
- Open as a draft with
Closes #<N>; capture the URL. - Iterating later → regenerate the whole body, never append.