{
  "id": "W3JyNL5KOXyxnQkR",
  "name": "GitHub Issue Monitor",
  "active": false,
  "isArchived": false,
  "versionId": "946033ea-3c7d-402f-97c6-637df2e539d8",
  "settings": {
    "executionOrder": "v1",
    "availableInMCP": true
  },
  "connections": {
    "GitHub Trigger": {
      "main": [
        [
          {
            "node": "Filter Issue Opened",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter Issue Opened": {
      "main": [
        [
          {
            "node": "OpenRouter Triage",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Ignore Non-Opened Events",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenRouter Triage": {
      "main": [
        [
          {
            "node": "Parse Triage",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Triage": {
      "main": [
        [
          {
            "node": "Add GitHub Label",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Add GitHub Label": {
      "main": [
        [
          {
            "node": "Post Slack Alert",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "nodes": [
    {
      "id": "749727b3-ef80-41ce-82df-c7cbe4b0ba34",
      "name": "GitHub Trigger",
      "type": "n8n-nodes-base.githubTrigger",
      "typeVersion": 1,
      "position": [
        0,
        96
      ],
      "parameters": {
        "owner": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $vars.GITHUB_OWNER }}"
        },
        "repository": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $vars.GITHUB_REPO }}"
        },
        "events": [
          "issues"
        ]
      }
    },
    {
      "id": "1418f09c-a816-40dd-b2c7-7cadf46ef73e",
      "name": "Filter Issue Opened",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        224,
        96
      ],
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "leftValue": "={{ $json.action }}",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "rightValue": "opened"
            }
          ],
          "combinator": "and"
        }
      }
    },
    {
      "id": "a8d69d3a-e30a-46f3-8d38-f2991f96a78a",
      "name": "OpenRouter Triage",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [
        448,
        0
      ],
      "parameters": {
        "method": "POST",
        "url": "={{ $vars.OPENROUTER_BASE_URL }}/chat/completions",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendBody": true,
        "contentType": "json",
        "specifyBody": "json",
        "jsonBody": "={{ { \"model\": $vars.OPENROUTER_MODEL, \"messages\": [{ \"role\": \"system\", \"content\": \"You are a GitHub issue triage assistant. Analyze the issue and respond ONLY with valid JSON: {\\\"priority\\\": \\\"low|medium|high\\\", \\\"category\\\": \\\"bug|feature|docs|question\\\", \\\"suggested_label\\\": \\\"string (one word, lowercase, no spaces)\\\", \\\"summary\\\": \\\"one sentence max 100 chars\\\"}\" }, { \"role\": \"user\", \"content\": \"Issue title: \" + $json.issue.title + \"\\nBody: \" + ($json.issue.body ?? \"(no body)\") }] } }}",
        "options": {
          "timeout": 20000
        }
      }
    },
    {
      "id": "6e4782a6-2f06-4513-ad9c-ed7bd1bfb088",
      "name": "Parse Triage",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        672,
        0
      ],
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "const raw = $input.first().json?.choices?.[0]?.message?.content ?? '';\nlet triage = {};\ntry {\n  const s = raw.replace(/```(?:json)?\\n?/g, '').trim();\n  triage = JSON.parse(s);\n} catch(e) {\n  triage = { priority: 'medium', category: 'question', suggested_label: 'needs-triage', summary: 'AI triage failed \u2014 manual review needed' };\n}\n// Validate and sanitize label (lowercase, no spaces, max 50 chars)\nconst label = (triage.suggested_label ?? 'needs-triage')\n  .toLowerCase().replace(/\\s+/g, '-').slice(0, 50);\n\nconst issue = $('GitHub Trigger').first().json;\nreturn [{ json: {\n  issue_number: issue.issue?.number,\n  issue_title: issue.issue?.title,\n  issue_url: issue.issue?.html_url,\n  repo_owner: issue.repository?.owner?.login,\n  repo_name: issue.repository?.name,\n  priority: triage.priority ?? 'medium',\n  category: triage.category ?? 'question',\n  suggested_label: label,\n  summary: triage.summary ?? 'No summary available'\n}}];"
      }
    },
    {
      "id": "2c7e0e82-2493-4928-8058-b88b40b18bf1",
      "name": "Add GitHub Label",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [
        896,
        0
      ],
      "parameters": {
        "method": "POST",
        "url": "={{ 'https://api.github.com/repos/' + $json.repo_owner + '/' + $json.repo_name + '/issues/' + $json.issue_number + '/labels' }}",
        "authentication": "genericCredentialType",
        "genericAuthType": "oAuth2Api",
        "sendBody": true,
        "contentType": "json",
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({ labels: [$json.suggested_label] }) }}",
        "options": {
          "response": {
            "response": {
              "responseFormat": "json"
            }
          }
        }
      }
    },
    {
      "id": "02a447b4-214e-4f74-9d3b-21bb0d839fcc",
      "name": "Post Slack Alert",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.5,
      "position": [
        1120,
        0
      ],
      "parameters": {
        "resource": "message",
        "operation": "post",
        "authentication": "accessToken",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "name",
          "value": "#github-alerts"
        },
        "messageType": "text",
        "text": "={{ \"\ud83d\udd14 *New GitHub Issue*\\n*\" + $(\"Parse Triage\").item.json.issue_title + \"*\\nPriority: \" + $(\"Parse Triage\").item.json.priority + \" | Category: \" + $(\"Parse Triage\").item.json.category + \"\\nSummary: \" + $(\"Parse Triage\").item.json.summary + \"\\n\ud83c\udff7\ufe0f Label added: `\" + $(\"Parse Triage\").item.json.suggested_label + \"`\\n\ud83d\udd17 \" + $(\"Parse Triage\").item.json.issue_url }}",
        "otherOptions": {}
      }
    },
    {
      "id": "3f1d9de5-b0e6-46b5-964d-eaab9a9bce70",
      "name": "Ignore Non-Opened Events",
      "type": "n8n-nodes-base.noOp",
      "typeVersion": 1,
      "position": [
        448,
        192
      ],
      "parameters": {}
    }
  ],
  "tags": [],
  "meta": {
    "aiBuilderAssisted": true,
    "builderVariant": "mcp"
  },
  "description": "Automatically triages new GitHub issues with AI (OpenRouter) and posts structured Slack alerts with priority, category, label, and summary."
}