How to Prompt AI to Write a Changelog Entry From a PR
A reusable prompt template for turning a diff or PR description into a clean, user-facing changelog entry, with tone guidance and a full before/after example.
How to Prompt AI to Write a Changelog Entry From a PR
When you ask an AI to write a changelog entry from a pull request, the biggest failure mode is not grammar, it is scope. Paste a raw diff or commit list into a chat window and you get a rewritten commit log: technically accurate, useless to a reader who does not work in the codebase. Getting a clean changelog entry from a pull request takes telling the model three things up front: who is reading this, what counts as user-facing, and what to strip. Below is a reusable prompt template, the reasoning behind each rule in it, and a before/after example that turns a messy diff into a changelog line worth shipping.
Why a diff alone produces a bad changelog
A diff is written for the next engineer who touches this code. A changelog entry is written for someone who has never seen the code and does not care that it exists. Those two audiences want opposite things.
Commit messages answer "what did I do," a changelog entry answers "what changed for you."
A diff shows every line touched, and most of it is implementation detail: renamed variables, added tests, a helper function split in two.
PR descriptions are written for reviewers. They assume context a changelog reader does not have: ticket numbers, internal service names, flags nobody outside the team has heard of.
Feed a model the raw diff with no instructions and it defaults to summarizing the diff, not the outcome. You get "refactored the export service and added rate limiting" instead of "CSV exports are now faster and cannot be abused to overload the API." The second one is the changelog. The first one is a commit message with better punctuation.
The prompt template
This template has six moving parts: a role, an audience, the input, an inclusion rule, an exclusion rule, and a fixed output format. Fill in the bracketed parts once per product and reuse it on every PR.
You are writing one changelog entry for {PRODUCT_NAME}'s public release notes.
Input: a git diff and/or pull request description, pasted below.
Audience: {AUDIENCE - e.g. "end users of the product, non-technical"}.
Rules:
1. Write only about what changed FOR THE USER, not how it was implemented.
2. Skip anything purely internal: refactors, renamed variables or files,
added or updated tests, dependency bumps, internal-only config, CI
changes, code comments, formatting.
3. If the diff touches a user-visible feature, name the feature plainly,
then state the new behavior in one sentence.
4. If the change fixes a bug, describe the symptom the user saw, not the
root cause in the code.
5. Plain, active language. No jargon, no ticket numbers, no file names,
no function names.
6. One entry per distinct user-facing change. If nothing in this diff is
user-facing, respond with exactly: "No user-facing changes."
7. Match this format for every entry:
- [Added|Fixed|Changed|Removed] <one-sentence description, present tense>
Diff / PR description:
{PASTE_DIFF_OR_PR_TEXT_HERE}Rule 6 matters more than it looks. Without an explicit "say nothing" option, a model under pressure to produce output will manufacture a user-facing spin on an internal-only PR rather than admit there is nothing to report. That single line is what stops your changelog from filling up with padding on quiet release weeks.
Tone: user-facing changelog vs internal changelog
Most teams actually want two documents, not one. An internal engineering log can and should mention the auth middleware refactor, because the next engineer benefits from knowing it happened. A public changelog never should, because the reader has no way to act on that information and it just adds noise.
If you keep both, run the diff through two prompts rather than editing one output down. Trying to write a single entry that quietly serves both audiences is how vague, hedge-everything changelog copy happens.
A line belongs in the internal log only, not the public one, when it has any of these traits:
It names a file, function, or variable.
It describes how the change was made rather than what changed.
It references an internal ticket number, service name, or team.
It is preparatory work behind a feature flag the user cannot see yet.
What to strip out
These categories almost never belong in a user-facing changelog entry, and the exclusion rule in the template above is written to catch them automatically:
Refactors with no behavior change.
Dependency version bumps, unless the bump closes a publicly disclosed vulnerability.
New or updated tests.
CI, build pipeline, or deployment tooling changes.
Code comments, formatting, and linting fixes.
Internal API changes with no client-visible effect.
Work still sitting behind a feature flag nobody outside the team can flip.
The one exception worth calling out: a security fix almost always belongs in the public changelog even when the code change itself looks like ordinary internal cleanup. The user-facing outcome, a vulnerability closed, is what matters, not whether the diff "looks" internal.
Before and after: a messy diff becomes a release note
The input
Here is a stitched-together commit list, the kind of thing that actually lands in a PR description on a normal Tuesday:
commit a1b2c3: refactor auth middleware to use new session store
commit d4e5f6: bump lodash to 4.17.21
commit 7890ab: add rate limit to /api/export endpoint (429 after 10 req/min)
commit bcdef1: fix typo in internal admin dashboard
commit 234567: add unit tests for export service
commit 567890: export CSV now includes archived records (previously
excluded without any message to the user)
commit 890123: rename ExportService.run() to ExportService.execute()
commit abcabc: fix bug where CSV export timed out for accounts with
more than 50,000 rowsThe output
Run that through the template above with {AUDIENCE} set to "end users, non-technical" and this is what comes back:
Fixed: CSV exports no longer time out for accounts with more than 50,000 rows.
Changed: CSV exports now include archived records. Previously these were left out with no indication anything was missing.
Added: The export API now limits requests to 10 per minute to keep the endpoint stable for everyone.
Everything else in the commit list got cut, and each cut has a reason. The auth middleware refactor changed no visible behavior, so it is gone. The lodash bump is dependency hygiene, not news. The admin dashboard typo fix touches an internal-only tool. The added tests are process, not product. The method rename is pure internal API surface. Eight commits went in, three sentences came out, and every sentence describes something the reader can actually notice.
Note the rate limit change: it is technically an implementation detail (a 429 status code, a request counter) but it is included because a real user can hit it and see an error. The test for inclusion is never "is this a code change or a product change," it is "can a user observe this." Keep asking that question and the borderline cases sort themselves out.
Making the prompt repeatable across every PR
A template you re-type from memory drifts. Save it once as a system prompt or a stored snippet with the product name and audience already filled in, then paste a fresh diff each time.
Keep one or two real, good entries in the prompt as few-shot examples. This does more for consistency than adding another rule.
Keep a short "never mention" list next to the rules: internal service names, ticket prefixes, internal tool names specific to your company.
When the output drifts back into commit-message language, regenerate with a stricter reminder rather than hand-editing the same output repeatedly. Editing teaches you nothing about why the prompt failed; regenerating with a sharper instruction does.
If your PRs already get reviewed with an AI's help, the same discipline applies before merge, not just at release time: catching that the diff itself is what it claims to be makes the changelog step easier too, since you are not summarizing changes nobody actually verified.
Common mistakes when prompting for changelog entries
Pasting only the diff with no rules attached. The model has nothing to filter against and defaults to describing the code.
Asking for a "summary" instead of concrete inclusion and exclusion rules. A summary request produces vague, marketing-adjacent language instead of specific, checkable claims.
Not specifying tense and format. Without it, entries drift between past and present tense across releases, and the reading experience gets inconsistent fast.
Skipping the explicit "no user-facing changes" fallback. Without it, an internal-only PR still gets an invented changelog line, because the model is optimizing for having something to say.
How this fits with release notes and other engineering docs
A changelog entry is the smallest unit in this family of documents. If you are assembling a full release announcement out of several of these entries, the same audience and exclusion rules carry over, you are just grouping several entries under one release and adding a short intro. The same strip-the-internals instinct applies when writing an incident postmortem, where the trick is the opposite: keep the internal detail, because that audience is the engineering team, not the end user. These two prompt templates are mirror images of the same idea: define the reader before you define the rules.
If you are deciding what belongs on a public changelog page at all, not just how to phrase one entry, a checklist for what to include and leave off a product changelog is the companion piece to this one. And if prompt structure itself is new territory, the core techniques behind writing prompts that hold up under real use cover the fundamentals this template is built on.
The Added/Fixed/Changed/Removed labels used in the template above are not arbitrary. They follow the Keep a Changelog convention, a widely used format specifically for the kind of entry-per-line structure this template produces. You do not have to use those exact four categories, but picking a small fixed set and sticking to it is what makes a changelog scannable instead of a wall of prose.
How long should a changelog entry be
A person scanning release notes reads maybe five to ten seconds per line before moving on. One sentence per entry, stated as a concrete outcome, works better than a paragraph explaining the reasoning behind a fix. If an entry needs two sentences, the first should be the change and the second should be the one detail a user needs to act on it, like a setting that reset or a step they no longer need to repeat.
Frequently asked questions
Should I paste the full diff or just the PR description?
Paste both when you have them. The PR description usually states intent in plain language, which helps the model classify borderline changes correctly, while the diff confirms what actually shipped rather than what was planned. A description alone can describe a change that got scoped down before merge; the diff is the source of truth for what to report.
What if a PR touches both an internal refactor and a user-facing fix?
That is normal, most real PRs are mixed. The template handles it through rule 6: it asks for one entry per distinct user-facing change and explicit permission to say nothing about the rest. You do not need to separate the diff yourself, the exclusion rule does that filtering as part of generating the entry.
How do I keep the AI from inventing details that are not in the diff?
Keep the instruction to describe only what is present in the pasted diff or description, and keep the "no user-facing changes" fallback in place so the model is never forced to manufacture something to report. If an entry mentions a number, a limit, or a specific behavior, check it against the diff before publishing. This is a place worth a human skim even with a good prompt.
Should internal and public changelogs use the same prompt?
No. Run the same diff through two prompts with different audience and exclusion rules rather than trying to write one entry that serves both readers. A single blended version tends to either leak internal detail into the public log or strip so much detail that the internal log stops being useful.
Does this work on a batch of PRs at once, not just one?
Yes, paste multiple diffs or PR descriptions in sequence, each clearly separated, and ask the model to apply the same rules to each before grouping the resulting entries by category. This is how a full release's changelog gets assembled: one pass per PR at the entry level, then a short combine step, rather than one prompt trying to summarize an entire release from a giant merged diff.
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.


