Workflow · Coding
PR Description from Diff
Turn a git diff into a reviewer-ready PR description — summary, changes, test plan, and risks — via CLI, Copilot, or a GitHub Action.
Problem
Developers ship PRs with empty descriptions or 'fix stuff' bodies. Reviewers waste time reconstructing intent from the diff. The same sections (summary, test plan, risks) get rewritten from scratch every time. Copilot's auto-generated text is a start but rarely matches team conventions.
Final output
A Markdown PR body matching your template — Summary, Changes, Test plan (checkboxes), Risks — plus an optional title suggestion. Runnable as: `npm run pr-describe`, a `prepare-commit-msg` hook, or a GitHub Action comment on draft PRs.
Architecture
git diff (+ optional issue/PR metadata)
→ Collect context (commits, changed paths, linked issue body)
→ LLM with team PR template + conventions
→ Structured Markdown body (+ title)
→ Paste into PR / gh pr create / Action updates descriptionStep-by-step
- 01
Define your PR template
Write the sections reviewers expect: Summary, Changes, Test plan, Risks, Screenshots (if UI). Store as `.github/pull_request_template.md` and as the system prompt anchor.
- 02
Capture diff context
Script gathers `git diff main...HEAD`, commit subjects, list of changed paths, and optional issue text from `gh issue view`. Cap diff at ~100K tokens — summarize file list if larger.
- 03
Build the generation prompt
System: technical writer + your conventions. User: diff + metadata. Require Markdown only, no preamble. Instruct: user-visible changes first, honest test plan, flag breaking changes.
- 04
Generate and review
Call Claude Haiku/Flash for cost or Sonnet for nuance. Human scans for hallucinated features or missing risks — 30-second review before publish.
- 05
Wire into workflow
Options: local CLI alias, `gh pr create --body-file`, GitHub Action on `pull_request` opened, or [GitHub Copilot](/tools/github-copilot) PR UI with the same template pasted as instructions.
What you'll build
A small script (or GitHub Action) that reads your branch diff and outputs a reviewer-ready PR description — not a generic AI summary, but your team's exact sections with a real test plan and honest risks.
Why this matters
Review latency is often "waiting for context," not "reading code." A good PR body answers:
- What changed (user-visible)
- Why now
- How to verify
- What could go wrong
Developers skip writing this because it's tedious. LLMs are unusually good at it when you give them the diff and a rigid template. The failure mode is trusting output blindly — 30 seconds of human edit beats 15 minutes of reviewer archaeology.
Architecture
git diff main...HEAD
+ commit messages + changed paths + linked issue
→ LLM (template-locked prompt)
→ Markdown PR body
→ gh pr create / GitHub UI / Action
Pair with GitHub Copilot PR tools or Claude Code hooks — same prompt, different surface.
Step 1 — PR template
Create .github/pull_request_template.md:
## Summary
## Changes
## Test plan
## Risks
Mirror the same headings in your generator's system prompt. Reviewers and the model should see identical structure.
Add conventions inline:
- Test command:
npm test/pytest/go test ./... - Breaking changes require migration steps in Risks
- UI PRs need screenshot checklist in Test plan
Step 2 — Capture context
Minimal shell collector:
#!/usr/bin/env bash
set -euo pipefail
BASE="${1:-main}"
COMMITS=$(git log --oneline "${BASE}...HEAD")
FILES=$(git diff --name-only "${BASE}...HEAD")
DIFF=$(git diff "${BASE}...HEAD")
STAT=$(git diff --stat "${BASE}...HEAD")
# Optional: linked issue from branch name feat/1234-foo
ISSUE=$(gh issue view 1234 --json body -q .body 2>/dev/null || echo "")
Cap diff size. If wc -c exceeds ~300KB, run the "large diff — summarize first" prompt on file list + stat, then describe per group.
Step 3 — Generate
Call your model with the PR description generator prompt (see frontmatter). Rules that matter:
- Diff wins — don't claim features not in the diff.
- Checkboxes — Test plan must be executable steps.
- Risks — prefer "none identified" over silence on large PRs.
Example local runner sketch (Node + Anthropic):
import Anthropic from "@anthropic-ai/sdk";
import { readFileSync } from "fs";
const template = readFileSync(".github/pull_request_template.md", "utf8");
const client = new Anthropic();
const msg = await client.messages.create({
model: "claude-sonnet-4-20250514",
max_tokens: 2048,
system: `You write PR bodies for this repo. Template:\n${template}`,
messages: [{ role: "user", content: buildUserPrompt({ commits, files, diff, issue }) }],
});
console.log(msg.content[0].type === "text" ? msg.content[0].text : "");
For high volume, default to Haiku or Gemini Flash — see cheapest AI APIs.
Step 4 — Human review (non-optional)
Scan for:
- Invented endpoints or flags
- Test steps that don't exist ("run e2e suite" when you only ran unit tests)
- Missing BREAKING callouts on API changes
Fixing one hallucinated checkbox is cheaper than a reviewer chasing a ghost test.
Step 5 — Wire it up
Option A — CLI before push
npm run pr-describe > /tmp/pr-body.md
gh pr create --title "$(npm run pr-title --silent)" --body-file /tmp/pr-body.md
Option B — GitHub Action on pull_request: opened for draft PRs only — posts a comment "Suggested description" or updates body if empty. Reuse the pattern from AI Code Reviewer for Action scaffolding.
Option C — Copilot UI — paste the generator rules into your first Copilot Chat message when drafting the PR on GitHub.
Option D — Claude Code hook — PostToolUse on git push opens the description in your editor.
Large PR strategy
| Diff size | Strategy |
|---|---|
| < 500 lines | Single-pass full diff |
| 500–5000 lines | diff stat + per-file one-liners from git diff --name-only |
| > 5000 lines | Group by directory/theme, describe groups, link to full diff |
Monorepo tip: pass packages/foo as scope so Changes stays readable.
Extending
- Auto labels — model suggests
area:api,risk:highfrom diff paths. - Changelog entry — second prompt for
CHANGELOG.mdsemver section. - Linear/Jira sync — pull ticket acceptance criteria into Test plan checkboxes.
- Pair with review bot — AI Code Reviewer runs after description is set.
Operating cost
At 20 PRs/week and $0.02/run, inference costs **$1.60/month**. The win is reviewer time, not token savings. The highest ROI AI workflow for most engineering teams is "better PR hygiene" — this is the implementation.
Prompt examples
Copy any of these, replace the placeholders, run.
PR description generator
You write pull request descriptions for {{org}}/{{repo}}.
Template (use exactly these headings):
## Summary
1-2 sentences: what changed and why.
## Changes
- Bullet list, user-visible impact first, then internal refactors.
## Test plan
- [ ] Checkbox items a reviewer can execute
## Risks
- What could break, rollout notes, migrations
Rules:
- Only describe changes supported by the diff/commits below.
- If uncertain, say "verify" instead of inventing behavior.
- Breaking changes go in Risks with **BREAKING** prefix.
- No filler ("this PR improves code quality").
Commits:
{{commits}}
Changed files:
{{files}}
Linked issue (if any):
{{issue}}
Diff:
{{diff}}Title suggestion (short)
Given this PR diff and description, suggest ONE title line.
Format: type(scope): imperative summary
Types: feat, fix, chore, refactor, docs, test
Max 72 characters. No period at end.
Diff summary:
{{diff_stat}}Large diff — summarize first
This diff is too large to describe line-by-line. First pass:
1. Group changes by theme (max 8 groups).
2. For each group: files involved + one-sentence purpose.
3. Flag generated/lockfile-only groups as "mechanical."
Output JSON: { "groups": [{ "name", "files", "summary", "mechanical": boolean }] }
Diff stat:
{{diff_stat}}
File list:
{{files}}Cost estimate
| Line item | Approx. cost |
|---|---|
| Local run (Haiku / Flash, typical PR) | $0.01 |
| Local run (Sonnet, large feature PR) | $0.08 |
| GitHub Action per PR (cached template prompt) | $0.02 |
| Engineer time saved (5–15 min × loaded cost) | positive ROI day one |
| Total per run (approx.) | ~$0.11 |
Costs depend on model choice, content length, and how aggressively you cache.
Optimizations
- Skip generation when diff only touches `*.md` or `package-lock.json` — use a one-line template.
- Cache the system prompt (PR template + conventions) via provider prompt caching.
- Two-pass for huge PRs — summarize file groups first, then describe groups (not raw 5K-line diff).
- Include `CLAUDE.md` / `.github/copilot-instructions.md` excerpts so the model knows your test commands.
- Store generated bodies in Action artifacts for audit — helps tune prompts over time.
Common mistakes
- Sending the entire diff with no file cap — blows token budget and dilutes quality.
- No template — the model invents inconsistent sections every PR.
- Publishing without a 30-second human scan — hallucinated test steps erode trust.
- Describing intent from the issue when the diff doesn't implement it — instruct "diff wins."
- Using the same prompt for 10-line fixes and 80-file refactors — branch on diff size.
Frequently asked questions
Related on AIKnowHub
Workflow
Build an AI Code Reviewer
An AI bot that reviews every PR — catches bugs, suggests improvements, blocks dangerous patterns. Like having a senior engineer on every team.
Tool Guide
GitHub Copilot Guide
The definitive guide to GitHub Copilot — IDE completions, Copilot Chat, agent mode, CLI, PR features, enterprise policy, pricing, and how it compares to Cursor and Claude Code.
Concept
Prompt Engineering Basics
The actual techniques that move the needle — role priming, structured output, few-shot examples, and why specificity always wins.
Concept
Structured Outputs Explained
Structured outputs make models return valid JSON every time — no more parsing failures, no more 'almost JSON.' Here's how they work and when to use them.
Tool Guide
Claude Code Guide
The definitive guide to Anthropic's terminal-native AI coding agent — install, configure, MCP, hooks, skills, sub-agents, plan mode, cost, security, limitations.
Directory
Claude Code
Terminal-native agent that reads, writes, runs, and reviews your codebase.