Build an AI Pull Request Description Generator with Claude API
Build a GitHub Action that automatically generates detailed PR descriptions using Claude API. Reads the git diff, generates summary, testing instructions, and risk assessment, then posts it back to the PR.
Writing good PR descriptions takes time. Most engineers write a single line and move on. This GitHub Action uses Claude API to read your git diff and automatically generate a full PR description — summary, testing steps, risks, and all — every time a PR is opened.
This is different from PR review bots. Those tools review your code and leave comments. This tool generates the description the PR author should have written.
What It Builds
When a PR is opened:
- The Action reads the full git diff of the PR
- Sends it to Claude Haiku with a structured prompt
- Gets back a formatted PR description
- Posts it to the PR body via the GitHub API
The result is a PR description with: what changed, why it matters, how to test it, and what could break.
Prerequisites
- GitHub repository
- Anthropic API key (get one at console.anthropic.com)
- Add
ANTHROPIC_API_KEYto your repo's Settings → Secrets → Actions secrets
The Python Script
Save this as .github/scripts/generate_pr_description.py:
import os
import sys
import anthropic
import requests
def get_pr_diff(repo: str, pr_number: int, github_token: str) -> str:
url = f"https://api.github.com/repos/{repo}/pulls/{pr_number}"
headers = {
"Authorization": f"token {github_token}",
"Accept": "application/vnd.github.v3.diff",
}
response = requests.get(url, headers=headers)
response.raise_for_status()
# Truncate to 8000 chars to stay within token limits
return response.text[:8000]
def generate_description(diff: str, pr_title: str) -> str:
client = anthropic.Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
prompt = f"""You are a senior software engineer writing a pull request description.
PR Title: {pr_title}
Git Diff:
{diff}
Write a clear PR description in this exact format:
## Summary
[2-3 bullet points describing what changed and why]
## Changes Made
[Bullet list of specific files/components changed and what was done]
## How to Test
[Step-by-step instructions to verify this PR works correctly]
## Potential Risks
[Any areas that could break, edge cases to watch, or dependencies changed]
Be specific and technical. Use the actual file names and function names from the diff.
Do not add any commentary outside this format."""
message = client.messages.create(
model="claude-haiku-4-5-20251001",
max_tokens=1024,
messages=[{"role": "user", "content": prompt}],
)
return message.content[0].text
def post_pr_description(
repo: str,
pr_number: int,
github_token: str,
description: str,
) -> None:
url = f"https://api.github.com/repos/{repo}/pulls/{pr_number}"
headers = {
"Authorization": f"token {github_token}",
"Accept": "application/vnd.github.v3+json",
}
data = {"body": description}
response = requests.patch(url, headers=headers, json=data)
response.raise_for_status()
print(f"PR description updated successfully.")
def main():
repo = os.environ["GITHUB_REPOSITORY"]
pr_number = int(os.environ["PR_NUMBER"])
pr_title = os.environ["PR_TITLE"]
github_token = os.environ["GITHUB_TOKEN"]
print(f"Fetching diff for PR #{pr_number}...")
diff = get_pr_diff(repo, pr_number, github_token)
if not diff.strip():
print("Empty diff. Skipping.")
sys.exit(0)
print("Generating PR description with Claude...")
description = generate_description(diff, pr_title)
print("Posting description to PR...")
post_pr_description(repo, pr_number, github_token, description)
if __name__ == "__main__":
main()The GitHub Actions Workflow
Save this as .github/workflows/pr-description.yml:
name: Generate PR Description
on:
pull_request:
types: [opened]
jobs:
generate-description:
runs-on: ubuntu-latest
permissions:
pull-requests: write
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install dependencies
run: pip install anthropic requests
- name: Generate and post PR description
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_REPOSITORY: ${{ github.repository }}
PR_NUMBER: ${{ github.event.pull_request.number }}
PR_TITLE: ${{ github.event.pull_request.title }}
run: python .github/scripts/generate_pr_description.pyNote: GITHUB_TOKEN is automatically provided by GitHub Actions — you do not need to create this secret manually. Only ANTHROPIC_API_KEY needs to be added to your repo secrets.
Example Output
For a PR that adds a new Kubernetes health check endpoint, Claude generates:
## Summary
- Adds /healthz and /readyz endpoints to the FastAPI application for Kubernetes liveness and readiness probes
- Separates liveness (process is alive) from readiness (app is ready to serve traffic) to allow proper rolling deployments
- No database or external service dependencies in the liveness check to avoid cascading failures
## Changes Made
- `src/main.py`: Added two new route handlers at /healthz and /readyz
- `k8s/deployment.yaml`: Added livenessProbe and readinessProbe configuration pointing to new endpoints
- `tests/test_health.py`: Added test cases for both endpoints including failure scenarios
## How to Test
1. Run locally: uvicorn src.main:app --reload
2. Hit GET /healthz — expect {"status": "ok"} with 200
3. Hit GET /readyz — expect {"status": "ready", "db": "connected"} with 200
4. Apply to staging: kubectl apply -f k8s/deployment.yaml
5. Watch rollout: kubectl rollout status deployment/my-app
## Potential Risks
- The readiness probe checks database connectivity. If the database is slow on startup, pods may not become ready immediately and cause brief traffic disruption during deployments.
- Liveness probe failure interval is set to 3 failures before restart — confirm this matches your app's startup time.
That is a real, useful PR description generated in about 3 seconds.
Controlling When It Runs
The workflow only triggers on pull_request: opened. If you want it to also update on PR edits:
on:
pull_request:
types: [opened, synchronize]With synchronize, the description updates every time new commits are pushed to the PR branch. This keeps the description accurate as the PR evolves.
Cost
Claude Haiku is cheap. A typical PR diff (8000 chars in, ~400 tokens out) costs around $0.0003 per PR. At 100 PRs per month, that is $0.03. Not worth worrying about.
If your diffs are large (monorepo PRs), the 8000-character truncation in the script prevents runaway costs. Adjust the truncation limit to your needs.
This is one of the simplest high-value automations you can add to any engineering team's workflow. The time it saves on writing descriptions pays back instantly.
Today I Fixed
Short real fixes from production — posted daily
Stay ahead of the curve
Get the latest DevOps, Kubernetes, AWS, and AI/ML guides delivered straight to your inbox. No spam — just practical engineering content.
Related Articles
Build an AI DevOps Daily Digest with Claude API
Build a Python script that collects pending PRs, firing Prometheus alerts, Kubernetes warnings, and failed CI jobs, then uses Claude API to generate a prioritized morning briefing posted to Slack.
Build an AI Flaky Test Detector for GitHub Actions with Claude API
Build a Python tool using PyGithub and the Anthropic Claude API to detect flaky tests in GitHub Actions, analyze root causes with AI, and generate fix reports — runs as a weekly cron job.
Build an AI GitHub Issue Triage Bot with Claude API
Automatically label, prioritize, and route GitHub issues using Claude API. Save your team hours of manual triage every week with this Python bot.