Writing detailed PR descriptions is often skipped due to time pressure, but it's crucial for code review efficiency. In this tutorial, you'll build an AI agent that automatically generates a PR description from the code diff whenever a pull request is opened. You'll use GitHub Actions and OpenAI's API. By the end, every new PR will have a clear, context-rich description without manual effort.

Prerequisites: A GitHub repository, an OpenAI API key, basic familiarity with GitHub Actions and Node.js.

Step 1: Set Up Your OpenAI API Key

Generate an API key at platform.openai.com/api-keys. Then add it as a secret in your GitHub repository: go to Settings > Secrets and variables > Actions > New repository secret, name it OPENAI_API_KEY, and paste your key.

Step 2: Create the GitHub Actions Workflow

Inside your repo, create the file .github/workflows/pr-description.yml:

name: AI PR Description
on:
  pull_request:
    types: [opened, reopened, synchronize]

jobs:
  generate-description:
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
      - run: npm ci
      - name: Generate description
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
          PR_NUMBER: ${{ github.event.pull_request.number }}
          REPO: ${{ github.repository }}
        run: node .github/scripts/generate-pr-description.js

This workflow triggers on PR events and runs a Node.js script that will fetch the diff and call the API.

Step 3: Write the Node.js Script

Create the file .github/scripts/generate-pr-description.js:

const { Octokit } = require('@octokit/rest');
const { Configuration, OpenAIApi } = require('openai');

const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });
const openai = new OpenAIApi(new Configuration({ apiKey: process.env.OPENAI_API_KEY }));

async function main() {
  const [owner, repo] = process.env.REPO.split('/');
  const prNumber = parseInt(process.env.PR_NUMBER);

  // Get PR diff
  const { data: diff } = await octokit.rest.pulls.get({
    owner,
    repo,
    pull_number: prNumber,
    mediaType: { format: 'diff' },
  });

  // Truncate diff if too long (OpenAI context limit)
  const maxLength = 15000;
  const diffText = diff.length > maxLength ? diff.slice(0, maxLength) + '\n... (truncated)' : diff;

  // Generate description using OpenAI
  const prompt = `You are a senior developer writing a PR description. Based on the following code diff, write a summary in markdown:
- Purpose and context of the changes
- Key changes (bullet points)
- Any potential side effects or testing notes

Diff:
${diffText}`;

  const response = await openai.createChatCompletion({
    model: 'gpt-4o-mini',
    messages: [
      { role: 'system', content: 'You write concise, informative PR descriptions.' },
      { role: 'user', content: prompt },
    ],
    max_tokens: 500,
    temperature: 0.3,
  });

  const description = response.data.choices[0].message.content;

  // Update PR body
  await octokit.rest.pulls.update({
    owner,
    repo,
    pull_number: prNumber,
    body: description,
  });

  console.log('PR description updated successfully.');
}

main().catch(err => {
  console.error('Error:', err);
  process.exit(1);
});

Don't forget to add a package.json in .github/scripts/ with dependencies @octokit/rest and openai, then run npm install locally or let the workflow do it (the workflow runs npm ci but you need a lockfile). For simplicity, create the file with these dependencies listed and commit the lockfile.

Note: The diff can be long; we truncate to 15,000 characters. Consider using GPT-4 (8k or 16k) for larger diffs. Also, adjust the prompt based on your team's style.

Step 4: Test It

Create a new branch, make changes, and open a pull request. Watch the Actions tab; the job should run and update the PR description. You'll see the AI-generated text replace the default body.

Success! Every future PR will now have a consistent, useful description, saving your team time and improving code review quality.

You can customize the prompt to include ticket numbers, enforce a format, or request breaking changes notes. Consider adding a fallback if the API fails (e.g., keep the original body). This workflow integrates seamlessly with your existing process.

By automating PR descriptions, you eliminate a common friction point and allow developers to focus on what matters: writing great code.