This workflow corresponds to n8n.io template #15918 — we link there as the canonical source.
This workflow follows the Agent → 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 →
{
"id": "LsnWpLAtXRBsnad1",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Review n8n workflows from Slack",
"tags": [
{
"id": "yUsi9lg2NP4uQpci",
"name": "template",
"createdAt": "2026-05-22T13:33:12.587Z",
"updatedAt": "2026-05-22T13:33:12.587Z"
}
],
"nodes": [
{
"id": "8cc19c01-1414-45d7-8197-3bf55eb547ef",
"name": "Slack: @mention or DM",
"type": "n8n-nodes-base.slackTrigger",
"position": [
-1520,
48
],
"parameters": {
"options": {
"userIds": "={{ [\"U0B4GBJEYE8\"] }}",
"resolveIds": false
},
"trigger": [
"app_mention",
"message"
],
"watchWorkspace": true
},
"credentials": {
"slackApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "babd6d7c-6278-4080-8f92-227ce1363cc3",
"name": "Keep mentions and DMs",
"type": "n8n-nodes-base.filter",
"position": [
-1296,
48
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "or",
"conditions": [
{
"id": "bd288eda-5c22-4172-9b40-b00b7ddb4185",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.type }}",
"rightValue": "app_mention"
},
{
"id": "9dbbc229-e65f-4558-9632-692ff13b2be5",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.channel_type }}",
"rightValue": "im"
}
]
}
},
"typeVersion": 2.3
},
{
"id": "8f2f6fcc-31e0-42aa-a3b4-f2ee46b602ec",
"name": "Add Eyes Reaction",
"type": "n8n-nodes-base.slack",
"position": [
-1072,
48
],
"parameters": {
"name": "eyes",
"resource": "reaction",
"channelId": {
"__rl": true,
"mode": "id",
"value": "={{ $json.channel }}"
},
"timestamp": "={{ $json.ts }}"
},
"credentials": {
"slackApi": {
"name": "<your credential>"
}
},
"retryOnFail": true,
"typeVersion": 2.4,
"waitBetweenTries": 5000
},
{
"id": "50049c18-b721-4b4f-b00c-2b51e1be7c9f",
"name": "Parse URL",
"type": "n8n-nodes-base.set",
"position": [
-864,
48
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "channel",
"name": "channel",
"type": "string",
"value": "={{ $('Slack: @mention or DM').item.json.channel }}"
},
{
"id": "ts",
"name": "ts",
"type": "string",
"value": "={{ $('Slack: @mention or DM').item.json.ts }}"
},
{
"id": "thread_ts",
"name": "thread_ts",
"type": "string",
"value": "={{ $('Slack: @mention or DM').item.json.thread_ts || $('Slack: @mention or DM').item.json.ts }}"
},
{
"id": "rawText",
"name": "rawText",
"type": "string",
"value": "={{ $('Slack: @mention or DM').item.json.text }}"
},
{
"id": "workflowId",
"name": "workflowId",
"type": "string",
"value": "={{ (() => { const text = $('Slack: @mention or DM').item.json.text || ''; const m = text.match(/\\/workflow\\/([A-Za-z0-9_-]+)/); return m ? m[1] : ''; })() }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "6d6f2252-b1e6-4d14-967e-5577a5aafc06",
"name": "Valid URL?",
"type": "n8n-nodes-base.if",
"position": [
-656,
48
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"operator": {
"type": "string",
"operation": "notEmpty"
},
"leftValue": "={{ $json.workflowId }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.3
},
{
"id": "e976538a-153d-4879-8781-81917d14e1ac",
"name": "Get Top-Level Workflow",
"type": "n8n-nodes-base.n8n",
"onError": "continueErrorOutput",
"position": [
-416,
48
],
"parameters": {
"operation": "get",
"workflowId": {
"__rl": true,
"mode": "id",
"value": "={{ $json.workflowId }}"
},
"requestOptions": {}
},
"credentials": {
"n8nApi": {
"name": "<your credential>"
}
},
"retryOnFail": true,
"typeVersion": 1
},
{
"id": "fd495032-9187-47f4-9a7b-4e31a337a040",
"name": "Remove Reaction (Bad URL)",
"type": "n8n-nodes-base.slack",
"onError": "continueRegularOutput",
"position": [
-640,
1008
],
"parameters": {
"name": "eyes",
"resource": "reaction",
"channelId": {
"__rl": true,
"mode": "id",
"value": "={{ $('Parse URL').item.json.channel }}"
},
"operation": "remove",
"timestamp": "={{ $('Parse URL').item.json.ts }}"
},
"credentials": {
"slackApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.4
},
{
"id": "5396243d-ea95-4a82-975b-b76c1a222266",
"name": "Post Error: Bad URL",
"type": "n8n-nodes-base.slack",
"position": [
-416,
1008
],
"parameters": {
"text": "Workflow Review - Could not find a workflow URL",
"select": "channel",
"blocksUi": "={{ { blocks: [ { type: 'header', text: { type: 'plain_text', text: 'Could not find a workflow URL' } }, { type: 'section', text: { type: 'mrkdwn', text: 'Send me a workflow URL like `https://<your-n8n-host>/workflow/<id>` and I will review it.' } }, { type: 'context', elements: [ { type: 'mrkdwn', text: '*You said:* ' + ($('Parse URL').item.json.rawText || '').slice(0, 500) } ] } ] } }}",
"channelId": {
"__rl": true,
"mode": "id",
"value": "={{ $('Parse URL').item.json.channel }}"
},
"messageType": "block",
"otherOptions": {
"mrkdwn": true,
"thread_ts": {
"replyValues": {
"thread_ts": "={{ $('Parse URL').item.json.thread_ts }}"
}
},
"unfurl_links": false,
"unfurl_media": false,
"includeLinkToWorkflow": false
}
},
"credentials": {
"slackApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.4
},
{
"id": "1b02aebd-88b9-4949-a9c3-944132e32f1e",
"name": "Remove Reaction (Fetch Failed)",
"type": "n8n-nodes-base.slack",
"onError": "continueRegularOutput",
"position": [
-640,
816
],
"parameters": {
"name": "eyes",
"resource": "reaction",
"channelId": {
"__rl": true,
"mode": "id",
"value": "={{ $('Parse URL').item.json.channel }}"
},
"operation": "remove",
"timestamp": "={{ $('Parse URL').item.json.ts }}"
},
"credentials": {
"slackApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.4
},
{
"id": "7be3a1e5-ad4c-44a1-9427-a81af25f09a4",
"name": "Post Error: Fetch Failed",
"type": "n8n-nodes-base.slack",
"position": [
-416,
816
],
"parameters": {
"text": "Workflow Review - Could not fetch the workflow",
"select": "channel",
"blocksUi": "={{ { blocks: [ { type: 'header', text: { type: 'plain_text', text: 'Could not fetch the workflow' } }, { type: 'section', text: { type: 'mrkdwn', text: 'The n8n API did not return that workflow. Common causes: wrong ID, archived workflow, MCP access disabled, or the n8nApi credential lacks permission.' } }, { type: 'context', elements: [ { type: 'mrkdwn', text: '*Workflow ID:* `' + $('Parse URL').item.json.workflowId + '`' } ] } ] } }}",
"channelId": {
"__rl": true,
"mode": "id",
"value": "={{ $('Parse URL').item.json.channel }}"
},
"messageType": "block",
"otherOptions": {
"mrkdwn": true,
"thread_ts": {
"replyValues": {
"thread_ts": "={{ $('Parse URL').item.json.thread_ts }}"
}
},
"unfurl_links": false,
"unfurl_media": false,
"includeLinkToWorkflow": false
}
},
"credentials": {
"slackApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.4
},
{
"id": "3279164a-f628-4cd8-ba36-29d67db4a1e6",
"name": "Fetch Review Checklist",
"type": "n8n-nodes-base.httpRequest",
"onError": "continueErrorOutput",
"position": [
-160,
48
],
"parameters": {
"url": "https://raw.githubusercontent.com/n8n-io/skills/main/skills/n8n-workflow-lifecycle/references/REVIEW_CHECKLIST.md",
"options": {
"timeout": 10000,
"response": {
"response": {
"responseFormat": "text",
"outputPropertyName": "checklistMarkdown"
}
}
}
},
"retryOnFail": true,
"typeVersion": 4.4
},
{
"id": "86a0dba8-5415-4cc2-807a-f1a4022d61d8",
"name": "Remove Reaction (Checklist Failed)",
"type": "n8n-nodes-base.slack",
"onError": "continueRegularOutput",
"position": [
-640,
624
],
"parameters": {
"name": "eyes",
"resource": "reaction",
"channelId": {
"__rl": true,
"mode": "id",
"value": "={{ $('Parse URL').item.json.channel }}"
},
"operation": "remove",
"timestamp": "={{ $('Parse URL').item.json.ts }}"
},
"credentials": {
"slackApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.4
},
{
"id": "7e717227-5bd4-4686-81b6-a441d69a8fa5",
"name": "Post Error: Checklist Failed",
"type": "n8n-nodes-base.slack",
"position": [
-416,
624
],
"parameters": {
"text": "Workflow Review - Could not reach the review checklist",
"select": "channel",
"blocksUi": "={{ { blocks: [ { type: 'header', text: { type: 'plain_text', text: 'Could not reach the review checklist' } }, { type: 'section', text: { type: 'mrkdwn', text: 'I could not pull REVIEW_CHECKLIST.md from the public n8n-io/skills repo. This is almost always transient (GitHub rate limit or hiccup). Try again in a minute.' } }, { type: 'context', elements: [ { type: 'mrkdwn', text: '*Tried:* raw.githubusercontent.com/n8n-io/skills/main/skills/n8n-workflow-lifecycle/references/REVIEW_CHECKLIST.md' } ] } ] } }}",
"channelId": {
"__rl": true,
"mode": "id",
"value": "={{ $('Parse URL').item.json.channel }}"
},
"messageType": "block",
"otherOptions": {
"mrkdwn": true,
"thread_ts": {
"replyValues": {
"thread_ts": "={{ $('Parse URL').item.json.thread_ts }}"
}
},
"unfurl_links": false,
"unfurl_media": false,
"includeLinkToWorkflow": false
}
},
"credentials": {
"slackApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.4
},
{
"id": "1dca61d6-4de7-4103-ae3d-e67f2b8d558a",
"name": "Extract Subworkflow IDs",
"type": "n8n-nodes-base.set",
"position": [
368,
64
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "subworkflowIds",
"name": "subworkflowIds",
"type": "array",
"value": "={{ (() => { const nodes = $('Get Top-Level Workflow').first().json.nodes || []; const ids = nodes.filter(n => n.type === 'n8n-nodes-base.executeWorkflow').map(n => n.parameters && n.parameters.workflowId && n.parameters.workflowId.value).filter(id => typeof id === 'string' && id.length > 0); return Array.from(new Set(ids)); })() }}"
}
]
},
"includeOtherFields": true
},
"typeVersion": 3.4
},
{
"id": "d42677f6-58fc-4847-a1e4-1efd61f6e76d",
"name": "Split Out Subworkflow IDs",
"type": "n8n-nodes-base.splitOut",
"position": [
864,
-32
],
"parameters": {
"options": {},
"fieldToSplitOut": "subworkflowIds"
},
"typeVersion": 1
},
{
"id": "338d506c-a614-4a7c-a40b-ac2f6e690c84",
"name": "Get Each Subworkflow",
"type": "n8n-nodes-base.n8n",
"notes": "continues on fail",
"onError": "continueRegularOutput",
"position": [
1072,
-32
],
"parameters": {
"operation": "get",
"workflowId": {
"__rl": true,
"mode": "id",
"value": "={{ $json.subworkflowIds }}"
},
"requestOptions": {}
},
"credentials": {
"n8nApi": {
"name": "<your credential>"
}
},
"notesInFlow": true,
"retryOnFail": true,
"typeVersion": 1
},
{
"id": "372796db-d14a-4d0b-a803-bbb7ab73a7c7",
"name": "Aggregate Subworkflows",
"type": "n8n-nodes-base.aggregate",
"position": [
1280,
-32
],
"parameters": {
"options": {},
"aggregate": "aggregateAllItemData",
"destinationFieldName": "subworkflows"
},
"typeVersion": 1
},
{
"id": "85bcdb33-8597-443f-8ac3-7a36e023cae9",
"name": "Combine Branches",
"type": "n8n-nodes-base.merge",
"position": [
1552,
64
],
"parameters": {},
"typeVersion": 3.2
},
{
"id": "36fe785d-7a5e-4216-abfc-6b20c77b5485",
"name": "Empty Subworkflows",
"type": "n8n-nodes-base.set",
"position": [
1296,
160
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "subworkflows",
"name": "subworkflows",
"type": "array",
"value": "={{ [] }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "58166ae5-7c29-475f-92c5-adb73da3c0c8",
"name": "Build Agent Payload",
"type": "n8n-nodes-base.set",
"position": [
1776,
64
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "topLevelWorkflow",
"name": "topLevelWorkflow",
"type": "object",
"value": "={{ $('Get Top-Level Workflow').first().json }}"
},
{
"id": "subworkflows",
"name": "subworkflows",
"type": "array",
"value": "={{ ($json.subworkflows || []).filter(item => !item.error) }}"
},
{
"id": "reviewChecklist",
"name": "reviewChecklist",
"type": "string",
"value": "={{ $('Fetch Review Checklist').first().json.checklistMarkdown }}"
},
{
"id": "skillFiles",
"name": "skillFiles",
"type": "string",
"value": "={{ JSON.stringify(($('Fetch Skill Files Index').first().json.tree || []).filter(item => item.type === 'blob' && item.path.endsWith('.md') && item.path.startsWith('skills/')).filter(item => { const name = item.path.toLowerCase().split('/').pop(); return name !== 'readme.md' && name !== 'license' && name !== 'license.md'; }).map(item => item.path), null, 2) }}"
}
]
}
},
"executeOnce": true,
"typeVersion": 3.4
},
{
"id": "f21c6d2d-bf4b-434f-8ebf-2b24e5418eee",
"name": "Reviewer Agent",
"type": "@n8n/n8n-nodes-langchain.agent",
"onError": "continueErrorOutput",
"maxTries": 2,
"position": [
2000,
64
],
"parameters": {
"text": "={{ 'AVAILABLE SKILL FILES (every markdown file path inside the public n8n-io/skills repo - fetch any of these via the Get Skill File tool):\\n\\n' + $json.skillFiles + '\\n\\n---\\n\\nREVIEW_CHECKLIST.md (your primary guide, fetched from n8n-io/skills):\\n\\n' + $json.reviewChecklist + '\\n\\n---\\n\\nTARGET WORKFLOW JSON:\\n' + JSON.stringify($json.topLevelWorkflow) + '\\n\\nDIRECT SUBWORKFLOW JSONS (' + $json.subworkflows.length + '):\\n' + JSON.stringify($json.subworkflows) }}",
"options": {
"maxIterations": 50,
"systemMessage": "=You are an n8n workflow reviewer. You review n8n workflows for security, correctness, and best practices, then produce a Slack Block Kit reply.\n\nCurrent date: {{ $now }}\n\n## How you work\nYour input message contains four things, in order:\n1. AVAILABLE SKILL FILES - a JSON list of every markdown file path inside the public n8n-io/skills repo. This is the catalog of canonical evidence you can fetch via the Get Skill File tool.\n2. REVIEW_CHECKLIST.md - the canonical, severity-tiered review checklist from the same repo. This is your primary guide. Walk it top to bottom and decide which items apply to the JSON.\n3. TARGET WORKFLOW JSON - the workflow the user pasted.\n4. DIRECT SUBWORKFLOW JSONS - every workflow that the target directly references via Execute Sub-workflow nodes (one level deep, not recursive).\n\nYou also have one tool:\n- Get Skill File - fetches the raw markdown of any path in the AVAILABLE SKILL FILES list. Use it to drill into a canonical reference whenever the checklist points you at one (e.g., REVIEW_CHECKLIST.md links to ../../n8n-credentials-and-security/SKILL.md - the absolute path is skills/n8n-credentials-and-security/SKILL.md). Use concurrent tool calls when fetching multiple references.\n\nYou do NOT have access to the n8n MCP or any other system. The JSONs, the checklist, and the skill files you fetch in this run are the entire universe of evidence.\n\n## You have NO built-in knowledge of n8n\nThis is the most important rule. You must not rely on training data, prior n8n knowledge, or remembered conventions. Every finding you produce must be grounded in BOTH:\n1. The TARGET WORKFLOW JSON / DIRECT SUBWORKFLOW JSONS (what is actually in the workflow), AND\n2. The REVIEW_CHECKLIST.md or a skill file you have fetched in this run via Get Skill File (the canonical rule the finding is based on).\n\nConcrete consequences:\n- Before citing a skill, a reference file, or a named convention (e.g., COMMS_NODES.md, NAMING_CONVENTIONS.md, API_WORKFLOWS.md, n8n-expressions, etc.), you MUST have fetched that file in this run via Get Skill File. Do not cite from memory.\n- If REVIEW_CHECKLIST.md references a deeper file and you have not fetched it, fetch it before writing the finding that depends on it. Use concurrent tool calls to batch.\n- If the AVAILABLE SKILL FILES list does not contain a file you were about to cite, that file does not exist. Do not invent paths.\n- If you cannot find a canonical rule that backs a finding, drop the finding. Speculative best practices from training data are not acceptable.\n\n## Reviewing scope\nTreat the target workflow + its direct subworkflows as one build. When a finding involves a subworkflow, name the subworkflow in the finding. Don't comment on issues inside subworkflows-of-subworkflows; those aren't in scope.\n\n## Severity tiers (from REVIEW_CHECKLIST.md)\n- MUST FIX - ship-blocker (security, broken connections, production-breaking bugs).\n- SHOULD FIX - real issue (antipatterns, missing error handling, broken contracts).\n- NICE TO HAVE - polish (naming, descriptions, conventions).\n\n## Overall grade\nPick exactly one of these labels based on findings:\n- Critical - at least one MUST FIX involving security or broken connections.\n- Needs work - multiple MUST FIX findings OR many SHOULD FIX findings.\n- Fair - 1 MUST FIX, OR several SHOULD FIX findings.\n- Good - 0 MUST FIX, a few SHOULD FIX, otherwise clean.\n- Excellent - 0 MUST FIX, at most 1 SHOULD FIX.\n\n## Output format\nRespond with raw JSON only (no markdown code fence) matching:\n{\n \"grade\": \"<one of the 5 labels above>\",\n \"overview\": \"<one short paragraph: workflow purpose + headline findings, <= 600 chars>\",\n \"blocks\": [ <Slack Block Kit blocks array> ]\n}\n\n## Block Kit guidance\n- Open with a header block: Workflow Review - <grade>.\n- Section block for the overview paragraph (mrkdwn).\n- Divider.\n- One header block per severity tier you have findings for: Must fix, Should fix, Nice to have. Skip a tier if it has zero findings.\n- Under each tier header, one section block per finding. Format the mrkdwn as:\n *<short title>* - <one-sentence description>\n `<affected node name or workflow name>`\n -> <one-line fix hint, with the skill reference name if applicable>\n- End with a context block citing which REVIEW_CHECKLIST.md sections you walked AND which skill files you fetched in this run.\n- Hard caps: 45 blocks total, each section's text.text <= 2800 chars, each header's text.text <= 150 chars.\n- mrkdwn only in section bodies. Use Slack's mrkdwn dialect (*bold*, _italic_, backticks for code).\n\n## Important\n- Load as many skills as needed, even if you pull all of them. It's better to get too many than not enough\n- Cite specific node names and (for subworkflows) the subworkflow name.\n- Don't invent issues. If the workflow is clean, return a short review and Excellent.\n- DO NOT wrap the JSON output in a markdown code block.\n- Reach 45 blocks at most. If you have more findings, collapse the lowest-severity ones into a single section."
},
"promptType": "define",
"hasOutputParser": true
},
"retryOnFail": true,
"typeVersion": 3.1
},
{
"id": "35760b71-a6f8-499e-8070-75a60a3b21db",
"name": "Get Skill File",
"type": "n8n-nodes-base.httpRequestTool",
"position": [
2096,
496
],
"parameters": {
"url": "={{ 'https://raw.githubusercontent.com/n8n-io/skills/main/' + $fromAI('path', 'Path to a markdown file inside the n8n-io/skills repo, relative to repo root. The REVIEW_CHECKLIST.md you already have contains relative links like ../../n8n-credentials-and-security/SKILL.md from inside skills/n8n-workflow-lifecycle/references/. To fetch that, the absolute path here is skills/n8n-credentials-and-security/SKILL.md. Always start with skills/. No leading slash.', 'string') }}",
"options": {
"timeout": 10000,
"response": {
"response": {
"responseFormat": "text"
}
}
},
"toolDescription": "Fetches the raw markdown of a file inside the public n8n-io/skills GitHub repo. This is your ONLY source of canonical n8n rules - you have no built-in knowledge to fall back on, so you MUST use this tool to ground every finding you make. Fetch any skill file whose path appears in the AVAILABLE SKILL FILES list (provided at the top of your input). Resolve relative links from REVIEW_CHECKLIST.md to absolute repo paths and pass them as the path parameter. Use concurrent tool calls when you need multiple files. Never cite a skill file you have not fetched in this run. Returns the file content as plain markdown."
},
"typeVersion": 4.4
},
{
"id": "ce05af43-920a-45ff-8aa8-eb6abe815468",
"name": "Block Kit Output Parser",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"position": [
2272,
416
],
"parameters": {
"prompt": "Instructions:\n--------------\n{instructions}\n--------------\nCompletion:\n--------------\n{completion}\n--------------\nAbove, the Completion did not satisfy the constraints given in the Instructions.\nError:\n--------------\n{error}\n--------------\nPlease try again. Only respond with JSON that satisfies the constraints. DO NOT wrap the output in a markdown code block.",
"autoFix": true,
"schemaType": "manual",
"inputSchema": "{\"type\":\"object\",\"properties\":{\"grade\":{\"type\":\"string\",\"enum\":[\"Excellent\",\"Good\",\"Fair\",\"Needs work\",\"Critical\"],\"description\":\"Overall grade label based on severity tier counts.\"},\"overview\":{\"type\":\"string\",\"description\":\"One short paragraph (<= 600 chars) summarizing the workflow purpose and headline findings.\"},\"blocks\":{\"type\":\"array\",\"description\":\"A valid Slack Block Kit blocks array. Use header, section, divider, context blocks. Max 45 blocks total. Each section text.text mrkdwn <= 2800 chars.\",\"items\":{\"type\":\"object\"}}},\"required\":[\"grade\",\"overview\",\"blocks\"]}",
"customizeRetryPrompt": true
},
"typeVersion": 1.3
},
{
"id": "46b61f15-eefe-4174-80be-0784c8365890",
"name": "Remove Reaction (Agent Failed)",
"type": "n8n-nodes-base.slack",
"onError": "continueRegularOutput",
"position": [
2624,
240
],
"parameters": {
"name": "eyes",
"resource": "reaction",
"channelId": {
"__rl": true,
"mode": "id",
"value": "={{ $('Parse URL').item.json.channel }}"
},
"operation": "remove",
"timestamp": "={{ $('Parse URL').item.json.ts }}"
},
"credentials": {
"slackApi": {
"name": "<your credential>"
}
},
"retryOnFail": true,
"typeVersion": 2.4,
"waitBetweenTries": 5000
},
{
"id": "1b54371f-44a5-41b0-a8bc-7a374ca9a626",
"name": "Post Error: Agent Failed",
"type": "n8n-nodes-base.slack",
"position": [
2848,
240
],
"parameters": {
"text": "Workflow Review - The reviewer agent failed",
"select": "channel",
"blocksUi": "={{ { blocks: [ { type: 'header', text: { type: 'plain_text', text: 'The reviewer agent failed' } }, { type: 'section', text: { type: 'mrkdwn', text: 'Something went wrong while running the review. Most common causes: OpenRouter rate-limited, the model temporarily unavailable, or the structured-output parser could not recover. Try again in a minute.' } }, { type: 'context', elements: [ { type: 'mrkdwn', text: '*Execution:* `' + $execution.id + '`' } ] } ] } }}",
"channelId": {
"__rl": true,
"mode": "id",
"value": "={{ $('Parse URL').item.json.channel }}"
},
"messageType": "block",
"otherOptions": {
"mrkdwn": true,
"thread_ts": {
"replyValues": {
"thread_ts": "={{ $('Parse URL').item.json.thread_ts }}"
}
},
"unfurl_links": false,
"unfurl_media": false,
"includeLinkToWorkflow": false
}
},
"credentials": {
"slackApi": {
"name": "<your credential>"
}
},
"retryOnFail": true,
"typeVersion": 2.4
},
{
"id": "14b3c4f9-baa8-462f-8df6-0f2707125bc4",
"name": "Remove Reaction (Success)",
"type": "n8n-nodes-base.slack",
"onError": "continueRegularOutput",
"position": [
2624,
-64
],
"parameters": {
"name": "eyes",
"resource": "reaction",
"channelId": {
"__rl": true,
"mode": "id",
"value": "={{ $('Parse URL').item.json.channel }}"
},
"operation": "remove",
"timestamp": "={{ $('Parse URL').item.json.ts }}"
},
"credentials": {
"slackApi": {
"name": "<your credential>"
}
},
"retryOnFail": true,
"typeVersion": 2.4
},
{
"id": "5d260f94-a2ed-4470-b9b4-3e6a5909d1eb",
"name": "Post Review Reply",
"type": "n8n-nodes-base.slack",
"onError": "continueErrorOutput",
"position": [
2848,
-64
],
"parameters": {
"text": "={{ 'Workflow Review - ' + $('Reviewer Agent').item.json.output.grade }}",
"select": "channel",
"blocksUi": "={{ { blocks: $('Reviewer Agent').item.json.output.blocks } }}",
"channelId": {
"__rl": true,
"mode": "id",
"value": "={{ $('Parse URL').item.json.channel }}"
},
"messageType": "block",
"otherOptions": {
"mrkdwn": true,
"thread_ts": {
"replyValues": {
"thread_ts": "={{ $('Parse URL').item.json.thread_ts }}"
}
},
"unfurl_links": false,
"unfurl_media": false,
"includeLinkToWorkflow": false
}
},
"credentials": {
"slackApi": {
"name": "<your credential>"
}
},
"retryOnFail": true,
"typeVersion": 2.4,
"waitBetweenTries": 5000
},
{
"id": "bc27c49c-3cda-4a04-be86-ff4ade6981cc",
"name": "OpenRouter Opus 4.7",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
"position": [
1840,
496
],
"parameters": {
"model": "anthropic/claude-opus-4.7",
"options": {
"temperature": 0.1
}
},
"credentials": {
"openRouterApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "5d4de331-96bd-45a9-ab07-4687d683bb9f",
"name": "Sticky: Subworkflow loop",
"type": "n8n-nodes-base.stickyNote",
"position": [
816,
-144
],
"parameters": {
"color": 7,
"width": 616,
"height": 282,
"content": "### Direct subworkflows (1 level deep)\nScan top-level for `executeWorkflow` nodes \u2192 split, fetch each workflow, then aggregate into a single list to pass into the agent. "
},
"typeVersion": 1
},
{
"id": "4aa2d7a7-662c-4c25-a13b-97c4de7bb5b5",
"name": "Sticky: Error paths",
"type": "n8n-nodes-base.stickyNote",
"position": [
-688,
256
],
"parameters": {
"color": 7,
"width": 460,
"height": 930,
"content": "## Error paths (always reply, never silent)\n\nEach path removes the `:eyes:` reaction and posts a Block Kit error in-thread with a hint about the likely cause. The bot is never left silently broken.\n\n_Note: i would have abstracted this into a single helper subworkflow so there is less duplication_ \ud83d\ude09"
},
"typeVersion": 1
},
{
"id": "148ab084-a1e5-4dc5-bb56-66a1f5ef78b5",
"name": "Has any subworkflows?",
"type": "n8n-nodes-base.if",
"position": [
624,
64
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "50ec2eb1-0a80-4553-acea-1bf24ef530c1",
"operator": {
"type": "array",
"operation": "notEmpty",
"singleValue": true
},
"leftValue": "={{ $json.subworkflowIds }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.3
},
{
"id": "29c7e9af-22f7-4458-9168-abe12344f747",
"name": "Fetch Skill Files Index",
"type": "n8n-nodes-base.httpRequest",
"onError": "continueErrorOutput",
"position": [
112,
48
],
"parameters": {
"url": "https://api.github.com/repos/n8n-io/skills/git/trees/main?recursive=1",
"options": {
"timeout": 10000
}
},
"retryOnFail": true,
"typeVersion": 4.4,
"waitBetweenTries": 5000
},
{
"id": "042b031d-c694-4023-9904-83f26815513a",
"name": "Remove Reaction (Skills Index Failed)",
"type": "n8n-nodes-base.slack",
"position": [
-640,
432
],
"parameters": {
"name": "eyes",
"resource": "reaction",
"channelId": {
"__rl": true,
"mode": "id",
"value": "={{ $('Parse URL').item.json.channel }}"
},
"operation": "remove",
"timestamp": "={{ $('Parse URL').item.json.ts }}"
},
"credentials": {
"slackApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.4
},
{
"id": "e91874db-fad0-4a72-b8f5-d318c32bbb83",
"name": "Post Error: Skills Index Failed",
"type": "n8n-nodes-base.slack",
"position": [
-416,
432
],
"parameters": {
"text": "Workflow Review - Could not load the skills directory",
"select": "channel",
"blocksUi": "={{ { blocks: [ { type: 'header', text: { type: 'plain_text', text: 'Could not load the skills directory' } }, { type: 'section', text: { type: 'mrkdwn', text: 'I couldn\\'t pull the file index for the public n8n-io/skills repo from GitHub. This is almost always transient (GitHub API rate limit or hiccup). Try again in a minute.' } }, { type: 'context', elements: [ { type: 'mrkdwn', text: '*Tried:* api.github.com/repos/n8n-io/skills/git/trees/main?recursive=1' } ] } ] } }}",
"channelId": {
"__rl": true,
"mode": "id",
"value": "={{ $('Parse URL').item.json.channel }}"
},
"messageType": "block",
"otherOptions": {
"mrkdwn": true,
"thread_ts": {
"replyValues": {
"thread_ts": "={{ $('Parse URL').item.json.thread_ts }}"
}
},
"unfurl_links": false,
"unfurl_media": false,
"includeLinkToWorkflow": false
}
},
"credentials": {
"slackApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.4
},
{
"id": "5c23b274-caa9-42f6-a991-2b18bb8d65f3",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2176,
-32
],
"parameters": {
"color": 7,
"width": 560,
"height": 944,
"content": "## Video of Claude Building this Workflow\n**This was built using Claude Code, [n8n MCP](https://docs.n8n.io/advanced-ai/mcp/accessing-n8n-mcp-server/), and [n8n skills](https://github.com/n8n-io/skills)**\n@[youtube](qgoGuwRpndU)\n_real video being released soon: here is the mcp video for now_\n\n# What This Is\nA Slack bot that reviews any n8n workflow you send it. Mention the bot or DM it with a workflow URL, and it replies in-thread with a graded review (Excellent \u2192 Critical), a short overview, and findings grouped into Must Fix / Should Fix / Nice to Have.\n\n### How it works\n\n1. Slack trigger fires on @mention or DM and adds an :eyes: reaction so you know it is working\n2. The workflow ID is extracted from the URL, then the target workflow and every direct subworkflow are fetched via the native n8n node\n3. The `REVIEW_CHECKLIST.md` and full list of skills is fetched from the n8n-io/skills repo\n4. Everything gets handed to the agent. The agent uses `Get Skill File` tool to load skills from GitHub as needed\n5. Output is structured JSON (grade, overview, Block Kit blocks)\n6. The review is posted as a single formatted reply in thread and the :eyes: reaction is removed. Any failure along the way still posts a Slack message with the likely cause, so the bot never breaks silently\n\n### Notes\n- Reviews top + direct children only (one level deep). Subworkflows-of-subworkflows are out of scope.\n- One-shot. No memory, no follow-ups, one reply per request."
},
"typeVersion": 1
},
{
"id": "d3ffe921-bbdf-488d-b95a-4e7889662ad6",
"name": "Pass Through",
"type": "n8n-nodes-base.noOp",
"position": [
864,
160
],
"parameters": {},
"typeVersion": 1
},
{
"id": "9d3f1b53-689a-4998-a3d8-c8bdd911f779",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
2576,
144
],
"parameters": {
"color": 3,
"width": 480,
"height": 272,
"content": "## Error Path\nIf there is an unexpected error, we still send a message to slack. You never want to fail silently"
},
"typeVersion": 1
},
{
"id": "7dacc2e9-582e-4c95-8541-3619df2f51f3",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
2560,
-160
],
"parameters": {
"color": 4,
"width": 496,
"height": 272,
"content": "## Success\nSend the review to the Slack thread\n"
},
"typeVersion": 1
},
{
"id": "b7d428dc-bb5a-4160-9e3e-0bb369be7d51",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
1760,
288
],
"parameters": {
"color": 7,
"width": 256,
"height": 352,
"content": "### LLM\nPick any LLM that:\n- [ ] Is good at coding\n- [ ] Has a large context length\n- [ ] You can afford \n(opus 4.7 is ~$2.80 to review this workflow while Kimi 2.6 is ~$0.12)"
},
"typeVersion": 1
},
{
"id": "3e53efcf-080c-45e9-86e7-cf33636870b1",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
2032,
288
],
"parameters": {
"color": 7,
"width": 208,
"height": 352,
"content": "### Get Skills\nThis is how the model actually gets the skills from [n8n-io/skills](https://github.com/n8n-io/skills).\n\nThe nodes before the workflow list of all the skills available for it to fetch"
},
"typeVersion": 1
},
{
"id": "758a46a9-491a-45aa-9dd5-f839dce4b3c3",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
2256,
288
],
"parameters": {
"color": 7,
"width": 272,
"height": 352,
"content": "### Output Parser\nThis is what tells the agent what format to output, which gives the next nodes something to reference"
},
"typeVersion": 1
},
{
"id": "d266c034-74bd-4301-851c-9cc0f957a0fe",
"name": "OpenRouter (Fixer)",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
"position": [
2352,
528
],
"parameters": {
"model": "anthropic/claude-sonnet-4.6",
"options": {
"temperature": 0
}
},
"credentials": {
"openRouterApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "a99e6655-544b-4ea7-b787-4179b4c19986",
"name": "Sticky Note6",
"type": "n8n-nodes-base.stickyNote",
"position": [
-224,
-48
],
"parameters": {
"color": 7,
"width": 512,
"height": 256,
"content": "### Gets Skill Info\nFetches the [review checklist](https://github.com/n8n-io/skills/blob/main/skills/n8n-workflow-lifecycle/references/REVIEW_CHECKLIST.md) and gets the list of all [available skills](https://github.com/n8n-io/skills/tree/main/skills) from the public GitHub repo"
},
"typeVersion": 1
}
],
"active": true,
"settings": {
"binaryMode": "separate",
"availableInMCP": false,
"executionOrder": "v1"
},
"versionId": "f1c9d407-f104-4adf-966b-e6dbc39a5beb",
"connections": {
"Parse URL": {
"main": [
[
{
"node": "Valid URL?",
"type": "main",
"index": 0
}
]
]
},
"Valid URL?": {
"main": [
[
{
"node": "Get Top-Level Workflow",
"type": "main",
"index": 0
}
],
[
{
"node": "Remove Reaction (Bad URL)",
"type": "main",
"index": 0
}
]
]
},
"Pass Through": {
"main": [
[
{
"node": "Empty Subworkflows",
"type": "main",
"index": 0
}
]
]
},
"Get Skill File": {
"ai_tool": [
[
{
"node": "Reviewer Agent",
"type": "ai_tool",
"index": 0
}
]
]
},
"Reviewer Agent": {
"main": [
[
{
"node": "Remove Reaction (Success)",
"type": "main",
"index": 0
}
],
[
{
"node": "Remove Reaction (Agent Failed)",
"type": "main",
"index": 0
}
]
]
},
"Combine Branches": {
"main": [
[
{
"node": "Build Agent Payload",
"type": "main",
"index": 0
}
]
]
},
"Add Eyes Reaction": {
"main": [
[
{
"node": "Parse URL",
"type": "main",
"index": 0
}
]
]
},
"Post Review Reply": {
"main": [
[],
[
{
"node": "Remove Reaction (Agent Failed)",
"type": "main",
"index": 0
}
]
]
},
"Empty Subworkflows": {
"main": [
[
{
"node": "Combine Branches",
"type": "main",
"index": 1
}
]
]
},
"OpenRouter (Fixer)": {
"ai_languageModel": [
[
{
"node": "Block Kit Output Parser",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Build Agent Payload": {
"main": [
[
{
"node": "Reviewer Agent",
"type": "main",
"index": 0
}
]
]
},
"OpenRouter Opus 4.7": {
"ai_languageModel": [
[
{
"node": "Reviewer Agent",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Get Each Subworkflow": {
"main": [
[
{
"node": "Aggregate Subworkflows",
"type": "main",
"index": 0
}
]
]
},
"Has any subworkflows?": {
"main": [
[
{
"node": "Split Out Subworkflow IDs",
"type": "main",
"index": 0
}
],
[
{
"node": "Pass Through",
"type": "main",
"index": 0
}
]
]
},
"Keep mentions and DMs": {
"main": [
[
{
"node": "Add Eyes Reaction",
"type": "main",
"index": 0
}
]
]
},
"Slack: @mention or DM": {
"main": [
[
{
"node": "Keep mentions and DMs",
"type": "main",
"index": 0
}
]
]
},
"Aggregate Subworkflows": {
"main": [
[
{
"node": "Combine Branches",
"type": "main",
"index": 0
}
]
]
},
"Fetch Review Checklist": {
"main": [
[
{
"node": "Fetch Skill Files Index",
"type": "main",
"index": 0
}
],
[
{
"node": "Remove Reaction (Checklist Failed)",
"type": "main",
"index": 0
}
]
]
},
"Get Top-Level Workflow": {
"main": [
[
{
"node": "Fetch Review Checklist",
"type": "main",
"index": 0
}
],
[
{
"node": "Remove Reaction (Fetch Failed)",
"type": "main",
"index": 0
}
]
]
},
"Block Kit Output Parser": {
"ai_outputParser": [
[
{
"node": "Reviewer Agent",
"type": "ai_outputParser",
"index": 0
}
]
]
},
"Extract Subworkflow IDs": {
"main": [
[
{
"node": "Has any subworkflows?",
"type": "main",
"index": 0
}
]
]
},
"Fetch Skill Files Index": {
"main": [
[
{
"node": "Extract Subworkflow IDs",
"type": "main",
"index": 0
}
],
[
{
"node": "Remove Reaction (Skills Index Failed)",
"type": "main",
"index": 0
}
]
]
},
"Remove Reaction (Bad URL)": {
"main": [
[
{
"node": "Post Error: Bad URL",
"type": "main",
"index": 0
}
]
]
},
"Remove Reaction (Success)": {
"main": [
[
{
"node": "Post Review Reply",
"type": "main",
"index": 0
}
]
]
},
"Split Out Subworkflow IDs": {
"main": [
[
{
"node": "Get Each Subworkflow",
"type": "main",
"index": 0
}
]
]
},
"Remove Reaction (Agent Failed)": {
"main": [
[
{
"node": "Post Error: Agent Failed",
"type": "main",
"index": 0
}
]
]
},
"Remove Reaction (Fetch Failed)": {
"main": [
[
{
"node": "Post Error: Fetch Failed",
"type": "main",
"index": 0
}
]
]
},
"Remove Reaction (Checklist Failed)": {
"main": [
[
{
"node": "Post Error: Checklist Failed",
"type": "main",
"index": 0
}
]
]
},
"Remove Reaction (Skills Index Failed)": {
"main": [
[
{
"node": "Post Error: Skills Index Failed",
"type": "main",
"index": 0
}
]
]
}
}
}
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.
n8nApiopenRouterApislackApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
A Slack bot that reviews any n8n workflow on demand. Mention it or DM it a workflow URL and it replies in-thread with a graded review, plain-English overview, and findings tiered as Must Fix, Should Fix, and Nice to Have. Triggers when the bot is @mentioned in Slack or receives…
Source: https://n8n.io/workflows/15918/ — 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.
Who is this for? Agencies, consultants, and service providers who conduct discovery calls and need to quickly turn conversations into professional proposals.
This n8n template builds a WhatsApp support copilot that answers **order status and product availability** from Shopify using LLM "agents," then replies to the customer in WhatsApp or routes to human
The AI-Powered Shopify SEO Content Automation is an enterprise-grade workflow that transforms product content creation for e-commerce stores. This sophisticated multi-agent system integrates GPT-4o, C
🧠 Automate end-to-end SEO blog creation and WordPress publishing using a GPT-5 multi-agent workflow with real-time research, metadata generation, and optional featured images.
YouTube Strategist. Uses formTrigger, splitOut, splitInBatches, agent. Event-driven trigger; 50 nodes.