AutomationFlowsAI & RAG › Triage Github Issues with Openai Categorization and Embedding-based…

Triage Github Issues with Openai Categorization and Embedding-based…

Original n8n title: Triage Github Issues with Openai Categorization and Embedding-based Duplicate Detection

ByAyaka Sato @ayakerocom on n8n.io

Open-source maintainers, product teams with public repositories, and any organization receiving a steady stream of GitHub Issues. Ideal for small teams who waste hours per week triaging duplicates and misrouted reports.

Webhook trigger★★★★★ complexityAI-powered30 nodesGitHubHTTP RequestOpenAISlackGoogle Sheets
AI & RAG Trigger: Webhook Nodes: 30 Complexity: ★★★★★ AI nodes: yes Added:

This workflow corresponds to n8n.io template #15251 — 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": "h5gumj6V5XNoMdBI",
  "name": "Triage GitHub Issues with AI Category and Embedding-Based Duplicate Detection",
  "tags": [],
  "nodes": [
    {
      "id": "745894c9-1ce4-4b32-8020-b8b961f09f12",
      "name": "GitHub Issue Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        80,
        368
      ],
      "parameters": {
        "path": "github-issue-triage",
        "options": {},
        "httpMethod": "POST"
      },
      "typeVersion": 2
    },
    {
      "id": "b01b74ef-9385-4aa7-a608-ddfbf0e59ad8",
      "name": "Set Configuration",
      "type": "n8n-nodes-base.set",
      "position": [
        288,
        368
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "cfg-1",
              "name": "github_owner",
              "type": "string",
              "value": "YOUR_GITHUB_OWNER"
            },
            {
              "id": "cfg-2",
              "name": "github_repo",
              "type": "string",
              "value": "YOUR_REPO_NAME"
            },
            {
              "id": "cfg-3",
              "name": "duplicate_threshold",
              "type": "number",
              "value": 0.85
            },
            {
              "id": "cfg-4",
              "name": "roadmap_sheet_id",
              "type": "string",
              "value": "REPLACE_WITH_SHEET_ID"
            },
            {
              "id": "cfg-5",
              "name": "roadmap_sheet_name",
              "type": "string",
              "value": "feature_roadmap"
            },
            {
              "id": "cfg-6",
              "name": "dev_slack_channel",
              "type": "string",
              "value": "#dev-alerts"
            },
            {
              "id": "cfg-7",
              "name": "faq_url",
              "type": "string",
              "value": "https://your-docs.example.com/faq"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "186a9537-2b0a-4447-8b8e-42ca794e8308",
      "name": "Only On Issue Opened",
      "type": "n8n-nodes-base.if",
      "position": [
        480,
        368
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "f-1",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $('GitHub Issue Webhook').item.json.body.action }}",
              "rightValue": "opened"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "20c02959-8b7d-4d80-a480-f30359e8c949",
      "name": "Extract Issue Info",
      "type": "n8n-nodes-base.set",
      "position": [
        704,
        368
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "ex-1",
              "name": "issue_number",
              "type": "number",
              "value": "={{ $('GitHub Issue Webhook').item.json.body.issue.number }}"
            },
            {
              "id": "ex-2",
              "name": "issue_title",
              "type": "string",
              "value": "={{ $('GitHub Issue Webhook').item.json.body.issue.title }}"
            },
            {
              "id": "ex-3",
              "name": "issue_body",
              "type": "string",
              "value": "={{ $('GitHub Issue Webhook').item.json.body.issue.body || '' }}"
            },
            {
              "id": "ex-4",
              "name": "issue_html_url",
              "type": "string",
              "value": "={{ $('GitHub Issue Webhook').item.json.body.issue.html_url }}"
            },
            {
              "id": "ex-5",
              "name": "issue_author",
              "type": "string",
              "value": "={{ $('GitHub Issue Webhook').item.json.body.issue.user.login }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "3236b243-0009-487c-bc0b-4d2dd6174534",
      "name": "Fetch Recent Issues",
      "type": "n8n-nodes-base.github",
      "onError": "continueRegularOutput",
      "maxTries": 3,
      "position": [
        944,
        368
      ],
      "parameters": {
        "limit": 30,
        "owner": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $json.github_owner }}"
        },
        "resource": "repository",
        "repository": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $json.github_repo }}"
        },
        "authentication": "oAuth2",
        "getRepositoryIssuesFilters": {
          "state": "all"
        }
      },
      "retryOnFail": true,
      "typeVersion": 1.1,
      "waitBetweenTries": 2000
    },
    {
      "id": "a0d01de3-e6e2-4a7c-8096-51776c4b56c7",
      "name": "Prepare Texts for Embedding",
      "type": "n8n-nodes-base.code",
      "position": [
        1152,
        368
      ],
      "parameters": {
        "jsCode": "// ==========================================\n// Prepare text array for batch embeddings:\n// [new issue, past issue 1, past issue 2, ...]\n// ==========================================\nconst newIssue = $('Extract Issue Info').item.json;\nconst response = $input.first().json;\nconst pastIssues = Array.isArray(response) ? response : (response.body || []);\n\n// New issue text (first in array)\nconst texts = [\n  (newIssue.issue_title + '\\n' + (newIssue.issue_body || '')).substring(0, 2000)\n];\nconst metadata = [{ is_new: true }];\n\n// Past issues (exclude the new issue itself if present)\nfor (const issue of pastIssues) {\n  if (issue.number === newIssue.issue_number) continue;\n  if (issue.pull_request) continue; // skip PRs\n  texts.push(\n    (issue.title + '\\n' + (issue.body || '').substring(0, 500)).substring(0, 2000)\n  );\n  metadata.push({\n    is_new: false,\n    number: issue.number,\n    title: issue.title,\n    html_url: issue.html_url,\n    state: issue.state\n  });\n}\n\nreturn [{ json: { texts, metadata, new_issue: newIssue } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "6f566b9d-0c55-4a33-84fe-9c935a2ba79b",
      "name": "Get Embeddings (Batch)",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueRegularOutput",
      "maxTries": 3,
      "position": [
        1360,
        368
      ],
      "parameters": {
        "url": "https://api.openai.com/v1/embeddings",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"model\": \"text-embedding-3-small\",\n  \"input\": {{ JSON.stringify($json.texts) }}\n}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "retryOnFail": true,
      "typeVersion": 4.2,
      "waitBetweenTries": 2000
    },
    {
      "id": "601840c3-8d5e-45ce-8c50-01eb7a4a445d",
      "name": "Calculate Similarity",
      "type": "n8n-nodes-base.code",
      "position": [
        1616,
        368
      ],
      "parameters": {
        "jsCode": "// ==========================================\n// Cosine similarity: new issue vs each past issue\n// Find the max to detect duplicate\n// ==========================================\nfunction cosine(a, b) {\n  let dot = 0, magA = 0, magB = 0;\n  for (let i = 0; i < a.length; i++) {\n    dot += a[i] * b[i];\n    magA += a[i] * a[i];\n    magB += b[i] * b[i];\n  }\n  return dot / (Math.sqrt(magA) * Math.sqrt(magB));\n}\n\nconst embedResp = $input.first().json;\nconst embeddings = embedResp.data;\nconst metadata = $('Prepare Texts for Embedding').item.json.metadata;\nconst newIssue = $('Prepare Texts for Embedding').item.json.new_issue;\nconst threshold = $('Set Configuration').item.json.duplicate_threshold || 0.85;\n\nif (!embeddings || embeddings.length < 2) {\n  // No past issues to compare against\n  return [{\n    json: {\n      ...newIssue,\n      max_similarity: 0,\n      is_duplicate: false,\n      matched_issue: null\n    }\n  }];\n}\n\nconst newVec = embeddings[0].embedding;\nlet maxSim = 0;\nlet matched = null;\n\nfor (let i = 1; i < embeddings.length; i++) {\n  const sim = cosine(newVec, embeddings[i].embedding);\n  if (sim > maxSim) {\n    maxSim = sim;\n    matched = metadata[i];\n  }\n}\n\nreturn [{\n  json: {\n    ...newIssue,\n    max_similarity: Math.round(maxSim * 1000) / 1000,\n    is_duplicate: maxSim >= threshold,\n    matched_issue: matched\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "249beca5-71aa-4766-adb4-a93ad60bb38f",
      "name": "If Duplicate",
      "type": "n8n-nodes-base.if",
      "position": [
        1824,
        368
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "if-dup",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $json.is_duplicate }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "241741d1-8fc5-48d8-aa8a-b7bc889e218e",
      "name": "Post Duplicate Comment",
      "type": "n8n-nodes-base.github",
      "onError": "continueRegularOutput",
      "maxTries": 3,
      "position": [
        2112,
        304
      ],
      "parameters": {
        "body": "=\ud83d\udc4b Thanks for the report! This looks like a possible duplicate of a recent issue (similarity {{ $json.top_similarity }}). We'll close this one to keep things tidy \u2014 please comment on the original issue if this still affects you.",
        "owner": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $('Set Configuration').item.json.github_owner }}"
        },
        "operation": "createComment",
        "repository": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $('Set Configuration').item.json.github_repo }}"
        },
        "issueNumber": "={{ $('Extract Issue Info').item.json.issue_number }}",
        "authentication": "oAuth2"
      },
      "retryOnFail": true,
      "typeVersion": 1.1,
      "waitBetweenTries": 2000
    },
    {
      "id": "f1929589-7203-4fb7-ae9c-fcac82f263db",
      "name": "Close as Duplicate",
      "type": "n8n-nodes-base.github",
      "onError": "continueRegularOutput",
      "maxTries": 3,
      "position": [
        2384,
        304
      ],
      "parameters": {
        "owner": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $('Set Configuration').item.json.github_owner }}"
        },
        "operation": "edit",
        "editFields": {
          "state": "closed",
          "labels": [
            "duplicate"
          ]
        },
        "repository": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $('Set Configuration').item.json.github_repo }}"
        },
        "issueNumber": "={{ $('Extract Issue Info').item.json.issue_number }}",
        "authentication": "oAuth2"
      },
      "retryOnFail": true,
      "typeVersion": 1.1,
      "waitBetweenTries": 2000
    },
    {
      "id": "c4acc737-3324-4429-9eb3-d6fd32cb8207",
      "name": "Classify Issue",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "onError": "continueRegularOutput",
      "maxTries": 2,
      "position": [
        2064,
        624
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4o-mini",
          "cachedResultName": "gpt-4o-mini"
        },
        "options": {},
        "messages": {
          "values": [
            {
              "content": "You are a GitHub issue triage assistant. Classify the issue into exactly ONE of these categories: \"bug\", \"feature\", \"question\", \"spam\".\n\nRules:\n- \"bug\": reports of broken functionality, errors, crashes, regressions.\n- \"feature\": requests for new functionality or enhancements.\n- \"question\": how-to questions, usage help, FAQ-style asks.\n- \"spam\": off-topic, advertising, nonsense, or clearly malicious content.\n\nRespond ONLY with valid JSON in this exact shape (no markdown, no prose):\n{\"category\": \"bug|feature|question|spam\", \"reason\": \"short explanation, max 200 chars\"}\n\nIssue Title: {{ $json.issue_title }}\nIssue Body:\n{{ $json.issue_body }}"
            }
          ]
        },
        "jsonOutput": true
      },
      "retryOnFail": true,
      "typeVersion": 1.8,
      "waitBetweenTries": 2000
    },
    {
      "id": "bc77aba2-a530-4248-8f9a-a78dd0f8efbe",
      "name": "Route by Category",
      "type": "n8n-nodes-base.switch",
      "position": [
        2384,
        624
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "outputKey": "bug",
              "conditions": {
                "options": {
                  "version": 1,
                  "leftValue": "",
                  "caseSensitive": false,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "s1",
                    "operator": {
                      "type": "string",
                      "operation": "contains"
                    },
                    "leftValue": "={{ $json.message.content.toLowerCase().trim() }}",
                    "rightValue": "bug"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "question",
              "conditions": {
                "options": {
                  "version": 1,
                  "leftValue": "",
                  "caseSensitive": false,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "s2",
                    "operator": {
                      "type": "string",
                      "operation": "contains"
                    },
                    "leftValue": "={{ $json.message.content.toLowerCase().trim() }}",
                    "rightValue": "question"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "feature",
              "conditions": {
                "options": {
                  "version": 1,
                  "leftValue": "",
                  "caseSensitive": false,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "s3",
                    "operator": {
                      "type": "string",
                      "operation": "contains"
                    },
                    "leftValue": "={{ $json.message.content.toLowerCase().trim() }}",
                    "rightValue": "feature"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "spam",
              "conditions": {
                "options": {
                  "version": 1,
                  "leftValue": "",
                  "caseSensitive": false,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "s4",
                    "operator": {
                      "type": "string",
                      "operation": "contains"
                    },
                    "leftValue": "={{ $json.message.content.toLowerCase().trim() }}",
                    "rightValue": "spam"
                  }
                ]
              },
              "renameOutput": true
            }
          ]
        },
        "options": {}
      },
      "typeVersion": 3.2
    },
    {
      "id": "a1636638-8f03-49d8-9fe5-32bd54d3154e",
      "name": "Add Bug Label",
      "type": "n8n-nodes-base.github",
      "onError": "continueRegularOutput",
      "maxTries": 3,
      "position": [
        2640,
        288
      ],
      "parameters": {
        "owner": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $('Set Configuration').item.json.github_owner }}"
        },
        "operation": "edit",
        "editFields": {
          "labels": [
            "bug",
            "triage:auto"
          ]
        },
        "repository": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $('Set Configuration').item.json.github_repo }}"
        },
        "issueNumber": "={{ $('Extract Issue Info').item.json.issue_number }}",
        "authentication": "oAuth2"
      },
      "retryOnFail": true,
      "typeVersion": 1.1,
      "waitBetweenTries": 2000
    },
    {
      "id": "ca1e9be9-fa40-4bdf-a379-47f379bc53f7",
      "name": "Alert Dev Team",
      "type": "n8n-nodes-base.slack",
      "onError": "continueRegularOutput",
      "maxTries": 3,
      "position": [
        2912,
        288
      ],
      "parameters": {
        "text": "=\ud83d\udc1b *New bug report triaged*\n\n\u2022 Title: {{ $('Calculate Similarity').item.json.issue_title }}\n\u2022 #{{ $('Calculate Similarity').item.json.issue_number }}: {{ $('Calculate Similarity').item.json.issue_html_url }}\n\u2022 Reporter: {{ $('Calculate Similarity').item.json.issue_author }}",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $('Set Configuration').item.json.dev_slack_channel }}"
        },
        "otherOptions": {}
      },
      "retryOnFail": true,
      "typeVersion": 2.2,
      "waitBetweenTries": 2000
    },
    {
      "id": "9e8a9ea2-cd28-4bd0-bd4d-6974c560b151",
      "name": "Post FAQ Comment",
      "type": "n8n-nodes-base.github",
      "onError": "continueRegularOutput",
      "maxTries": 3,
      "position": [
        2640,
        560
      ],
      "parameters": {
        "body": "=\ud83d\udc4b Thanks for your question! Many common questions are answered in our FAQ: {{ $('Set Configuration').item.json.faq_url }}\n\nIf you can't find your answer there, please reply with more details and a maintainer will help you out.",
        "owner": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $('Set Configuration').item.json.github_owner }}"
        },
        "operation": "createComment",
        "repository": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $('Set Configuration').item.json.github_repo }}"
        },
        "issueNumber": "={{ $('Extract Issue Info').item.json.issue_number }}",
        "authentication": "oAuth2"
      },
      "retryOnFail": true,
      "typeVersion": 1.1,
      "waitBetweenTries": 2000
    },
    {
      "id": "42d56db6-1810-475e-9238-c3913162050b",
      "name": "Add to Roadmap",
      "type": "n8n-nodes-base.googleSheets",
      "onError": "continueRegularOutput",
      "maxTries": 3,
      "position": [
        2656,
        848
      ],
      "parameters": {
        "columns": {
          "value": {
            "url": "={{ $('Calculate Similarity').item.json.issue_html_url }}",
            "title": "={{ $('Calculate Similarity').item.json.issue_title }}",
            "author": "={{ $('Calculate Similarity').item.json.issue_author }}",
            "status": "proposed",
            "date_added": "={{ $now.toISO() }}",
            "issue_number": "={{ $('Calculate Similarity').item.json.issue_number }}"
          },
          "mappingMode": "defineBelow",
          "matchingColumns": []
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $('Set Configuration').item.json.roadmap_sheet_name }}"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Set Configuration').item.json.roadmap_sheet_id }}"
        }
      },
      "retryOnFail": true,
      "typeVersion": 4.5,
      "waitBetweenTries": 2000
    },
    {
      "id": "412816df-f1e3-4004-bb01-1ae73a0e8e49",
      "name": "Close as Spam",
      "type": "n8n-nodes-base.github",
      "onError": "continueRegularOutput",
      "maxTries": 3,
      "position": [
        2656,
        1136
      ],
      "parameters": {
        "owner": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $('Set Configuration').item.json.github_owner }}"
        },
        "operation": "edit",
        "editFields": {
          "state": "closed",
          "labels": [
            "spam"
          ]
        },
        "repository": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $('Set Configuration').item.json.github_repo }}"
        },
        "issueNumber": "={{ $('Extract Issue Info').item.json.issue_number }}",
        "authentication": "oAuth2"
      },
      "retryOnFail": true,
      "typeVersion": 1.1,
      "waitBetweenTries": 2000
    },
    {
      "id": "st-ixgwv4tygb",
      "name": "README",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -608,
        192
      ],
      "parameters": {
        "width": 628,
        "height": 928,
        "content": "# Triage GitHub Issues with AI Category and Embedding-Based Duplicate Detection\n\nWhen a new Issue is opened, the workflow fetches recent Issues from the same repo, runs batch embeddings to calculate semantic similarity, and auto-closes duplicates with a reference comment. Non-duplicates are classified by AI into one of four categories and routed to the matching action branch.\n\n## How it works\n1. Receive a GitHub webhook when a new Issue is opened\n2. Filter for the \"opened\" action only\n3. Fetch the last 30 Issues from the repository\n4. Send all Issue texts to OpenAI embeddings in a single batch call\n5. Calculate cosine similarity between the new Issue and each past Issue\n6. If similarity exceeds 0.85, auto-close as duplicate with a reference comment\n7. Otherwise, classify the Issue with AI into bug, question, feature, or spam\n8. Route to the matching action branch\n\n## Categories\n- Bug: Add label and send Slack alert to dev team\n- Question: Post FAQ link as a comment\n- Feature: Append to roadmap Google Sheet\n- Spam: Auto-close with spam label\n- Duplicate: Auto-close with reference to the original Issue\n\n## Setup steps\n1. Generate a GitHub Personal Access Token with repo scope\n2. Create a webhook on your repository subscribing to Issues events\n3. Create a Google Sheet named feature_roadmap with columns: date_added, issue_number, title, author, url, status\n4. Open Set Configuration and fill in the repo owner, repo name, Sheet ID, Slack channel, and FAQ URL\n5. Connect GitHub, OpenAI, Google Sheets, and Slack credentials\n6. Activate the workflow"
      },
      "typeVersion": 1
    },
    {
      "id": "st-fgn6gf7bzv",
      "name": "Section 1 Trigger & Filter",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        32,
        192
      ],
      "parameters": {
        "color": 7,
        "width": 816,
        "height": 340,
        "content": "## 1. Trigger & Filter\n\nGitHub webhook receives Issue events \u2192 load central configuration (owner/repo, thresholds, FAQ URL, Slack channel, Roadmap sheet) \u2192 keep only `opened` actions and extract the issue number / title / body for downstream use."
      },
      "typeVersion": 1
    },
    {
      "id": "st-x39gpewg44",
      "name": "Section 2 Fetch & Embed",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        880,
        192
      ],
      "parameters": {
        "color": 7,
        "width": 688,
        "height": 340,
        "content": "## 2. Fetch & Embed\n\nPull the last 30 Issues from the same repo, combine titles + bodies, and send them all to the OpenAI embeddings API in a single batch request for cost & latency efficiency."
      },
      "typeVersion": 1
    },
    {
      "id": "st-kuse1id055",
      "name": "Section 3 Similarity & Dedup",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1584,
        192
      ],
      "parameters": {
        "color": 7,
        "width": 432,
        "height": 340,
        "content": "## 3. Similarity & Dedup\n\nCompute cosine similarity between the new Issue and every fetched Issue. If the top score exceeds `duplicate_threshold` (default 0.85) \u2192 route to the Duplicate branch, otherwise continue to AI classification."
      },
      "typeVersion": 1
    },
    {
      "id": "st-rtusm0gvlj",
      "name": "Section 4 Classify & Dispatch",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2032,
        464
      ],
      "parameters": {
        "color": 7,
        "width": 528,
        "height": 388,
        "content": "## 4. Classify & Dispatch\n\nGPT-4o-mini labels the Issue as one of bug / feature / question / spam (deterministic JSON). A Switch node fans out to five side effects: duplicate handling, bug alerting, FAQ reply, roadmap logging, and spam closure."
      },
      "typeVersion": 1
    },
    {
      "id": "st-wrb2p6qnld",
      "name": "Branch: Post Duplicate Comment",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2032,
        192
      ],
      "parameters": {
        "color": 7,
        "width": 260,
        "height": 264,
        "content": "### \ud83d\udd01 Duplicate \u2192 Comment\nPolite \"possible duplicate\" comment posted on the new Issue with the similarity score."
      },
      "typeVersion": 1
    },
    {
      "id": "st-49ic6vbdyf",
      "name": "Branch: Close as Duplicate",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2304,
        192
      ],
      "parameters": {
        "color": 7,
        "width": 260,
        "height": 264,
        "content": "### \ud83d\udd12 Duplicate \u2192 Close\nCloses the Issue and applies the `duplicate` label."
      },
      "typeVersion": 1
    },
    {
      "id": "st-4cgzl7vacl",
      "name": "Branch: Add Bug Label",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2576,
        192
      ],
      "parameters": {
        "color": 7,
        "width": 260,
        "height": 264,
        "content": "### \ud83d\udc1b Bug \u2192 Label\nAdds the `bug` + `triage:auto` labels to the Issue."
      },
      "typeVersion": 1
    },
    {
      "id": "st-7dos69hjg4",
      "name": "Branch: Alert Dev Team",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2848,
        192
      ],
      "parameters": {
        "color": 7,
        "width": 260,
        "height": 264,
        "content": "### \ud83d\udce3 Bug \u2192 Slack Alert\nPings the configured dev Slack channel with the issue link."
      },
      "typeVersion": 1
    },
    {
      "id": "st-h9m8bl1sz6",
      "name": "Branch: Post FAQ Comment",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2576,
        464
      ],
      "parameters": {
        "color": 7,
        "width": 260,
        "height": 248,
        "content": "### \u2753 Question \u2192 FAQ Reply\nAuto-replies with a link to the FAQ documentation."
      },
      "typeVersion": 1
    },
    {
      "id": "st-w619lvcarm",
      "name": "Branch: Add to Roadmap",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2576,
        736
      ],
      "parameters": {
        "color": 7,
        "width": 260,
        "height": 264,
        "content": "### \u2728 Feature \u2192 Roadmap\nAppends the request to a Google Sheets roadmap backlog."
      },
      "typeVersion": 1
    },
    {
      "id": "st-ibvc4cu84t",
      "name": "Branch: Close as Spam",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2576,
        1024
      ],
      "parameters": {
        "color": 7,
        "width": 260,
        "height": 280,
        "content": "### \ud83d\udeab Spam \u2192 Close\nCloses the Issue immediately and applies the `spam` label."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "31feeac4-3bcf-4643-8c92-eb50053621b6",
  "connections": {
    "If Duplicate": {
      "main": [
        [
          {
            "node": "Post Duplicate Comment",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Classify Issue",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Add Bug Label": {
      "main": [
        [
          {
            "node": "Alert Dev Team",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Classify Issue": {
      "main": [
        [
          {
            "node": "Route by Category",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Route by Category": {
      "main": [
        [
          {
            "node": "Add Bug Label",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Post FAQ Comment",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Add to Roadmap",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Close as Spam",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Configuration": {
      "main": [
        [
          {
            "node": "Only On Issue Opened",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Issue Info": {
      "main": [
        [
          {
            "node": "Fetch Recent Issues",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Recent Issues": {
      "main": [
        [
          {
            "node": "Prepare Texts for Embedding",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Calculate Similarity": {
      "main": [
        [
          {
            "node": "If Duplicate",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "GitHub Issue Webhook": {
      "main": [
        [
          {
            "node": "Set Configuration",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Only On Issue Opened": {
      "main": [
        [
          {
            "node": "Extract Issue Info",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Embeddings (Batch)": {
      "main": [
        [
          {
            "node": "Calculate Similarity",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Post Duplicate Comment": {
      "main": [
        [
          {
            "node": "Close as Duplicate",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Texts for Embedding": {
      "main": [
        [
          {
            "node": "Get Embeddings (Batch)",
            "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

Open-source maintainers, product teams with public repositories, and any organization receiving a steady stream of GitHub Issues. Ideal for small teams who waste hours per week triaging duplicates and misrouted reports.

Source: https://n8n.io/workflows/15251/ — 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 advanced n8n workflow automates the full lead enrichment, qualification, and personalized outreach process tailored specifically for the B2B real estate sector. Integrating top platforms like Api

N8N Nodes Fillout, OpenAI Chat, Pinecone Vector Store +11
AI & RAG

WooriFisa 최종. Uses memoryMongoDbChat, agent, httpRequest, documentDefaultDataLoader. Scheduled trigger; 68 nodes.

Memory Mongo Db Chat, Agent, HTTP Request +14
AI & RAG

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

Google Sheets, HTTP Request, Slack +10
AI & RAG

This workflow automates patient communication for medical clinics using the WhatsApp Business API. It supports appointment booking, rescheduling, service inquiries, follow-ups, and document submission

Google Sheets, Data Table, Data Table Tool +12
AI & RAG

This n8n template automatically classifies incoming emails (Sales, Support, Internal, Finance, Promotions) and routes them to a dedicated OpenAI LLM Agent for processing. Depending on the category, th

OpenAI, Gmail, Text Classifier +16