How to Write a Pull Request Description With AI
Feeding the model your diff produces a longer version of what the reviewer can already read. The useful input is everything the diff cannot contain.
To write a pull request description with AI that a reviewer actually values, you have to stop feeding it the diff. The diff is the one thing your reviewer already has. A model that only reads the diff produces a summary of the diff, which is a longer, less accurate version of information the reviewer can read for themselves.
Everything useful in a PR description is information that is not in the diff: why this change exists, what you considered and rejected, what could break, and what you tested. None of that is recoverable from the code. All of it is in your head, and getting it out of your head is the actual job.
The failure mode, side by side
Here is what a model produces when you paste a diff and ask for a description:
This PR updates the
BookingServiceclass to add a newcancelBookingmethod. It also modifiesBookingControllerto expose a new endpoint and adds tests inbooking_service_test.py.
Accurate. Useless. The reviewer learned nothing they would not learn in six seconds of scrolling.
Here is the same change described with the context the model could not see:
Customers who cancel through support currently have the booking deleted, which loses the audit trail and breaks the monthly reconciliation report. This adds a soft cancel that keeps the row and sets
cancelled_at. Reconciliation already ignores rows withcancelled_atset, so no report change is needed. Risk: the mobile app filters bookings client side and will show cancelled bookings until it ships the matching filter, so this is behindsoft_cancel_enabled, default off.
The second one takes a reviewer from cold to informed in one paragraph, and it tells them exactly where to look hard.
Give the model what the diff cannot contain
The workflow that produces the second version is a short interview, not a summarisation. Before you generate anything, answer four questions in rough notes. Ugly bullet points are fine, the model cleans them up.
What was wrong before? The specific behaviour, not the ticket title.
Why this approach? Especially: what did you consider and not do.
What could this break? Be concrete. Name the systems that touch this code.
What did you actually test? Not what you intend to test.
Then hand the model your notes plus the diff, in that order, with the notes marked as authoritative.
Here are my notes on this change. They are the source of truth for
intent and risk. The diff follows, use it only to check that my notes
match what the code does and to flag anything I have missed.
NOTES:
- before: support cancels delete the booking row, audit trail is lost,
monthly reconciliation report undercounts
- approach: soft cancel, keep row, set cancelled_at. considered a
separate cancellations table, rejected because every read path would
need a join
- risk: mobile app filters bookings client side, will show cancelled
ones until it ships the matching filter. behind soft_cancel_enabled,
default off
- tested: unit tests for cancel and double cancel, manually verified
reconciliation output on staging for July
DIFF:
<paste diff>
Write a PR description with sections: Why, What changed, Risk and
rollout, How this was tested. Keep it under 250 words. Do not restate
the diff file by file. If my notes contradict the diff, say so at the
top instead of writing the description.That last instruction earns its place more often than you would expect. "If my notes contradict the diff, say so" catches the case where you described the change you meant to make rather than the one you made.
A template worth committing
Put the shape in the repository so both humans and agents inherit it. GitHub reads a file at .github/pull_request_template.md and prefills every new PR with it, which is documented behaviour rather than a convention you have to enforce socially.
## Why
What was wrong or missing. Link the issue, but explain it here too.
## What changed
The shape of the change in two or three sentences. Not a file list.
## Risk and rollout
What could break, who is affected, flag name if there is one,
how to roll back.
## How this was tested
What you ran and what you observed. "CI is green" is not a test plan.Four headings, and the model fills them from your notes rather than inventing a structure each time. Consistency here compounds: reviewers learn where to look, and after a month they read the Risk section first.
The parts you should never let a model write
Two sections are yours alone.
The test plan. A model will happily write "tested the cancellation flow end to end" whether or not you did. That sentence, if false, is worse than no sentence, because it stops a reviewer from asking. Write what you actually ran, in your own words, including the thing you did not get to.
The risk assessment. Models are systematically optimistic about blast radius, because the diff does not show them the six other services that read that table. You know about those. Write them down.
Everything else, the wording, the structure, the tightening, is genuinely better with a model in the loop.
When the agent wrote the code
If an AI coding agent produced the change, the interview still applies, it just has an extra step. You cannot describe intent you never formed, so read the diff properly first and reconstruct the decisions. If you cannot explain why the agent chose an approach, that is a signal about the change, not about the description. Reviewing before you describe is the whole discipline, and it is the same reason reviewing AI-generated code before you ship it is not optional.
One anti-pattern to name: do not let the agent open the PR and write its own description in the same run. You get a fluent account of what it believes it did, which is not the same as what it did, and the fluency makes the gap harder to notice.
When the change is too big to describe
Sometimes the interview produces an answer you do not want: the "why" has three unrelated parts. That is the description telling you the PR is wrong, and it is the most useful thing this process does.
A quick test. Write the Why section first, before anything else. If it contains the word "and" joining two independent motivations, split the PR. A reviewer can hold one argument in their head and check the code against it. Two arguments in one diff means each gets half the attention, and the smaller one gets none.
When splitting genuinely is not possible, because a refactor and a behaviour change are entangled, say so explicitly at the top and give the reviewer a reading order:
This contains a mechanical rename (commits 1 to 3) and one behaviour change (commit 4). Review commit 4 carefully, skim the rest. The rename is compiler-verified.
That single sentence redirects attention to the 40 lines that matter out of 900. It is worth more than any amount of polish elsewhere in the description.
Make it repeatable, not heroic
Doing this well once is easy. Doing it on every PR at 6pm on a Thursday is the actual problem, and the fix is to move the standard out of your discipline and into the repository.
Two files carry most of the weight. The pull request template gives the structure. A project instructions file, AGENTS.md or the equivalent your tools read, can carry the rules themselves, so an agent asked to draft a description inherits your conventions rather than a generic idea of one:
## Pull request descriptions
- Sections: Why, What changed, Risk and rollout, How this was tested
- Under 250 words
- Never restate the diff file by file
- Never write the test plan; leave it as TODO for a human
- Flag any contradiction between the stated intent and the diffThat fourth line is deliberate. Leaving the test plan as an explicit blank is more honest than letting an agent fill it, and an obvious TODO in a PR is something reviewers will chase. If you have not set one of these files up, writing an AGENTS.md file covers the general shape.
Keep descriptions short on purpose
A 900-word PR description does not get read. It gets skimmed for the diff link. Under 250 words is a good ceiling for ordinary changes, and if the change genuinely needs more than that, the honest conclusion is usually that it needs to be two PRs.
FAQ
Should the PR description just repeat the commit messages?
No. Commit messages explain individual steps, the PR description explains the whole change and its risk. They serve different readers. Good commit hygiene helps though, and the same interview technique works for writing commit messages with AI.
Can AI write a good PR description with no input from me?
It can write a fluent one. It cannot write a true one, because intent, alternatives considered, and real test coverage are not present in the code. Those four notes are the minimum input.
What model should I use for this?
Almost any current model handles it well, because this is a rewriting task with a strong structure, not a reasoning task. Consistency of format matters more than model choice here.
How do I stop my team writing empty descriptions?
Make the template the path of least resistance and review the Risk section out loud in standups for a week. Enforcement by tooling is weaker than enforcement by attention.
More on working with agents day to day: the AI coding tools guide, writing a bug report an AI coding agent can act on, and handling merge conflicts when agents are in the loop.
How did this land?
About the author

Developer Advocate
Steve builds something with Swarmz every week and writes up what worked, what broke, and what he'd do differently. Tutorials and hands-on guides are his lane.


