{
  "name": "GitHub Issues and PRs to Slack",
  "nodes": [
    {
      "parameters": {
        "content": "## GitHub Issues and PRs to Slack Notifications\n\nNew issues and PRs surface in your team channel with the label, author, and a one-line preview - tuned to only the events you care about, unlike the firehose the official app sends.\n\n**Setup time:** 10 minutes  ·  **Level:** Beginner\n\n**You'll need accounts/credentials for:** GitHub, Slack\n\n**Replace these before running:**\n- `REPLACE_WITH_OWNER`\n- `REPLACE_WITH_REPO`\n- `REPLACE_WITH_CHANNEL`\n\n**Setup steps:**\n1. Connect GitHub with a personal access token (repo scope) and select your repository in the trigger.\n2. Connect Slack and choose your #dev or #bugs channel.\n3. Optionally edit the Code node filter - e.g. only issues labeled 'bug', or skip your bot accounts.\n4. Activate the workflow and open a test issue.\n\nFree templates and updates: navkhan103.github.io",
        "height": 640,
        "width": 400,
        "color": 4
      },
      "id": "sticky-setup",
      "name": "Setup — read me first",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -440,
        -40
      ]
    },
    {
      "parameters": {
        "content": "### How it runs\n\nStarts from **GitHub Events**.\n\n1. A GitHub Trigger subscribes to issues and pull_request events on your repo.\n2. A Code node keeps only opened events (edit the filter to add labels, authors, or keywords).\n3. A Slack node posts a formatted line: type, title, author, labels, and link.",
        "height": 322,
        "width": 400,
        "color": 7
      },
      "id": "sticky-how",
      "name": "How it runs",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -440,
        640
      ]
    },
    {
      "parameters": {
        "content": "### If something breaks\n\nThe read and AI nodes here **retry 3× automatically** (5s apart), which absorbs rate limits and brief timeouts.\n\nNodes that **send or write deliberately do not retry** — a send that reached the far end but lost its response would otherwise fire twice, so you'd get duplicate messages or duplicate rows.\n\nTo be told when one of those fails, build a workflow starting with an **Error Trigger** node that posts to Slack or email, then set it under **three-dot menu > Settings > Error Workflow**. Do it once and point every workflow at it.",
        "height": 400,
        "width": 400,
        "color": 3
      },
      "id": "sticky-fail",
      "name": "If something breaks",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -440,
        1002
      ]
    },
    {
      "parameters": {
        "owner": {
          "__rl": true,
          "mode": "list",
          "value": "REPLACE_WITH_OWNER"
        },
        "repository": {
          "__rl": true,
          "mode": "list",
          "value": "REPLACE_WITH_REPO"
        },
        "events": [
          "issues",
          "pull_request"
        ],
        "options": {}
      },
      "id": "f3a4b5c6-0001-4000-8000-000000000001",
      "name": "GitHub Events",
      "type": "n8n-nodes-base.githubTrigger",
      "typeVersion": 1,
      "position": [
        0,
        0
      ]
    },
    {
      "parameters": {
        "jsCode": "const p = $input.first().json.body || $input.first().json;\nif (p.action !== 'opened') return []; // only new items\nconst item = p.issue || p.pull_request;\nif (!item) return [];\n// Optional filters - uncomment to use:\n// if (!(item.labels || []).some(l => l.name === 'bug')) return [];\n// if (item.user.login.endsWith('[bot]')) return [];\nreturn [{ json: {\n  kind: p.pull_request ? 'PR' : 'Issue',\n  title: item.title,\n  url: item.html_url,\n  author: item.user.login,\n  labels: (item.labels || []).map(l => l.name).join(', ') || 'none',\n  preview: (item.body || '').replace(/\\r?\\n/g, ' ').slice(0, 140)\n} }];"
      },
      "id": "f3a4b5c6-0002-4000-8000-000000000002",
      "name": "Filter and Format",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        220,
        0
      ]
    },
    {
      "parameters": {
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": "REPLACE_WITH_CHANNEL"
        },
        "text": "=:octopus: *New {{ $json.kind }}:* <{{ $json.url }}|{{ $json.title }}>\nby {{ $json.author }} - labels: {{ $json.labels }}\n>{{ $json.preview }}",
        "otherOptions": {}
      },
      "id": "f3a4b5c6-0003-4000-8000-000000000003",
      "name": "Post to Slack",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.3,
      "position": [
        440,
        0
      ]
    }
  ],
  "connections": {
    "GitHub Events": {
      "main": [
        [
          {
            "node": "Filter and Format",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter and Format": {
      "main": [
        [
          {
            "node": "Post to Slack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  }
}