This workflow follows the Chainllm → 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 →
{
"name": "LLM Code Review in GitHub MR",
"nodes": [
{
"parameters": {
"content": "## Edit your own prompt \u2b07\ufe0f\n"
},
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
800,
460
],
"typeVersion": 1,
"id": "ff91ffff-cb3c-4921-8073-c3adee4e76c8"
},
{
"parameters": {
"content": "## Filter comments and customize your trigger words \u2b07\ufe0f"
},
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-460,
500
],
"typeVersion": 1,
"id": "9c7d250f-77c0-490f-a221-760ffadb4532"
},
{
"parameters": {
"content": "## Replace your github URL and token \u2b07\ufe0f"
},
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-200,
480
],
"typeVersion": 1,
"id": "e8b8a21e-d934-4ed7-af3f-a9cb689cce08"
},
{
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "// \u89e3\u6790 patch \u7684\u51fd\u6570\nfunction parsePatch(patch) {\n const lines = patch.split('\\n');\n let lastOldLine = 0;\n let lastNewLine = 0;\n let positionLine = 0;\n const originalLines = [];\n const newLines = [];\n\n lines.forEach((line, index) => {\n const match = line.match(/^@@ -(\\d+),\\d+ \\+(\\d+),\\d+ @@/);\n if (match) {\n lastOldLine = parseInt(match[1]);\n lastNewLine = parseInt(match[2]);\n positionLine = lastNewLine + 1;\n } else if (line.startsWith('-')) {\n originalLines.push(line);\n } else if (line.startsWith('+')) {\n newLines.push(line);\n } else if (!line.startsWith('\\\\ No newline at end of file')) {\n originalLines.push(line);\n newLines.push(line);\n }\n });\n\n return {\n lastOldLine: lastOldLine,\n lastNewLine: lastNewLine,\n positionLine: positionLine,\n originalCode: originalLines.join('\\n'),\n newCode: newLines.join('\\n')\n };\n}\n\n// \u4ece\u8f93\u5165\u4e2d\u63d0\u53d6\u4fe1\u606f\nconst input = $json[\"patch\"];\nconst parsedData = parsePatch(input);\n\n// \u8f93\u51fa\nreturn {\n originalCode: parsedData.originalCode,\n newCode: parsedData.newCode\n};\n"
},
"name": "Code",
"type": "n8n-nodes-base.code",
"position": [
640,
460
],
"typeVersion": 2,
"id": "4dc1b952-2822-4a00-b3fb-382998e63ef5"
},
{
"parameters": {
"content": "## Replace your github URL and token \u2b07\ufe0f"
},
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
1120,
460
],
"typeVersion": 1,
"id": "644b5f17-2728-4503-be94-a49df5c96376"
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 1
},
"conditions": [
{
"operator": {
"type": "number",
"operation": "equals"
},
"leftValue": "={{ $json.body.pull_request.comments }}",
"rightValue": 0
}
],
"combinator": "and"
},
"options": {}
},
"name": "Need Review",
"type": "n8n-nodes-base.if",
"position": [
-400,
680
],
"typeVersion": 2,
"id": "5f93b317-3f3b-4bae-8941-74180c5c24c1"
},
{
"parameters": {
"url": "=https://api.github.com/repos/{{ $json[\"body\"][\"repository\"][\"full_name\"] }}/pulls/{{ $json[\"body\"][\"pull_request\"][\"number\"] }}/files",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "token YOUR_TOKEN"
}
]
},
"options": {}
},
"name": "Get Changes",
"type": "n8n-nodes-base.httpRequest",
"position": [
-140,
660
],
"typeVersion": 4.1,
"id": "298b696b-7bbf-4306-8b63-61f3a3f2b0ac"
},
{
"parameters": {
"fieldToSplitOut": "changes",
"include": "selectedOtherFields",
"fieldsToInclude": "patch",
"options": {
"disableDotNotation": false,
"destinationFieldName": "changes",
"includeBinary": false
}
},
"name": "Split Out",
"type": "n8n-nodes-base.splitOut",
"position": [
60,
660
],
"typeVersion": 1,
"id": "3db26038-4d63-43cf-8e19-55b121d57318"
},
{
"parameters": {
"conditions": {
"options": {
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"conditions": [
{
"operator": {
"type": "number",
"operation": "gt"
},
"leftValue": "={{ $json.changes }}",
"rightValue": 0
}
],
"combinator": "and"
},
"options": {}
},
"name": "Skip File Change",
"type": "n8n-nodes-base.if",
"position": [
260,
660
],
"typeVersion": 2,
"id": "939f3c1d-505b-4643-a6f4-9a80429aeb3e"
},
{
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "// \u89e3\u6790 patch \u7684\u51fd\u6570\nfunction parsePatch(patch) {\n const lines = patch.split('\\n');\n let lastOldLine = 0;\n let lastNewLine = 0;\n let positionLine = 0;\n const filteredLines = [];\n\n lines.forEach((line, index) => {\n // \u67e5\u627e @@ -17,6 +17,20 @@ \u5f62\u5f0f\u7684\u884c\uff0c\u5e76\u63d0\u53d6\u4fe1\u606f\n const match = line.match(/^@@ -(\\d+),\\d+ \\+(\\d+),\\d+ @@/);\n if (match) {\n lastOldLine = parseInt(match[1]);\n lastNewLine = parseInt(match[2]);\n positionLine = lastNewLine + 1;\n }\n // \u8fc7\u6ee4\u6389\u201cNo newline at end of file\u201d\u884c\n if (line.trim() !== '\\\\ No newline at end of file') {\n filteredLines.push(line);\n }\n });\n\n return {\n lastOldLine: lastOldLine,\n lastNewLine: lastNewLine,\n positionLine: positionLine,\n patch: filteredLines.join('\\n') // \u8fd4\u56de\u53bb\u6389\u591a\u4f59\u884c\u7684patch\n };\n}\n\n// \u4ece\u8f93\u5165\u4e2d\u63d0\u53d6\u4fe1\u606f\nconst input = $json[\"patch\"];\nconst changes = $json[\"changes\"];\nconst parsedData = parsePatch(input);\n\n// \u8f93\u51fa\nreturn {\n lastOldLine: parsedData.lastOldLine,\n lastNewLine: parsedData.lastNewLine,\n positionLine: changes, // \u786e\u4fdd positionLine \u7b49\u4e8e changes\n patch: parsedData.patch\n};\n"
},
"name": "Parse Last Diff Line",
"type": "n8n-nodes-base.code",
"position": [
460,
460
],
"typeVersion": 2,
"id": "e6e66503-6867-4266-8050-5ae3d938cd18"
},
{
"parameters": {
"method": "POST",
"url": "=https://api.github.com/repos/{{$('Webhook').item.json['body'].repository.full_name}}/pulls/{{ $('Webhook').item.json.body.pull_request.number }}/comments",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "token YOUR_TOKEN"
},
{
"name": "Content-Type",
"value": " application/json"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"body\": {{ JSON.stringify($('Basic LLM Chain').item.json[\"text\"]); }},\n \"commit_id\": {{ JSON.stringify($('Need Review').item.json.body.pull_request.head.sha); }},\n \"path\": {{ JSON.stringify($('Get Changes').item.json.filename); }},\n \"position\": {{ $('Parse Last Diff Line').item.json.positionLine }}\n}",
"options": {}
},
"name": "Post Discussions",
"type": "n8n-nodes-base.httpRequest",
"position": [
1200,
640
],
"typeVersion": 4.1,
"id": "31b93a2e-bf75-4dc3-bb9b-0de3b1d43c3a"
},
{
"parameters": {
"httpMethod": "POST",
"path": "4b8de672-fbc8-41c9-a4b4-a218579206cc",
"options": {}
},
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"position": [
-620,
680
],
"typeVersion": 1.1,
"id": "a6e39d35-7114-43bf-903b-b33ede1f3796"
},
{
"parameters": {
"model": "=GLM-4-Plus",
"options": {
"baseURL": "https://open.bigmodel.cn/api/paas/v4/"
}
},
"name": "big model",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
820,
780
],
"typeVersion": 1,
"id": "725bf6fb-0b89-496a-ab81-8a23d1091d42",
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"prompt": "=\n\n```Original code\n {{ $json.originalCode }}\n```\nchange to\n```New code\n {{ $json.newCode }}\n```\nPlease review the code changes in this section:",
"hasOutputParser": true,
"messages": {
"messageValues": [
{
"type": "AIMessagePromptTemplate",
"message": "# Overview:| \u60a8\u662f\u9ad8\u7ea7\u7f16\u7a0b\u4e13\u5bb6Bot\uff0c\u8d1f\u8d23\u5ba1\u67e5\u4ee3\u7801\u66f4\u6539\u5e76\u63d0\u4f9b\u5ba1\u67e5\u5efa\u8bae\u3002\u5728\u5efa\u8bae\u4e4b\u521d\uff0c\u9700\u8981\u660e\u786e\u505a\u51fa\u201c\u62d2\u7edd\u201d\u6216\u201c\u63a5\u53d7\u201d\u4ee3\u7801\u53d8\u66f4\u7684\u51b3\u5b9a\uff0c\u5e76\u4ee5\u201c\u53d8\u66f4\u5f97\u5206:\u5b9e\u9645\u5f97\u5206\u201d\u7684\u5f62\u5f0f\u5bf9\u53d8\u66f4\u8fdb\u884c\u8bc4\u5206\uff0c\u8bc4\u5206\u8303\u56f4\u4e3a0-100\u5206\u3002\u7136\u540e\uff0c\u4ee5\u7b80\u6d01\u7684\u8bed\u8a00\u548c\u4e25\u5389\u7684\u8bed\u6c14\u6307\u51fa\u5b58\u5728\u7684\u95ee\u9898\u3002\u5982\u679c\u60a8\u89c9\u5f97\u6709\u5fc5\u8981\uff0c\u53ef\u4ee5\u76f4\u63a5\u63d0\u4f9b\u4fee\u6539\u540e\u7684\u5185\u5bb9\u3002\u4f60\u7684\u8bc4\u5ba1\u63d0\u6848\u5fc5\u987b\u4f7f\u7528\u4e25\u683c\u7684Markdown\u683c\u5f0f"
}
]
}
},
"name": "Basic LLM Chain",
"type": "@n8n/n8n-nodes-langchain.chainLlm",
"position": [
800,
640
],
"typeVersion": 1.2,
"id": "db38a0e7-4c12-45eb-9cb5-f473441be4f9"
}
],
"connections": {
"Code": {
"main": [
[
{
"node": "Basic LLM Chain",
"type": "main",
"index": 0
}
]
]
},
"Need Review": {
"main": [
[
{
"node": "Get Changes",
"type": "main",
"index": 0
}
]
]
},
"Get Changes": {
"main": [
[
{
"node": "Split Out",
"type": "main",
"index": 0
}
]
]
},
"Split Out": {
"main": [
[
{
"node": "Skip File Change",
"type": "main",
"index": 0
}
]
]
},
"Skip File Change": {
"main": [
[
{
"node": "Parse Last Diff Line",
"type": "main",
"index": 0
}
]
]
},
"Parse Last Diff Line": {
"main": [
[
{
"node": "Code",
"type": "main",
"index": 0
}
]
]
},
"Webhook": {
"main": [
[
{
"node": "Need Review",
"type": "main",
"index": 0
}
]
]
},
"big model": {
"ai_languageModel": [
[
{
"node": "Basic LLM Chain",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Basic LLM Chain": {
"main": [
[
{
"node": "Post Discussions",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "4988315a-70cd-43b4-9f91-85408f6c5dc9",
"meta": {
"templateCredsSetupCompleted": true
},
"id": "YCTsv5Aohm9hZO3I",
"tags": [
{
"createdAt": "2024-10-31T11:12:04.946Z",
"updatedAt": "2024-10-31T11:12:04.946Z",
"id": "qFI4u1x8MkoOs1vC",
"name": "share"
}
]
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
openAiApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
LLM Code Review in GitHub MR. Uses httpRequest, lmChatOpenAi, chainLlm. Webhook trigger; 14 nodes.
Source: https://gist.github.com/JeaNile/0ee00f3a855385b4e60f50bf686695b3 — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
CLINICAINTEGRAL_secretary. Uses postgres, mcpClientTool, googleDriveTool, toolWorkflow. Webhook trigger; 89 nodes.
This n8n workflow orchestrates a powerful suite of AI Agents and automations to manage and optimize various aspects of an e-commerce operation, particularly for platforms like Shopify. It leverages La
The "Short Content" automation is a powerful, all-in-one solution designed to streamline the creation of short videos for social media, marketing, or personal projects. Leveraging cutting-edge AI tool
🔥 LIMITED-TIME OFFER: AI Video Automation (Previously \$59) Previously Template
leads. Uses supabase, gmail, formTrigger, httpRequest. Webhook trigger; 62 nodes.