AutomationFlowsAI & RAG › Review Github Pull Requests with Gpt-4o and Send Feedback and Slack Alerts

Review Github Pull Requests with Gpt-4o and Send Feedback and Slack Alerts

ByTakatoYamada @takato-door on n8n.io

Engineering teams, code reviewers, and tech leads who want to automate code review feedback. Ideal for repositories with high PR volume where consistent first-pass review is valuable.

Event trigger★★★★☆ complexityAI-powered15 nodesGithub TriggerHTTP RequestOpenAIGitHubSlack
AI & RAG Trigger: Event Nodes: 15 Complexity: ★★★★☆ AI nodes: yes Added:

This workflow corresponds to n8n.io template #15306 — we link there as the canonical source.

This workflow follows the GitHub → HTTP Request recipe pattern — see all workflows that pair these two integrations.

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "id": "AlHVikTKJ41ARefk7-ZTm",
  "name": "Automatically review pull requests with AI and post feedback as GitHub comments",
  "tags": [
    {
      "id": "0db9feb574da46e5",
      "name": "ai",
      "createdAt": "2026-04-30T18:38:11.353194Z",
      "updatedAt": "2026-04-30T18:38:11.353194Z"
    },
    {
      "id": "488c1574bb33409a",
      "name": "gpt-4",
      "createdAt": "2026-04-30T18:38:11.353194Z",
      "updatedAt": "2026-04-30T18:38:11.353194Z"
    },
    {
      "id": "62d32ecd261f4fce",
      "name": "openai",
      "createdAt": "2026-04-30T18:38:11.353194Z",
      "updatedAt": "2026-04-30T18:38:11.353194Z"
    },
    {
      "id": "tanWNWkQaVKBvG4h",
      "name": "github",
      "createdAt": "2026-04-22T22:16:32.332Z",
      "updatedAt": "2026-04-22T22:16:32.332Z"
    },
    {
      "id": "929db4748f034b67",
      "name": "slack",
      "createdAt": "2026-04-30T18:38:11.353194Z",
      "updatedAt": "2026-04-30T18:38:11.353194Z"
    },
    {
      "id": "a0291087c4a844c1",
      "name": "code-review",
      "createdAt": "2026-04-30T18:38:11.353194Z",
      "updatedAt": "2026-04-30T18:38:11.353194Z"
    },
    {
      "id": "de8ac33010a74fe5",
      "name": "devops",
      "createdAt": "2026-04-30T18:38:11.353194Z",
      "updatedAt": "2026-04-30T18:38:11.353194Z"
    },
    {
      "id": "xkhvijdyzZQ1znPF",
      "name": "automation",
      "createdAt": "2026-04-22T22:16:32.341Z",
      "updatedAt": "2026-04-22T22:16:32.341Z"
    }
  ],
  "nodes": [
    {
      "id": "2ad2f601-2b50-4ef6-87c2-2cbabc173ed6",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1872,
        -64
      ],
      "parameters": {
        "width": 480,
        "height": 688,
        "content": "## Automatically review pull requests with AI and post feedback as GitHub comments\n\n## How it works\n\n1. Initiates on a GitHub pull request event trigger.\n2. Filters pull request events to continue with only 'opened' actions.\n3. Retrieves the pull request diff via HTTP request.\n4. Formats the diff, then uses GPT-4o to automatically review the code.\n5. Generates and posts a comment with the review results on GitHub and sends alerts on Slack based on the review severity.\n\n## Setup steps\n\n- [ ] Configure GitHub credentials for the trigger and comment posting\n- [ ] Set up OpenAI API key for GPT-4o code review\n- [ ] Configure Slack credentials for sending alerts\n\n## Customization\n\nAdjust the sensitivity of severity checks within the conditional branch to customize alert levels."
      },
      "typeVersion": 1
    },
    {
      "id": "88edd9fe-e658-4879-9a5a-b438c3388964",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1312,
        64
      ],
      "parameters": {
        "color": 7,
        "width": 416,
        "height": 304,
        "content": "## Trigger and filter PR\n\nStarts the workflow on pull request events and filters for 'opened' status."
      },
      "typeVersion": 1
    },
    {
      "id": "4c23501c-512b-4155-a280-515efaf148cb",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -864,
        64
      ],
      "parameters": {
        "color": 7,
        "width": 400,
        "height": 304,
        "content": "## Fetch and format diff\n\nRetrieves the diff of the pull request and formats it for AI analysis."
      },
      "typeVersion": 1
    },
    {
      "id": "bb95fe03-4409-4e3a-9d12-65136351fcd5",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -432,
        80
      ],
      "parameters": {
        "color": 7,
        "width": 640,
        "height": 272,
        "content": "## AI review and comment\n\nUses AI to review the code and formulates a GitHub comment."
      },
      "typeVersion": 1
    },
    {
      "id": "e976ecd2-a43e-45cc-9f08-0312076c835e",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        240,
        -64
      ],
      "parameters": {
        "color": 7,
        "width": 416,
        "height": 544,
        "content": "## Severity check and alerts\n\nChecks the review severity and sends alerts to Slack."
      },
      "typeVersion": 1
    },
    {
      "id": "6dac4b91-a5bd-44df-8342-b2eefd358678",
      "name": "When PR Opened",
      "type": "n8n-nodes-base.githubTrigger",
      "position": [
        -1264,
        192
      ],
      "parameters": {
        "owner": "={{ $vars.GITHUB_OWNER }}",
        "events": [
          "pull_request"
        ],
        "options": {},
        "repository": "={{ $vars.GITHUB_REPO }}",
        "authentication": "oAuth2"
      },
      "typeVersion": 1
    },
    {
      "id": "5946aa5f-9949-42ca-adb7-e895e7a740bd",
      "name": "Check PR Open",
      "type": "n8n-nodes-base.if",
      "position": [
        -1040,
        192
      ],
      "parameters": {
        "conditions": {
          "string": [
            {
              "value1": "={{ $json.action }}",
              "value2": "opened"
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "24978946-9b3f-4b2f-91f8-2212b6000eb9",
      "name": "Fetch PR Diff",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -816,
        192
      ],
      "parameters": {
        "url": "={{ $json.pull_request.diff_url }}",
        "options": {
          "response": {
            "response": {
              "responseFormat": "text"
            }
          }
        },
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Accept",
              "value": "application/vnd.github.v3.diff"
            },
            {
              "name": "Authorization",
              "value": "=Bearer {{ $vars.GITHUB_TOKEN }}"
            }
          ]
        }
      },
      "typeVersion": 4.1
    },
    {
      "id": "e38e529b-bf33-4c31-a36b-cc0346934cbc",
      "name": "Format PR Diff",
      "type": "n8n-nodes-base.code",
      "position": [
        -608,
        192
      ],
      "parameters": {
        "jsCode": "const triggerData = $('When PR Opened').first().json;\nconst diffRaw = $input.first().json.data;\n\nconst MAX_DIFF_CHARS = 12000;\nconst diffStr = typeof diffRaw === 'string' ? diffRaw : JSON.stringify(diffRaw);\nconst diff = diffStr.slice(0, MAX_DIFF_CHARS);\nconst truncated = diffStr.length > MAX_DIFF_CHARS;\n\nreturn [{\n  json: {\n    diff,\n    truncated,\n    pr_number: triggerData.number,\n    pr_title: triggerData.pull_request.title,\n    pr_body: triggerData.pull_request.body || '',\n    pr_url: triggerData.pull_request.html_url,\n    repo_full_name: triggerData.repository.full_name,\n    owner: triggerData.repository.owner.login,\n    repo: triggerData.repository.name,\n    author: triggerData.pull_request.user.login,\n    base_branch: triggerData.pull_request.base.ref,\n    head_branch: triggerData.pull_request.head.ref\n  }\n}];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "6f11c0ff-49a8-4323-807d-c6a91a47414a",
      "name": "AI Code Review with GPT-4",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        -384,
        192
      ],
      "parameters": {
        "resource": "chat"
      },
      "typeVersion": 1.4
    },
    {
      "id": "129f584c-ab65-4bf5-8622-5a57d35bdef5",
      "name": "Build Comment for GitHub",
      "type": "n8n-nodes-base.code",
      "position": [
        -160,
        192
      ],
      "parameters": {
        "jsCode": "const rawContent = $input.first().json.message?.content\n  || $input.first().json.choices?.[0]?.message?.content\n  || '';\nconst prevData = $('Format PR Diff').first().json;\n\nlet review;\ntry {\n  const cleaned = rawContent.replace(/```json|```/g, '').trim();\n  review = JSON.parse(cleaned);\n} catch (e) {\n  review = {\n    severity: 'MEDIUM',\n    summary: 'Review parsing failed. Please inspect the raw AI output.',\n    issues: [],\n    positives: [],\n    overall_score: 5\n  };\n}\n\nconst severityEmoji = { CRITICAL: '\ud83d\udd34', HIGH: '\ud83d\udfe0', MEDIUM: '\ud83d\udfe1', LOW: '\ud83d\udfe2' };\nconst emoji = severityEmoji[review.severity] || '\u26aa';\n\nlet comment = `## ${emoji} AI Code Review \u2014 Severity: **${review.severity}**\\n\\n`;\ncomment += `**Overall Score:** ${review.overall_score}/10\\n\\n`;\ncomment += `### \ud83d\udccb Summary\\n${review.summary}\\n\\n`;\n\nif (review.issues && review.issues.length > 0) {\n  comment += `### \ud83d\udea8 Issues (${review.issues.length})\\n\\n`;\n  for (const issue of review.issues) {\n    const ie = severityEmoji[issue.severity] || '\u26aa';\n    comment += `<details>\\n<summary>${ie} [${issue.severity}] ${issue.category?.toUpperCase()} \u2014 ${issue.file}${issue.line ? ` (line ${issue.line})` : ''}</summary>\\n\\n`;\n    comment += `**Issue:** ${issue.description}\\n\\n**Suggestion:** ${issue.suggestion}\\n\\n</details>\\n\\n`;\n  }\n}\n\nif (review.positives && review.positives.length > 0) {\n  comment += `### \u2705 Positives\\n`;\n  review.positives.forEach(p => { comment += `- ${p}\\n`; });\n  comment += '\\n';\n}\n\ncomment += `---\\n*Reviewed by GPT-4o via n8n \u00b7 [View PR](${prevData.pr_url})*`;\n\nreturn [{\n  json: {\n    ...prevData,\n    review,\n    comment_body: comment,\n    is_critical: review.severity === 'CRITICAL',\n    severity: review.severity,\n    score: review.overall_score\n  }\n}];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "adebde26-84a2-4675-b007-022f8824722d",
      "name": "Post Comment to GitHub",
      "type": "n8n-nodes-base.github",
      "position": [
        64,
        192
      ],
      "parameters": {
        "body": "={{ $json.comment_body }}",
        "owner": "={{ $json.owner }}",
        "operation": "createComment",
        "repository": "={{ $json.repo }}",
        "issueNumber": "={{ $json.pr_number }}",
        "authentication": "oAuth2"
      },
      "typeVersion": 1
    },
    {
      "id": "9eca81e5-4a04-4268-86be-c2d45ee95734",
      "name": "Check Critical Severity",
      "type": "n8n-nodes-base.if",
      "position": [
        288,
        192
      ],
      "parameters": {
        "conditions": {
          "boolean": [
            {
              "value1": "={{ $('Build Comment for GitHub').first().json.is_critical }}",
              "value2": true
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "2adfd0d1-0e9b-4e21-81ba-80a5e11230a7",
      "name": "Alert Critical Issues to Slack",
      "type": "n8n-nodes-base.slack",
      "position": [
        512,
        64
      ],
      "parameters": {
        "text": "=\ud83d\udea8 *CRITICAL code review alert*\n\n*PR:* <{{ $('Build Comment for GitHub').first().json.pr_url }}|#{{ $('Build Comment for GitHub').first().json.pr_number }} \u2014 {{ $('Build Comment for GitHub').first().json.pr_title }}>\n*Author:* `{{ $('Build Comment for GitHub').first().json.author }}`\n*Repo:* `{{ $('Build Comment for GitHub').first().json.repo_full_name }}`\n*Score:* {{ $('Build Comment for GitHub').first().json.score }}/10\n\n*Summary:*\n{{ $('Build Comment for GitHub').first().json.review.summary }}\n\n\u26a0\ufe0f Immediate review required before merge.",
        "otherOptions": {
          "unfurl_links": false
        },
        "authentication": "oAuth2"
      },
      "typeVersion": 2.1
    },
    {
      "id": "316f8c82-6e75-480b-a867-93782a25fe4f",
      "name": "Share Review Summary on Slack",
      "type": "n8n-nodes-base.slack",
      "position": [
        512,
        304
      ],
      "parameters": {
        "text": "=\u2705 *PR review completed*\n\n*PR:* <{{ $('Build Comment for GitHub').first().json.pr_url }}|#{{ $('Build Comment for GitHub').first().json.pr_number }} \u2014 {{ $('Build Comment for GitHub').first().json.pr_title }}>\n*Author:* `{{ $('Build Comment for GitHub').first().json.author }}`\n*Severity:* {{ $('Build Comment for GitHub').first().json.severity }}\n*Score:* {{ $('Build Comment for GitHub').first().json.score }}/10\n\nAI review comment has been posted to the PR.",
        "otherOptions": {
          "unfurl_links": false
        },
        "authentication": "oAuth2"
      },
      "typeVersion": 2.1
    }
  ],
  "active": false,
  "settings": {
    "availableInMCP": false,
    "executionOrder": "v1"
  },
  "versionId": "51911461-f6f6-46ca-ad91-d10d36d33f9b",
  "connections": {
    "Check PR Open": {
      "main": [
        [
          {
            "node": "Fetch PR Diff",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch PR Diff": {
      "main": [
        [
          {
            "node": "Format PR Diff",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format PR Diff": {
      "main": [
        [
          {
            "node": "AI Code Review with GPT-4",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When PR Opened": {
      "main": [
        [
          {
            "node": "Check PR Open",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Post Comment to GitHub": {
      "main": [
        [
          {
            "node": "Check Critical Severity",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Critical Severity": {
      "main": [
        [
          {
            "node": "Alert Critical Issues to Slack",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Share Review Summary on Slack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Comment for GitHub": {
      "main": [
        [
          {
            "node": "Post Comment to GitHub",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Code Review with GPT-4": {
      "main": [
        [
          {
            "node": "Build Comment for GitHub",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

Engineering teams, code reviewers, and tech leads who want to automate code review feedback. Ideal for repositories with high PR volume where consistent first-pass review is valuable.

Source: https://n8n.io/workflows/15306/ — original creator credit. Request a take-down →

More AI & RAG workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

AI & RAG

This workflow automatically handles new GitHub issues by reading and understanding them using AI, then taking multiple actions simultaneously — creating tasks, sending notifications, and keeping every

Github Trigger, Slack, OpenAI +5
AI & RAG

This workflow automatically turns any audio file uploaded to Google Drive into a complete podcast episode. It handles transcription, content generation, blog drafting, social copy creation, thumbnail

Google Drive Trigger, Google Drive, OpenAI +3
AI & RAG

This workflow is an AI-powered lighting and look development pipeline designed for VFX production. It transforms a single lighting brief into multiple high-quality cinematic lighting references using

Form Trigger, HTTP Request, Google Drive +4
AI & RAG

Overview

Gmail Trigger, Google Drive, OpenAI +4
AI & RAG

How This Works This automation automatically scrapes leads from Apollo using the Apify scraper, filters out those who do not have an Email or URL included, scrapes the leads' website content and write

OpenAI, Google Sheets, HTTP Request +1