Your team opens a pull request. Everyone gets notified. Nobody reviews it. Why? Because clicking through to GitHub, loading the diff, understanding the context, and deciding if it needs your attention takes mental effort. By the time someone reviews it, the author has moved on to another task.
What if every PR was instantly analysed by AI for security issues and potential bugs, with a summary posted to Discord before anyone even clicks the link?
With ETLR, you can build exactly that. No GitHub Actions configuration, no complex CI/CD setup. Just deploy once and let AI handle the first pass review.
What We’re Building
A workflow that:
- Receives GitHub webhook when a PR is opened or updated
- Fetches the actual diff using GitHub’s API (not just metadata)
- Analyses changes with Claude Sonnet focusing on bugs and security
- Posts actionable summary to Discord with direct link to the PR
- Works with private repositories using secure token authentication
The result? Instant PR summaries in Discord, so your team knows what needs attention:

The Complete Workflow
Here is the full YAML configuration:
workflow:
name: pr-reviewer-bot
environment:
- name: GITHUB_TOKEN
secret: true
- name: DISCORD_WEBHOOK_URL
secret: true
- name: ANTHROPIC_API_KEY
secret: true
input:
type: http_webhook
steps:
- type: http_call
url: ${pull_request.url}
method: GET
headers:
Authorization: token ${env:GITHUB_TOKEN}
Accept: application/vnd.github.v3.diff
output_to: pr_diff
- type: anthropic_chat
api_key: ${env:ANTHROPIC_API_KEY}
model: claude-sonnet-4-5
system: |
You are a Senior Software Engineer reviewing pull requests.
Analyse code changes and provide actionable feedback,
focusing on potential bugs or security issues.
Be concise, providing a single recommendation in your summary.
You can use markdown in the output.
prompt: |
Title: ${pull_request.title}
Author: ${sender.login}
Code Changes (diff):
${pr_diff.body}
output_to: ai_analysis
max_tokens: 300
- type: discord_webhook
webhook_url: ${env:DISCORD_WEBHOOK_URL}
content_template: |
*Title:* [${pull_request.title}](${pull_request.html_url})
*Author:* ${sender.login}
*Repository:* ${repository.full_name}
${ai_analysis}
username: PR Reviewer
Let’s break down each section.
How It Works
1. GitHub Webhook Input
input:
type: http_webhook
The workflow listens for GitHub webhook events. When someone opens or updates a pull request, GitHub sends a POST request with PR metadata.
But here’s the catch: GitHub webhooks are lightweight. They tell you a PR was created, but they don’t include the actual code changes. That’s where the next step comes in.
2. Fetching the Diff
- type: http_call
url: ${pull_request.url}
method: GET
headers:
Authorization: token ${env:GITHUB_TOKEN}
Accept: application/vnd.github.v3.diff
output_to: pr_diff
This is the critical step that most tutorials miss. The HTTP call step makes a second request to GitHub’s API to fetch the actual diff.
The magic is in the Accept header: application/vnd.github.v3.diff. Without this, GitHub returns a massive JSON object with file trees and metadata. With it, you get a clean, unified diff that LLMs can read naturally.
The Authorization header uses your GitHub token, which means this works for private repositories. This is production-ready, not just a toy for open source projects.
3. AI Code Review with Claude
- type: anthropic_chat
api_key: ${env:ANTHROPIC_API_KEY}
model: claude-sonnet-4-5
system: |
You are a Senior Software Engineer reviewing pull requests.
Analyse code changes and provide actionable feedback,
focusing on potential bugs or security issues.
Be concise, providing a single recommendation in your summary.
You can use markdown in the output.
prompt: |
Title: ${pull_request.title}
Author: ${sender.login}
Code Changes (diff):
${pr_diff.body}
output_to: ai_analysis
max_tokens: 300
The Anthropic chat step analyses the code with Claude Sonnet 4.5. We inject both the PR title (intent) and the diff (execution) into the prompt.
The system prompt is focused:
- Role: “Senior Software Engineer” sets the expertise level
- Focus areas: Bugs and security issues
- Format: Single concise recommendation
- Markdown support: For better formatting in Discord
max_tokens: 300 keeps the review brief and actionable. Claude Sonnet 4.5 excels at code understanding and can spot subtle issues that other models miss.
4. Discord Notification with Summary
- type: discord_webhook
webhook_url: ${env:DISCORD_WEBHOOK_URL}
content_template: |
*Title:* [${pull_request.title}](${pull_request.html_url})
*Author:* ${sender.login}
*Repository:* ${repository.full_name}
${ai_analysis}
username: PR Reviewer
The Discord webhook step posts the summary where your team actually works. The title is a clickable link, so reviewing is one click away.
This removes the “click tax.” Instead of clicking blindly, your team can read the summary and decide if this PR needs their attention right now.
The Workflow Graph
Here is how the workflow looks in the ETLR dashboard:

The three-step flow: webhook → fetch diff → AI review → Discord notification.
Environment Variables
The workflow uses three secrets:
- GITHUB_TOKEN: A GitHub Personal Access Token with
reposcope - ANTHROPIC_API_KEY: Your Anthropic API key for Claude Sonnet 4.5
- DISCORD_WEBHOOK_URL: The webhook URL for your development Discord channel
Set these in the ETLR dashboard under Environment Variables and mark them as secrets so they are encrypted at rest.
Why This Works
Traditional PR review workflows fail because:
- GitHub webhooks are incomplete: They send metadata, not diffs. You have to fetch the changes separately.
- No context at a glance: Team members must click through, load the page, scan the diff, and decide if it matters.
- Review fatigue: When everything looks equally important, nothing gets reviewed promptly.
- Private repo complexity: Most examples only work for public repos. Real companies need authentication.
AI-powered PR review solves this by:
- Fetching the full diff: Using GitHub’s API with the correct
Acceptheader to get clean, readable diffs - Context-aware analysis: The AI sees both the PR title (what the author claims to do) and the diff (what they actually did)
- Concise actionable summary: Single focused recommendation on bugs and security
- Reduced mental overhead: Team members can triage PRs from Discord without context switching
Setting Up GitHub Webhooks
To connect this workflow to your GitHub repository:
1. Generate a GitHub Token
- Go to GitHub Settings → Developer settings → Personal access tokens
- Generate new token (classic)
- Select
reposcope for full repository access - Copy the token and save it as
GITHUB_TOKENin ETLR
2. Add the Webhook
- Go to your repository Settings → Webhooks
- Click “Add webhook”
- Set Payload URL to your ETLR workflow webhook:
https://pipeline.etlr.io/v1/webhooks/{org_id}/{workflow_id}/{hash} - Set Content type to
application/json - Select “Let me select individual events”
- Check Pull requests only
- Click “Add webhook”
3. Test It
- Open a test PR in your repository
- Check Discord for the AI summary
- Verify the diff was analysed correctly
Customisation Ideas
This is just the starting point. Here are some ways to extend the workflow:
Filter by Labels
Only review PRs with specific labels:
- type: python_function
handler: process
code: |
def process(event):
labels = event.get('pull_request', {}).get('labels', [])
label_names = [label.get('name') for label in labels]
event['has_review_label'] = 'needs-review' in label_names
return event
- type: filter
groups:
- conditions:
- field: has_review_label
op: eq
value: true
Different AI Models for Different Repos
Use Claude Opus for critical repositories, Claude Sonnet for everything else:
- type: if_else
if:
conditions:
- field: repository.name
op: in
value: ["payment-service", "auth-service"]
steps:
- type: anthropic_chat
model: claude-opus-4
api_key: ${env:ANTHROPIC_API_KEY}
system: "You are a security-focused senior engineer..."
prompt: |
Title: ${pull_request.title}
Code Changes: ${pr_diff.body}
output_to: ai_analysis
else:
steps:
- type: anthropic_chat
model: claude-sonnet-4-5
api_key: ${env:ANTHROPIC_API_KEY}
system: "You are a code reviewer..."
prompt: |
Title: ${pull_request.title}
Code Changes: ${pr_diff.body}
output_to: ai_analysis
Post Comments Directly on GitHub
Add AI feedback as PR comments instead of Discord:
- type: http_call
url: ${pull_request.url}/reviews
method: POST
headers:
Authorization: token ${env:GITHUB_TOKEN}
Accept: application/vnd.github.v3+json
body:
event: COMMENT
body: |
🤖 **AI Review Summary**
${ai_analysis}
output_to: github_comment
Track Review Times
Log PR data to analytics to measure review velocity:
- type: segment
write_key: ${env:SEGMENT_WRITE_KEY}
operation: track
user_id: ${sender.login}
event: PR Opened
properties:
repository: ${repository.full_name}
pr_number: ${pull_request.number}
files_changed: ${pull_request.changed_files}
additions: ${pull_request.additions}
deletions: ${pull_request.deletions}
ai_summary: ${ai_analysis}
Multi-Language Support
Detect language and adjust review criteria:
- type: python_function
handler: process
code: |
def process(event):
diff = event.get('pr_diff', {}).get('body', '')
if '.py' in diff:
event['language'] = 'Python'
event['review_focus'] = 'PEP 8, type hints, async patterns'
elif '.ts' in diff or '.js' in diff:
event['language'] = 'TypeScript/JavaScript'
event['review_focus'] = 'TypeScript types, React patterns, async/await'
elif '.go' in diff:
event['language'] = 'Go'
event['review_focus'] = 'Error handling, goroutine safety, interface design'
else:
event['language'] = 'Unknown'
event['review_focus'] = 'General best practices'
return event
- type: anthropic_chat
api_key: ${env:ANTHROPIC_API_KEY}
model: claude-sonnet-4-5
system: |
You are reviewing ${language} code.
Focus on: ${review_focus}
prompt: |
Review this ${language} pull request:
${pr_diff.body}
output_to: ai_analysis
max_tokens: 300
Auto-Approve Simple Changes
Approve documentation or test-only PRs automatically:
- type: if_else
if:
conditions:
- field: pull_request.changed_files
op: lte
value: 3
steps:
- type: python_function
handler: process
code: |
def process(event):
diff = event.get('pr_diff', {}).get('body', '')
# Check if only docs or tests changed
lines = diff.split('\n')
changed_files = [l for l in lines if l.startswith('diff --git')]
is_safe = all(
any(pattern in f for pattern in ['README', 'docs/', 'test/', '.md'])
for f in changed_files
)
event['is_safe_change'] = is_safe
return event
- type: if_else
if:
conditions:
- field: is_safe_change
op: eq
value: true
steps:
- type: http_call
url: ${pull_request.url}/reviews
method: POST
headers:
Authorization: token ${env:GITHUB_TOKEN}
body:
event: APPROVE
body: "✅ Auto-approved: Documentation or test changes only"
- type: discord_webhook
webhook_url: ${env:DISCORD_WEBHOOK_URL}
content_template: "✅ Auto-approved PR: ${pull_request.title}"
username: PR Reviewer
Deploying the Workflow
Save the YAML as pr-reviewer.yaml and deploy with one command:
etlr deploy pr-reviewer.yaml
That is it. Every new pull request will be analysed by AI within seconds, with actionable summaries posted to Discord before your team even notices the GitHub notification.
Ready to speed up code reviews? Get started with ETLR or explore the documentation.
Have questions? Join our Discord community or check out more workflow examples.