Skip to content

PR Explainer for PMs ​

You will build an automated pipeline that watches your team's GitHub pull requests, translates code changes into plain-English summaries, identifies potential risks, and posts the result to a Slack channel. Product managers get a clear, non-technical summary of every PR without opening a single file diff or asking an engineer "so what does this actually do?"

The pipeline runs on demand or on a schedule. You trigger it with a single command. Within seconds, Claude Code reads the PR diff from GitHub, reasons about the business impact, flags anything that looks risky or out of scope, and delivers a Slack message your PM team can act on. No more guessing what shipped.

This tutorial is for product managers, engineering leads, and anyone who bridges the gap between what engineers build and what the business needs to know. You need basic terminal comfort but zero programming knowledge.

What you'll need ​

ItemDetails
Time30--45 minutes for initial setup; each PR summary takes ~15 seconds after that
CostFree tier works for small teams (Claude Code free tier, Slack free plan, GitHub free plan). Teams with 10+ PRs per day may need Anthropic's paid tier (~$20/month)
StackClaude Code (AI agent for code analysis), GitHub MCP server (reads PRs from GitHub), Slack Incoming Webhook (posts messages to a channel)
PrerequisitesA GitHub account with access to the repos you want to monitor, a Slack workspace where you can create apps, and Claude Code installed (npm install -g @anthropic-ai/claude-code)
Skill levelBasic terminal. Copy and paste commands. You configure three things: a GitHub token, a Slack webhook URL, and a Claude Code prompt

How it works ​

Claude Code connects to GitHub through an MCP (Model Context Protocol) server. When you point it at a pull request, the MCP server fetches the PR metadata, diff, comments, and file list. Claude reads the diff the same way a senior engineer would, then produces a summary. That summary gets formatted and sent to Slack through a webhook URL.

Each summary includes the PR title, author, a bullet list of changes in business language, risk flags, and a link back to the PR. Here is what a real Slack message looks like after this pipeline runs:

PR #247: Add rate limiting to the billing API Author: jchen | Repo: platform-api

What changed:

  • The billing endpoint now caps requests at 100 per minute per customer. Customers who exceed the limit get a 429 status code with a retry-after header.
  • Added a Redis dependency to track request counts across server instances.
  • Updated the API docs to document the new rate limit behavior.

Business impact: This prevents a single misbehaving integration from overwhelming the billing system. Customers see a clear error message and can retry automatically. No pricing or invoice logic changed.

Risk flags:

  • New Redis dependency. If Redis is unreachable, the rate limiter fails open (allows all requests) rather than blocking traffic. Confirm this is the desired failure mode.
  • Updated 3 environment variable files. Verify staging and production configs match.

Product managers can scan this in 10 seconds, understand what shipped, and raise concerns before the PR merges.

Build it ​

Step 1: Get a GitHub personal access token ​

Claude Code needs permission to read pull requests from your repositories.

  1. Go to github.com/settings/tokens
  2. Click "Generate new token" and choose "Fine-grained token" (or "Classic" if fine-grained is not available in your organization)
  3. Give it a name like "claude-code-pr-explainer"
  4. Under "Repository access," select "Only select repositories" and pick the repos you want to monitor. Or choose "All repositories" if you want broad coverage
  5. Under "Permissions," expand "Pull requests" and set it to "Read-only"
  6. Under "Permissions," expand "Metadata" (it should already be Read-only by default)
  7. Click "Generate token" and copy the token immediately. GitHub shows it only once

Store this token somewhere safe. You will need it in Step 3.

Step 2: Create a Slack incoming webhook ​

The webhook URL is the address where Claude Code sends the summary message.

  1. Go to api.slack.com/apps and click "Create New App"
  2. Choose "From scratch," name it "PR Explainer," and select your workspace
  3. In the left sidebar, click "Incoming Webhooks"
  4. Toggle "Activate Incoming Webhooks" to On
  5. Click "Add New Webhook to Workspace"
  6. Choose the channel where PR summaries should appear (create a dedicated channel like #pr-reviews first if you want to keep your main channels clean)
  7. Click "Allow"
  8. Copy the webhook URL. It looks like https://hooks.slack.com/services/T00000000/B00000000/xxxxxxxxxxxxxxxxxxxxxxxx

Test the webhook from your terminal to confirm it works:

bash
curl -X POST -H 'Content-type: application/json' \
  --data '{"text":"Hello from PR Explainer! Setup is working."}' \
  https://hooks.slack.com/services/T00000000/B00000000/xxxxxxxxxxxxxxxxxxxxxxxx

You should see the message appear in your chosen Slack channel. If nothing appears, double-check the URL and that the webhook is activated in your Slack app settings.

Step 3: Configure the GitHub MCP server for Claude Code ​

Claude Code needs to know about the GitHub MCP server. You configure this once and Claude Code uses it for every future session.

Create or edit the Claude Code MCP configuration file:

bash
mkdir -p ~/.claude

Open ~/.claude/mcp.json in any text editor. If the file does not exist, create it. Add this content, replacing YOUR_GITHUB_TOKEN with the token from Step 1:

json
{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-github"
      ],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "YOUR_GITHUB_TOKEN"
      }
    }
  }
}

If you already have an mcp.json file with other MCP servers configured, add only the "github" entry inside the existing mcpServers object.

Verify the MCP server starts correctly:

bash
claude --mcp-debug

Claude Code starts and checks connectivity to all configured MCP servers. Look for a line confirming the GitHub server connected successfully. If you see an error, the most common cause is a typo in the personal access token. Regenerate the token from Step 1 and try again.

Step 4: Write the PR explainer prompt ​

Create a directory for your PR explainer workflow:

bash
mkdir -p ~/pr-explainer
cd ~/pr-explainer

Create a file called explain-pr.md with your prompt template. This is the instruction set Claude Code reads every time you ask it to summarize a PR. Open explain-pr.md in a text editor and paste:

markdown
# PR Explainer Prompt

You are a product-minded technical translator. Your job is to read a GitHub pull request and produce a Slack message that a product manager with no engineering background can understand and act on.

## Input

The user will give you a GitHub PR URL like `https://github.com/owner/repo/pull/123`. Use the GitHub MCP tools to fetch the PR details, diff, comments, and file list.

## Output format

Produce a single Slack message using Slack mrkdwn formatting. The message must follow this exact structure:

PR #<number>: <PR title> Author: <username> | Repo: <repo-name>

What changed:

  • <bullet 1 in plain business language>
  • <bullet 2>
  • ...

Business impact: <2-3 sentence paragraph explaining what this means for users, customers, or the business. No technical jargon. If the change is purely internal (refactor, dependency update), explain why it matters -- stability, speed, future-proofing.>

Risk flags: <if none, write "None identified">

  • <flag 1>
  • <flag 2>

## Rules

1. Never mention file paths, line numbers, or function names unless they are directly relevant to a business concern
2. Translate every technical change into the user-visible or business-visible outcome. "Added a Redis cache layer for session tokens" becomes "Login sessions now persist across server restarts, so users don't get logged out during deployments"
3. Flag these as risks:
   - Database migrations (schema changes can cause downtime)
   - New third-party dependencies or API calls (new points of failure)
   - Changes to authentication, authorization, or billing logic (security and revenue impact)
   - Environment variable changes (config drift between environments)
   - Large diffs (more than 500 lines changed -- higher chance of bugs)
   - Missing tests for new logic
   - Changes touching files marked as critical (payment processing, auth, data deletion)
4. If the PR has review comments requesting changes, note them under risk flags: "Review comments from <reviewer> requesting changes to <area>"
5. Keep the total message under 2,000 characters. Slack blocks display poorly for very long messages
6. If the PR diff is so large you cannot read it all in one pass, summarize the major themes and note "Large PR -- manual review recommended"
7. Include a link back to the PR at the end of the message
8. Use bold (*asterisks*) for section headers and key terms, not for entire sentences
```

### Step 5: Create the runner script

You need a script that ties everything together: it takes a PR URL, runs Claude Code with your prompt, and sends the result to Slack. Create a file called `run.sh` in the same directory:

```bash
#!/bin/bash
# PR Explainer runner
# Usage: ./run.sh https://github.com/owner/repo/pull/123

set -euo pipefail

PR_URL="$1"
SLACK_WEBHOOK_URL="https://hooks.slack.com/services/T00000000/B00000000/xxxxxxxxxxxxxxxxxxxxxxxx"

echo "Analyzing $PR_URL..."

SUMMARY=$(claude -p "$(cat explain-pr.md)

Analyze this pull request and produce a Slack-formatted summary:

$PR_URL" --output-format text 2>&1)

if [ $? -ne 0 ]; then
  echo "Claude Code failed: $SUMMARY"
  exit 1
fi

# Escape the summary for JSON and send to Slack
ESCAPED_SUMMARY=$(echo "$SUMMARY" | python3 -c "import sys, json; print(json.dumps(sys.stdin.read()))")

curl -s -X POST -H 'Content-type: application/json' \
  --data "{\"text\": $ESCAPED_SUMMARY}" \
  "$SLACK_WEBHOOK_URL"

echo ""
echo "Summary posted to Slack."
```

Make it executable:

```bash
chmod +x run.sh
```

Replace the `SLACK_WEBHOOK_URL` value with your actual webhook URL from Step 2.

### Step 6: Run your first PR summary

Pick a real pull request from your team's repository. Find the URL on GitHub -- it looks like `https://github.com/your-org/your-repo/pull/42`.

Run the pipeline:

```bash
cd ~/pr-explainer
./run.sh https://github.com/your-org/your-repo/pull/42
```

Claude Code starts, connects to GitHub through the MCP server, fetches the PR diff, applies your prompt, formats the summary, and posts it to Slack. The whole process takes 10--20 seconds depending on the size of the PR.

Check your Slack channel. You should see a formatted message with the PR title, author, change bullets, business impact, and risk flags. If the formatting is wrong or the summary misses something important, edit `explain-pr.md` to refine the prompt, then run the command again.

### Step 7: Automate (optional)

Running `./run.sh` manually works well. If you want automatic notifications for every new PR, you have two practical options:

**Option A: GitHub Actions (recommended for teams)**

Create a file at `.github/workflows/pr-explainer.yml` in your repository:

```yaml
name: PR Explainer
on:
  pull_request:
    types: [opened, ready_for_review]

jobs:
  explain:
    runs-on: ubuntu-latest
    steps:
      - name: Summarize and notify
        run: |
          # This calls the same run.sh script via an API or webhook
          curl -X POST "${{ secrets.PR_EXPLAINER_ENDPOINT }}" \
            -H "Content-Type: application/json" \
            -d "{\"pr_url\": \"${{ github.event.pull_request.html_url }}\"}"
```

Store your runner endpoint as a GitHub secret (`PR_EXPLAINER_ENDPOINT`) and point it at a small server that runs `run.sh`. This approach works best with a lightweight web service wrapping your script. Tools like [Val Town](https://www.val.town) or [Pipedream](https://pipedream.com) can host this for free.

**Option B: Cron-based polling**

Run the script on a schedule to check for new PRs. Create a small wrapper that lists recent PRs and explains any that have not been summarized yet. Add it to your system's crontab:

```bash
# Run every 15 minutes during business hours
*/15 9-17 * * 1-5 cd ~/pr-explainer && ./poll-recent-prs.sh
```

For small teams, manual invocation is often better. You run it when you want to review open PRs, and you do not spam Slack with noise from draft or work-in-progress PRs.

## What goes wrong

| Mistake | How you notice it | The fix |
|---|---|---|
| GitHub token has wrong permissions | Claude Code says "not found" or "403 Forbidden" when fetching a PR | Go to GitHub token settings and confirm "Pull requests" is set to Read. Regenerate if needed. For private repos, make sure the token has access to those specific repositories |
| MCP server fails to start | `claude --mcp-debug` shows connection error for the GitHub server | Check `~/.claude/mcp.json` for JSON syntax errors (trailing commas are a common culprit). Verify the `GITHUB_PERSONAL_ACCESS_TOKEN` value is the token itself, not a variable name |
| npx fails to find the MCP package | Error about `@modelcontextprotocol/server-github` not found | Run `npx -y @modelcontextprotocol/server-github --help` directly to confirm the package downloads. If it fails, your Node.js version may be too old; upgrade to Node.js 18+ |
| Slack webhook returns "invalid_payload" | curl response includes `"invalid_payload"` | The JSON body is malformed. Most often this happens when the summary text contains unescaped double quotes or newlines. Verify the python3 JSON escaping in `run.sh` is working: run `echo 'test "quote"' | python3 -c "import sys, json; print(json.dumps(sys.stdin.read()))"` |
| Slack message is empty or truncated | Message shows only a few words or cuts off mid-sentence | The prompt's 2,000 character limit is kicking in. Edit `explain-pr.md` and ask Claude to produce shorter summaries. Or split very large PRs into smaller ones. Also check that the Slack webhook block limit is not hit (Slack's limit is 3,000 characters for webhook text) |
| Summary is too technical | PMs report they do not understand the message | Strengthen the prompt. Add to `explain-pr.md`: "If you use a technical term like 'middleware', 'cache invalidation', or 'ORM migration', define it in parentheses the first time. Prefer analogies over technical descriptions." |
| Claude Code uses too many API credits | You hit Anthropic rate limits or run out of free tier credits quickly | Large PRs consume more tokens. In `explain-pr.md`, add a rule: "If the diff exceeds 1,000 lines, summarize at the file level rather than reading every line. Focus on changed function signatures, new dependencies, and configuration changes." |
| Risk flags are noisy | Every PR gets flagged for "large diff" or "missing tests" | Tune the thresholds in the prompt. Change "more than 500 lines" to "more than 1,000 lines." Add a line: "Only flag missing tests when the PR introduces new business logic, not for configuration or documentation changes." |
| PR URL points to a merged or closed PR | Summary describes stale work | The script runs fine on any PR, but the summary is less useful for merged PRs. Add a check to `run.sh`: before running Claude, call the GitHub API to check the PR state and skip closed PRs. Or filter in your PR list script |
| Environment variable not set for MCP | Claude Code starts but GitHub tools are not available | The `mcp.json` `env` block is case-sensitive. `GITHUB_PERSONAL_ACCESS_TOKEN` must match exactly. Also, if you run Claude Code with `sudo`, environment variables are stripped. Run without `sudo` |

## The result

You now have a working pipeline that turns any GitHub pull request into a Slack message your product team can read, understand, and act on. To verify everything works:

1. **Functional test:** Pick three PRs from your team's recent history -- one small bug fix, one feature addition, and one refactor. Run `./run.sh` on each. Confirm the summaries appear in Slack and that a non-engineer colleague can understand all three without asking follow-up questions.
2. **Risk detection test:** Find a PR that includes a database migration, a new dependency, or an auth change. Run the pipeline. Confirm the risk flag appears in the Slack message.
3. **Prompt tuning loop:** Review the first five summaries with your PM team. Ask them: "What would make these more useful?" Adjust `explain-pr.md` based on their feedback. The prompt is the product; treat it like one.

### What you can build next

The same architecture extends in several directions:

- **Multi-channel notifications:** Post to Slack, email a digest to stakeholders, or create a Jira comment on the linked ticket. The `run.sh` script already produces the summary text; adding a second `curl` call to another service is a one-line change.
- **PR review queues:** Build a dashboard that shows all open PRs sorted by risk level. Run the pipeline on every open PR in the morning and post a "PR status" digest to the team channel.
- **Release notes automation:** When a PR merges, append its summary to a running changelog. At release time, you have a pre-written changelog in plain English, ready to publish.
- **Scope creep detection:** Add a prompt rule that compares the PR diff to the linked issue or ticket. Flag changes that appear to go beyond the ticket's stated scope. "This PR adds a new API endpoint not mentioned in the original ticket."
- **On-call handoff summaries:** Run the pipeline on all PRs that merged since the last on-call shift started. The incoming on-call engineer gets a plain-English summary of what changed while they were away.

The core insight is that Claude Code plus an MCP server gives you a programmatic bridge between engineering artifacts (code diffs) and business communication (Slack messages). The prompt is where you encode your team's standards, risk tolerance, and communication style. Invest in tuning it and the pipeline pays back every sprint.