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:

  1. Receives GitHub webhook when a PR is opened or updated
  2. Fetches the actual diff using GitHub’s API (not just metadata)
  3. Analyses changes with Claude Sonnet focusing on bugs and security
  4. Posts actionable summary to Discord with direct link to the PR
  5. Works with private repositories using secure token authentication

The result? Instant PR summaries in Discord, so your team knows what needs attention:

An AI PR review summary as it appears in Discord

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 workflow graph showing the PR review pipeline

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 repo scope
  • 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:

  1. GitHub webhooks are incomplete: They send metadata, not diffs. You have to fetch the changes separately.
  2. No context at a glance: Team members must click through, load the page, scan the diff, and decide if it matters.
  3. Review fatigue: When everything looks equally important, nothing gets reviewed promptly.
  4. 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 Accept header 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

  1. Go to GitHub Settings → Developer settings → Personal access tokens
  2. Generate new token (classic)
  3. Select repo scope for full repository access
  4. Copy the token and save it as GITHUB_TOKEN in ETLR

2. Add the Webhook

  1. Go to your repository Settings → Webhooks
  2. Click “Add webhook”
  3. Set Payload URL to your ETLR workflow webhook: https://pipeline.etlr.io/v1/webhooks/{org_id}/{workflow_id}/{hash}
  4. Set Content type to application/json
  5. Select “Let me select individual events”
  6. Check Pull requests only
  7. Click “Add webhook”

3. Test It

  1. Open a test PR in your repository
  2. Check Discord for the AI summary
  3. 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.