Writing clear PR descriptions is tedious, but AI can do it in seconds. In this tutorial, you'll build a simple, repeatable workflow that extracts the diff, sends it to an LLM with a focused prompt, and post the result as a PR description. You'll use GitHub CLI and a Node.js script — no complex frameworks required.
What you'll build: a script that fetches the diff of the current branch against main, generates a description via an LLM, and updates the PR. It takes about 15 minutes to set up.
Step 1: Collect Context with GitHub CLI
First, get the diff and commit list. The GitHub CLI (gh) makes this trivial. Create a file called collect-context.sh:
#!/bin/bash
BASE_BRANCH="main"
DIFF=$(gh pr diff --repo YOUR_OWNER/YOUR_REPO)
COMMITS=$(gh pr view --json commits --jq '.commits[].messageHeadline')
{
echo "=== DIFF ==="
echo "$DIFF" | head -c 12000 # trim to avoid token limits
echo ""
echo "=== COMMITS ==="
echo "$COMMITS"
} > pr-context.txt
Make it executable (chmod +x collect-context.sh) and run it against an open PR. This gives you a clean file with the diff and commit subjects — exactly what the AI needs.
Step 2: Craft the Prompt
Now, the magic. Create generate-description.mjs that reads that file and calls your model. Here's a Node.js version using fetch (Node 18+) so you don't need extra libraries:
import fs from 'fs';
const context = fs.readFileSync('pr-context.txt', 'utf8');
const prompt = `You are a senior engineer. Write a concise PR description from the diff and commits.
Use this format:
## Summary
## Changes
- bullet list
## Test Plan
(if obvious from diff, otherwise say "Manual testing")
Context:
${context}
`;
const res = await fetch("https://api.openai.com/v1/chat/completions", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${process.env.OPENAI_API_KEY}`
},
body: JSON.stringify({
model: "gpt-4o-mini",
messages: [
{ role: "system", content: "You write clear, technical PR descriptions." },
{ role: "user", content: prompt }
],
temperature: 0.3
})
});
const data = await res.json();
const description = data.choices[0].message.content;
fs.writeFileSync('pr-description.md', description);
console.log('Done! Saved to pr-description.md');
Heads up: if the diff is huge, you'll hit token limits. That's why we truncated it to 12,000 characters. For production, you'd chunk the diff and summarize each file, but this works for most PRs.
Step 3: Punch It Into the PR
Finally, take the generated description and update the PR body:
gh pr edit --body-file pr-description.md
That's it. Run the three steps in sequence and you'll have a polished description.
Make It One Command
Wrap it in a single command using &&:
./collect-context.sh && node generate-description.mjs && gh pr edit --body-file pr-description.md
Add that to your shell aliases or npm scripts for daily use.
Taking It Further
This workflow is deliberately simple, but you can extend it:
- Use structured outputs to force the model to return JSON (summary, changes, test_plan) for easier post-processing.
- Add a step to check for merge conflicts and include that in the PR description.
- Trigger it automatically with a GitHub Action on every new PR.
You did it! You now have a repeatable, AI-driven PR description workflow that saves you and your team time on every pull request.
Comments
No comments yet
Connect with Google to comment or reply.
Connect with Google