This workflow follows the Executecommand → 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": "Code Review with Claude Subscription",
"nodes": [
{
"parameters": {
"formTitle": "Code Review",
"formFields": {
"values": [
{
"fieldLabel": "Merge Request ID",
"fieldName": "mr_iid",
"requiredField": true
},
{
"fieldLabel": "Project",
"fieldName": "project_id",
"defaultValue": "17"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.formTrigger",
"typeVersion": 2.5,
"position": [
-432,
-192
],
"id": "34e44e9c-b6f5-45ba-82e2-db8cdf0bccb0",
"name": "On form submission"
},
{
"parameters": {
"command": "if [ -d \"/home/node/nimble-client/.git\" ]; then\n git -C /home/node/nimble-client pull --ff-only\nelse\n git clone --depth 1 \"$REPO_URL\" /home/node/nimble-client\nfi"
},
"type": "n8n-nodes-base.executeCommand",
"typeVersion": 1,
"position": [
-240,
-192
],
"id": "a1b2c3d4-1111-2222-3333-444444444420",
"name": "Update Repo"
},
{
"parameters": {
"url": "={{ 'https://gitlab.ninternal.com/api/v4/projects/' + $('On form submission').item.json.project_id + '/merge_requests/' + $('On form submission').item.json.mr_iid + '/changes' }}",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "gitlabApi",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "PRIVATE-TOKEN",
"value": "={{ $env.GITLAB_TOKEN }}"
},
{}
]
},
"options": {}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.4,
"position": [
-16,
-32
],
"id": "5b77ab09-ca9e-4029-b044-86e794589939",
"name": "HTTP Request",
"credentials": {
"gitlabApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"jsCode": "// 1. Grab the 'changes' array from the previous node (HTTP Request)\n// .item is used to access the specific data object n8n just received\nconst changes = $input.first().json.changes;\n\n// 2. Filter out lock files and SVGs (Your exact Bun logic)\nconst filtered = changes.filter((c) => \n !c.new_path.includes(\"lock\") && !c.new_path.endsWith(\".svg\")\n);\n\n// 3. Format the diffs into a single clean string\nconst formattedDiffs = filtered\n .map((c) => `File: ${c.new_path}\\n${c.diff}`)\n .join(\"\\n\\n\");\n\n// 4. Return the data for the next step\nreturn { \n diff: formattedDiffs,\n hasChanges: filtered.length > 0 \n};"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
160,
-64
],
"id": "396cb0d0-5bae-47dd-a66a-c6a1d81f89aa",
"name": "Code in JavaScript"
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "set-system-prompt-001",
"name": "systemPrompt",
"value": "You are a Senior Staff Frontend Engineer doing an INDEPENDENT review of a Git diff. Do NOT hold back findings \u2014 a second reviewer will also review independently. Project: React/Redux + legacy Backbone.js. Uses JSDoc + React Compiler. Review Focus: 1. Correctness: logic, null/undefined, race conditions. 2. Performance: Redundant hooks (React Compiler handles these). 3. Clean Code: SRP, extract constants, prefer Native JS over Lodash. Rules: Be concise. Bullet points. Reference specific lines (+line 42). Tags: \ud83d\udd34 Critical | \ud83d\udfe1 Warning | \ud83d\udd35 Nit. Suggest concrete fix in code block. No memoization. FORMAT: Finding -> File: path | Line: +X -> Code block. If clean, say LGTM!. The full repository is mounted at /home/node/nimble-client. Diff paths are relative to the repo root. Read files only when the diff alone is insufficient to judge correctness (e.g. unclear import, missing context for a hook or utility). Do not read files speculatively.",
"type": "string"
},
{
"id": "set-diff-passthrough-001",
"name": "diff",
"value": "={{ $json.diff }}",
"type": "string"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
384,
-64
],
"id": "a1b2c3d4-1111-2222-3333-444444444410",
"name": "Review Prompt"
},
{
"parameters": {
"jsCode": "const { diff, systemPrompt } = $input.first().json;\nrequire('fs').writeFileSync('/tmp/review-prompt.txt', systemPrompt + '\\nDIFF TO REVIEW:\\n' + diff, 'utf8');\nreturn [{ json: {} }];"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
554,
-64
],
"id": "a1b2c3d4-1111-2222-3333-444444444407",
"name": "Build Prompt"
},
{
"parameters": {
"command": "claude -p --output-format text < /tmp/review-prompt.txt"
},
"type": "n8n-nodes-base.executeCommand",
"typeVersion": 1,
"position": [
724,
-200
],
"id": "4a528059-6bbe-4eaf-802b-2773fb14f005",
"name": "Claude Review"
},
{
"parameters": {
"command": "codex exec --full-auto --ephemeral --skip-git-repo-check - < /tmp/review-prompt.txt"
},
"type": "n8n-nodes-base.executeCommand",
"typeVersion": 1,
"position": [
724,
80
],
"id": "a1b2c3d4-1111-2222-3333-444444444401",
"name": "Codex Review"
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "set-claude-review-001",
"name": "review",
"value": "={{ $json.stdout }}",
"type": "string"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
964,
-200
],
"id": "a1b2c3d4-1111-2222-3333-444444444402",
"name": "Normalize Claude"
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "set-codex-review-001",
"name": "review",
"value": "={{ $json.stdout }}",
"type": "string"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
964,
80
],
"id": "a1b2c3d4-1111-2222-3333-444444444403",
"name": "Normalize Codex"
},
{
"parameters": {
"mode": "append",
"options": {}
},
"type": "n8n-nodes-base.merge",
"typeVersion": 3.2,
"position": [
1204,
-60
],
"id": "a1b2c3d4-1111-2222-3333-444444444404",
"name": "Wait for All"
},
{
"parameters": {
"jsCode": "const items = $input.all();\nconst claudeReview = items[0].json.review;\nconst gptReview = items[1].json.review;\n\nconst prompt = `You are synthesizing two independent code reviews of the same Git diff.\n\nINSTRUCTIONS:\n1. MERGE: Keep ALL findings. Where both reviewers flagged the same issue (same file/line or same problem), merge into one finding.\n2. ATTRIBUTE each finding with one of:\n - \"Found by: both\" \u2014 both reviewers independently flagged it\n - \"Found by: Claude\" (+ \"GPT-4o: supports inclusion\" if GPT-4o agrees, or \"GPT-4o: disagrees\" if not)\n - \"Found by: GPT-4o\" (+ \"Claude: supports inclusion\" if Claude agrees, or \"Claude: disagrees\" if not)\n3. FORMAT:\n - Start with: \"Overall risk: HIGH/MEDIUM/LOW \u2014 N high, N medium, N low findings\"\n - Each finding: \ud83d\udd34/\ud83d\udfe1/\ud83d\udd35 Title \u2192 File: path | Line: +X \u2192 code block \u2192 Fix suggestion \u2192 Found by: ...\n - If no issues at all, say LGTM!\n\nREVIEW 1 (Claude):\n${claudeReview}\n\nREVIEW 2 (GPT-4o):\n${gptReview}`;\n\nrequire('fs').writeFileSync('/tmp/synthesis-prompt.txt', prompt, 'utf8');\nreturn [{ json: {} }];"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1424,
-60
],
"id": "a1b2c3d4-1111-2222-3333-444444444405",
"name": "Build Synthesis Prompt"
},
{
"parameters": {
"command": "claude -p --output-format text < /tmp/synthesis-prompt.txt"
},
"type": "n8n-nodes-base.executeCommand",
"typeVersion": 1,
"position": [
1644,
-60
],
"id": "a1b2c3d4-1111-2222-3333-444444444406",
"name": "Claude Synthesis"
},
{
"parameters": {
"method": "POST",
"url": "=https://gitlab.ninternal.com/api/v4/projects/17/merge_requests/{{ $node[\"On form submission\"].json.mr_iid }}/notes",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "PRIVATE-TOKEN",
"value": "={{ $env.GITLAB_TOKEN }}"
},
{}
]
},
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "body",
"value": "={{ $json.stdout }}"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.4,
"position": [
1864,
-60
],
"id": "ab7b322d-c97c-400a-9637-9c7d28e5bf6e",
"name": "HTTP Request1"
}
],
"connections": {
"On form submission": {
"main": [
[
{
"node": "Update Repo",
"type": "main",
"index": 0
}
]
]
},
"Update Repo": {
"main": [
[
{
"node": "HTTP Request",
"type": "main",
"index": 0
}
]
]
},
"HTTP Request": {
"main": [
[
{
"node": "Code in JavaScript",
"type": "main",
"index": 0
}
]
]
},
"Code in JavaScript": {
"main": [
[
{
"node": "Review Prompt",
"type": "main",
"index": 0
}
]
]
},
"Review Prompt": {
"main": [
[
{
"node": "Build Prompt",
"type": "main",
"index": 0
}
]
]
},
"Build Prompt": {
"main": [
[
{
"node": "Claude Review",
"type": "main",
"index": 0
},
{
"node": "Codex Review",
"type": "main",
"index": 0
}
]
]
},
"Claude Review": {
"main": [
[
{
"node": "Normalize Claude",
"type": "main",
"index": 0
}
]
]
},
"Codex Review": {
"main": [
[
{
"node": "Normalize Codex",
"type": "main",
"index": 0
}
]
]
},
"Normalize Claude": {
"main": [
[
{
"node": "Wait for All",
"type": "main",
"index": 0
}
]
]
},
"Normalize Codex": {
"main": [
[
{
"node": "Wait for All",
"type": "main",
"index": 1
}
]
]
},
"Wait for All": {
"main": [
[
{
"node": "Build Synthesis Prompt",
"type": "main",
"index": 0
}
]
]
},
"Build Synthesis Prompt": {
"main": [
[
{
"node": "Claude Synthesis",
"type": "main",
"index": 0
}
]
]
},
"Claude Synthesis": {
"main": [
[
{
"node": "HTTP Request1",
"type": "main",
"index": 0
}
]
]
},
"HTTP Request1": {
"main": [
[]
]
}
},
"settings": {
"executionOrder": "v1",
"binaryMode": "separate",
"availableInMCP": false
},
"staticData": null,
"meta": {
"templateCredsSetupCompleted": true
}
}
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.
gitlabApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Code Review with Claude Subscription. Uses formTrigger, executeCommand, httpRequest. Event-driven trigger; 14 nodes.
Source: https://github.com/nazarenkodima/nimble-n8n/blob/216d805af20e76df23cfdb7775177c5749925949/workflows/workflow.json — 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.
This workflow allows you to import any workflow from a file or another n8n instance and map the credentials easily. A multi-form setup guides you through the entire process At the beginning you have t
Credentials Transfer. Uses form, httpRequest, executeCommand, readWriteFile. Event-driven trigger; 22 nodes.
Credentials Transfer. Uses form, httpRequest, executeCommand, readWriteFile. Event-driven trigger; 22 nodes.
[](https://youtu.be/xKqkjXIPZoM)
Stringify. Uses formTrigger, executeCommand, httpRequest, readWriteFile. Event-driven trigger; 7 nodes.