{
  "id": "7EQzN4YzDTJiI6dU",
  "name": "Send pre-meeting Slack briefings using Google Calendar, GitHub",
  "tags": [],
  "nodes": [
    {
      "id": "922245e4-7413-4194-b565-ff0be4209829",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        0,
        0
      ],
      "parameters": {
        "width": 480,
        "height": 896,
        "content": "## Send pre-meeting Slack briefings using Google Calendar, GitHub\n\n### How it works\n\n1. The workflow triggers hourly checks from Google Calendar for upcoming events.\n2. It retrieves the last meeting notes if available and checks if there was a previous meeting.\n3. The workflow then extracts relevant keywords from the meeting notes to identify related GitHub pull requests (PRs).\n4. It builds a message for Slack that includes attendees and meeting context.\n5. Finally, it sends direct messages to each attendee on Slack with the meeting context and related PRs.\n\n### Setup steps\n\n- [ ] Configure Google Calendar API credentials in n8n.\n- [ ] Set up GitHub API credentials to access repositories.\n- [ ] Ensure Slack API credentials are ready for sending messages.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "d6c0cb59-a234-42c5-b147-97f0e151c3cc",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        560,
        576
      ],
      "parameters": {
        "color": 7,
        "width": 384,
        "height": 304,
        "content": "## Schedule checks for events\n\nRetrieves events from Google Calendar on an hourly schedule."
      },
      "typeVersion": 1
    },
    {
      "id": "12ad5a8c-54bd-4a87-a604-201ba25701ad",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1264,
        592
      ],
      "parameters": {
        "color": 7,
        "width": 608,
        "height": 272,
        "content": "## Get last meeting details\n\nFetches previous meeting notes and checks if there was a meeting."
      },
      "typeVersion": 1
    },
    {
      "id": "fbed418c-6b6a-4e78-b98f-494cb1bf9973",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3184,
        368
      ],
      "parameters": {
        "color": 7,
        "width": 416,
        "height": 544,
        "content": "## Extract keywords and PRs\n\nExtracts keywords from meeting notes to find relevant GitHub PRs."
      },
      "typeVersion": 1
    },
    {
      "id": "b6fac09c-cd1f-4a69-9d92-328ecacf7f6b",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        4656,
        496
      ],
      "parameters": {
        "color": 7,
        "width": 1472,
        "height": 352,
        "content": "## Handle Slack message construction\n\nBuilds and formats the message for Slack with meeting details and attendees."
      },
      "typeVersion": 1
    },
    {
      "id": "22446a06-0296-4e68-9dda-901d2a6d2a28",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        5456,
        880
      ],
      "parameters": {
        "color": 7,
        "width": 672,
        "height": 352,
        "content": "## Check and send Slack messages\n\nValidates Slack user information and sends out meeting details."
      },
      "typeVersion": 1
    },
    {
      "id": "198c1c51-cb1e-449f-af87-71a31f9a0166",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1904,
        944
      ],
      "parameters": {
        "color": 7,
        "width": 2448,
        "height": 288,
        "content": "## Merge GitHub data\n\nMerges data from GitHub PRs and issues related to the meeting."
      },
      "typeVersion": 1
    },
    {
      "id": "c5d00785-ca27-4911-a6d8-993fdf607aa8",
      "name": "Sticky Note7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3632,
        0
      ],
      "parameters": {
        "color": 7,
        "width": 2464,
        "height": 464,
        "content": "## Finalize meeting context\n\nPrepares and finalizes the meeting context to be sent to attendees via Slack."
      },
      "typeVersion": 1
    },
    {
      "id": "0344a88c-34d0-4175-9918-181a12bb5d5c",
      "name": "Build Message for Slack",
      "type": "n8n-nodes-base.code",
      "position": [
        4704,
        688
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// --------------------\n// 1. Read inputs safely\n// --------------------\nconst ticketsRaw = $json.tickets ?? [];\n\nconst previousNotes =\n  $('Normalize Calendar and Payloads').first()?.json?.previousMeetingNotes ?? '';\n\nconst meetingTitle =\n  $('Format Calenda Event Payload').first()?.json?.summary ?? 'Meeting';\n\nconst eventStart =\n  $('Format Calenda Event Payload').first()?.json?.eventStart;\n\nconst start = eventStart ? new Date(eventStart) : null;\n\n// --------------------\n// 2. Format meeting time\n// --------------------\nconst meetingTime = start\n  ? start.toLocaleString('en-IN', {\n      weekday: 'short',\n      day: '2-digit',\n      month: 'short',\n      hour: '2-digit',\n      minute: '2-digit'\n    })\n  : '';\n\n// --------------------\n// 3. Clean & validate tickets\n// --------------------\nconst validTickets = ticketsRaw.filter(\n  t => t && t.source && t.id && t.title\n);\n\n// --------------------\n// 4. Build Topics section\n// --------------------\nconst ticketText = validTickets.length\n  ? validTickets\n      .map(t => `\u2022 *[${t.source}]* ${t.id} \u2014 ${t.title}`)\n      .join('\\n')\n  : '_No tickets or PRs found._';\n\n// --------------------\n// 5. Build Previous Notes section\n// --------------------\nconst notesText = previousNotes.trim()\n  ? previousNotes\n      .split('\\n')\n      .map(l => `\u2022 ${l.replace(/^[-\u2022]\\s*/, '')}`)\n      .join('\\n')\n  : '_No previous meeting notes found._';\n\n// --------------------\n// 6. Return Slack Blocks\n// --------------------\nreturn {\n  blocks: [\n    {\n      type: 'header',\n      text: {\n        type: 'plain_text',\n        text: '\ud83e\udde0 Pre-Meeting Context',\n        emoji: true\n      }\n    },\n    {\n      type: 'context',\n      elements: [\n        {\n          type: 'mrkdwn',\n          text: `\ud83d\udcc5 *${meetingTitle}*${meetingTime ? ` \u00b7 *${meetingTime}*` : ''}`\n        }\n      ]\n    },\n    { type: 'divider' },\n    {\n      type: 'section',\n      text: {\n        type: 'mrkdwn',\n        text: `*Topics for Today*\\n${ticketText}`\n      }\n    },\n    { type: 'divider' },\n    {\n      type: 'section',\n      text: {\n        type: 'mrkdwn',\n        text: `*Previous Meeting Summary*\\n${notesText}`\n      }\n    },\n    {\n      type: 'context',\n      elements: [\n        {\n          type: 'mrkdwn',\n          text: '_Please review before the meeting starts._'\n        }\n      ]\n    }\n  ]\n};\n"
      },
      "typeVersion": 2
    },
    {
      "id": "41f84f05-ee8e-4d40-855c-2e9f426240b1",
      "name": "Is Previous Meeting",
      "type": "n8n-nodes-base.filter",
      "position": [
        1520,
        704
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "e6042a4c-041a-4743-b5f9-ee82e6c8f141",
              "operator": {
                "type": "dateTime",
                "operation": "before"
              },
              "leftValue": "={{ $json.created_at }}",
              "rightValue": "={{ $('Format Calenda Event Payload').item.json.eventStart }}"
            }
          ]
        },
        "looseTypeValidation": true
      },
      "typeVersion": 2.3
    },
    {
      "id": "0eb72dff-55d4-497d-9c8d-46b4680c5724",
      "name": "Wait for Time to Come",
      "type": "n8n-nodes-base.wait",
      "position": [
        2416,
        704
      ],
      "parameters": {
        "resume": "specificTime",
        "dateTime": "={{ $json.notifyAt }}"
      },
      "typeVersion": 1.1,
      "alwaysOutputData": true
    },
    {
      "id": "1fee8e24-4a5f-4054-bc66-81ccddbe2cb5",
      "name": "Get PRs from Repo",
      "type": "n8n-nodes-base.github",
      "position": [
        3680,
        112
      ],
      "parameters": {
        "owner": {
          "__rl": true,
          "mode": "name",
          "value": "Your GitHub user name"
        },
        "resource": "repository",
        "repository": {
          "__rl": true,
          "mode": "list",
          "value": "Your repository",
          "cachedResultUrl": "Your repository url",
          "cachedResultName": "Your repository"
        },
        "authentication": "oAuth2",
        "getRepositoryIssuesFilters": {
          "labels": "={{ $json.keywords }}"
        }
      },
      "typeVersion": 1.1,
      "alwaysOutputData": false
    },
    {
      "id": "a3f5e7aa-b886-45e7-abb6-315e622e03aa",
      "name": "Filter PRs Related to Meeting",
      "type": "n8n-nodes-base.code",
      "position": [
        3904,
        112
      ],
      "parameters": {
        "jsCode": "// --------------------\n// 1. Read meeting context (single values)\n// --------------------\nconst keywordsRaw =\n  $('Extract Meeting Keywords').first().json.keywords || '';\n\nconst keywords = keywordsRaw\n  .toLowerCase()\n  .split(' ')\n  .filter(Boolean);\n\nconst lastMeetingDateStr =\n  $('Normalize Calendar and Payloads').first().json.previousMeetingDate || null;\n\nconst lastMeetingDate = lastMeetingDateStr\n  ? new Date(lastMeetingDateStr)\n  : null;\n\n// --------------------\n// 2. Read PR list (multiple items)\n// --------------------\nconst prs = $input.all();\n\n// --------------------\n// 3. Filter PRs\n// --------------------\nconst filteredPRs = prs.filter(item => {\n  const pr = item.json;\n\n  // --- Date filter ---\n  if (lastMeetingDate && pr.created_at) {\n    const prCreatedAt = new Date(pr.created_at);\n    if (prCreatedAt <= lastMeetingDate) {\n      return false;\n    }\n  }\n\n  // --- Keyword relevance ---\n  const text = `${pr.title || ''} ${pr.body || ''}`.toLowerCase();\n\n  const matchesKeyword = keywords.some(k => text.includes(k));\n\n  return matchesKeyword;\n});\n\n// --------------------\n// 4. Return filtered PRs\n// --------------------\nreturn filteredPRs;"
      },
      "typeVersion": 2,
      "alwaysOutputData": true
    },
    {
      "id": "807ec820-0b98-43c6-8390-4b30532b7534",
      "name": "Normalize Attendees and Slack Message",
      "type": "n8n-nodes-base.set",
      "position": [
        4912,
        688
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "8a5490e3-14cf-41ca-b56e-05475e3d92a8",
              "name": "attendees",
              "type": "array",
              "value": "={{ $('Add 5 minute Early Time').first().json.attendees }}"
            },
            {
              "id": "a6bb5f56-eab0-47bd-ae48-f705904b75c1",
              "name": "message",
              "type": "object",
              "value": "={{ $json }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "4cf0d913-a468-462e-932e-fa024ac2fa29",
      "name": "Get User Slack Info from Email",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        5952,
        688
      ],
      "parameters": {
        "url": "https://slack.com/api/users.lookupByEmail",
        "options": {},
        "sendQuery": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "queryParameters": {
          "parameters": [
            {
              "name": "email",
              "value": "={{ $json.email }}"
            }
          ]
        }
      },
      "typeVersion": 4.3
    },
    {
      "id": "e286ddd5-cb69-4530-b2a9-f5c08c003e71",
      "name": "Check Slack User Found",
      "type": "n8n-nodes-base.if",
      "position": [
        5696,
        1072
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "74c0ae69-46aa-4d21-8f8e-b0b8b902a83e",
              "operator": {
                "type": "boolean",
                "operation": "equals"
              },
              "leftValue": "={{ $json.ok }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "6efdf3e2-173f-40a1-b4db-7e31be02b8f0",
      "name": "Send Meeting Context in Slack DM",
      "type": "n8n-nodes-base.slack",
      "position": [
        5984,
        992
      ],
      "parameters": {
        "text": "=Meeting Related Context",
        "user": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.user.id }}"
        },
        "select": "user",
        "blocksUi": "={{ $('Fan Out Attendees').item.json.message }}",
        "messageType": "block",
        "otherOptions": {
          "includeLinkToWorkflow": false
        },
        "authentication": "oAuth2"
      },
      "typeVersion": 2.4
    },
    {
      "id": "fb38b171-69e2-4d85-a843-9ea7884bdd8b",
      "name": "Extract Meeting Keywords",
      "type": "n8n-nodes-base.code",
      "position": [
        2640,
        704
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const title = ($json.summary || '').trim();\n\nconst keywords = title\n  .toLowerCase()\n  .replace(/[^a-z0-9\\s]/g, '') // remove symbols\n  .split(' ')\n  .filter(w => w.length > 2)   // drop short/noise words\n  .slice(0, 5)\n  .join(' ');\n\nreturn {\n  meetingTitle: title,\n  keywords\n};\n"
      },
      "typeVersion": 2
    },
    {
      "id": "dd1e199b-7371-493a-95e3-16f3d8498cdc",
      "name": "Fan Out Attendees",
      "type": "n8n-nodes-base.code",
      "position": [
        5104,
        688
      ],
      "parameters": {
        "jsCode": "const attendees = $input.first().json.attendees;\n\nconst message =\n  $input.first().json.message;\n\nif (!attendees || attendees.length === 0) {\n  return [];\n}\n\n// Optional: filter declined attendees\nconst valid = attendees.filter(\n  a => a.responseStatus !== 'declined'\n);\n\nreturn valid.map(a => ({\n  json: {\n    email: a.email,\n    message\n  }\n}));\n"
      },
      "typeVersion": 2
    },
    {
      "id": "f2961a78-af8c-4015-b24a-b2668b974f10",
      "name": "Get Last Meeting Notes",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1312,
        704
      ],
      "parameters": {
        "url": "Place GitHub issue url here",
        "options": {},
        "sendQuery": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "queryParameters": {
          "parameters": [
            {
              "name": "labels",
              "value": "meeting-notes"
            },
            {
              "name": "sort",
              "value": "created"
            },
            {
              "name": "direction",
              "value": "desc"
            },
            {
              "name": "per_page",
              "value": "1"
            }
          ]
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "50c94a1b-795f-42fa-8580-75017557437b",
      "name": "HTTP Request",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        3360,
        736
      ],
      "parameters": {
        "url": "https://api.github.com/search/issues",
        "options": {},
        "sendQuery": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "queryParameters": {
          "parameters": [
            {
              "name": "q",
              "value": "={{ $json.keywords }} repo:rajrathodpsspl-coder/n8n-learn is:issue is:open"
            },
            {
              "name": "sort",
              "value": "updated"
            },
            {
              "name": "order",
              "value": "desc"
            }
          ]
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "29c811f2-29eb-47f4-9a68-14d6abb59ff6",
      "name": "Merge Github issues and Github PR",
      "type": "n8n-nodes-base.merge",
      "position": [
        4208,
        1056
      ],
      "parameters": {},
      "typeVersion": 3.2,
      "alwaysOutputData": true
    },
    {
      "id": "3881fd16-f04d-435c-81d6-a1385ac621d7",
      "name": "Normalize Calendar and Payloads",
      "type": "n8n-nodes-base.set",
      "position": [
        1952,
        1072
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "e16008af-f28f-4430-998f-a286632fbf23",
              "name": "previousMeetingNotes",
              "type": "string",
              "value": "={{ $json.body }}"
            },
            {
              "id": "4c6e7c45-69f7-47cf-b66a-6be3aa8bdc0f",
              "name": "eventStart",
              "type": "string",
              "value": "={{ $('Format Calenda Event Payload').item.json.eventStart }}"
            },
            {
              "id": "0e66c8bf-ff51-4a85-a1a1-cf5272f8d77f",
              "name": "summary",
              "type": "string",
              "value": "={{ $('Format Calenda Event Payload').item.json.summary }}"
            },
            {
              "id": "3039ba27-cc43-449b-8100-078554284ac5",
              "name": "attendees",
              "type": "array",
              "value": "={{ $('Format Calenda Event Payload').item.json.attendees }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "dc05e3c7-1843-4f49-a0e5-df8a421acb39",
      "name": "Prepare PRs and issues List",
      "type": "n8n-nodes-base.code",
      "position": [
        4208,
        688
      ],
      "parameters": {
        "jsCode": "const response = $input.first().json;\n\nconst tickets = (response.items || [])\n  .filter(issue =>\n    (issue.labels || []).some(\n      label => label.name?.toLowerCase() === 'meeting-notes'\n    )\n  )\n  .map(issue => ({\n    source: 'GitHub',\n    id: `ISSUE-${issue.number}`,\n    title: issue.title,\n    url: issue.html_url\n  }));\n\nreturn [\n  {\n    json: {\n      tickets\n    }\n  }\n];"
      },
      "typeVersion": 2
    },
    {
      "id": "c37ffd9d-24e7-41e9-9a16-5513a4ca4bbd",
      "name": "Add 5 minute Early Time",
      "type": "n8n-nodes-base.code",
      "position": [
        2176,
        704
      ],
      "parameters": {
        "jsCode": "const start = new Date($input.first().json.eventStart);\nconst notifyAt = new Date(start.getTime() - 5 * 60 * 1000);\n\nreturn {\n  ...$input.first().json,\n  notifyAt\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "005f78a7-96dc-4c70-b3a4-46fc73da5cd8",
      "name": "Format Calenda Event Payload",
      "type": "n8n-nodes-base.code",
      "position": [
        1040,
        704
      ],
      "parameters": {
        "jsCode": "const meetings = $input.all().map(item => item.json);\n\nconst now = new Date();\n\n// Find the next upcoming meeting\nconst nextMeeting = meetings\n  .filter(meeting => new Date(meeting.start.dateTime) > now)\n  .sort((a, b) => new Date(a.start.dateTime) - new Date(b.start.dateTime))[0];\n\nif (!nextMeeting) {\n  return [];\n}\n\nreturn [\n  {\n    json: {\n      eventStart: nextMeeting.start.dateTime,\n      summary: nextMeeting.summary,\n      attendees: nextMeeting.attendees || []\n    }\n  }\n];"
      },
      "typeVersion": 2
    },
    {
      "id": "5c97cdd4-1b94-4c80-a5bf-4a97b10e20f5",
      "name": "If",
      "type": "n8n-nodes-base.if",
      "position": [
        4944,
        304
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "36cb4e3e-7d76-4244-9a56-b0f8c0267e2a",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $json.tickets.length > 0 }}",
              "rightValue": "false"
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "7f57f1b3-d69f-4034-abca-2f1f89655d7c",
      "name": "Get events from Google calendar",
      "type": "n8n-nodes-base.googleCalendar",
      "position": [
        800,
        704
      ],
      "parameters": {
        "options": {},
        "calendar": {
          "__rl": true,
          "mode": "list",
          "value": "Select Calenar",
          "cachedResultName": "Calendar name"
        },
        "operation": "getAll"
      },
      "credentials": {
        "googleCalendarOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "465822ce-2689-44d4-a396-dc86c9c39a53",
      "name": "Hourly Check Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        608,
        704
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours"
            }
          ]
        }
      },
      "typeVersion": 1.3
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "584998c4-6614-4d55-94b7-b41a4c087715",
  "connections": {
    "If": {
      "main": [
        [
          {
            "node": "Build Message for Slack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTTP Request": {
      "main": [
        [
          {
            "node": "Merge Github issues and Github PR",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Fan Out Attendees": {
      "main": [
        [
          {
            "node": "Get User Slack Info from Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get PRs from Repo": {
      "main": [
        [
          {
            "node": "Filter PRs Related to Meeting",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Is Previous Meeting": {
      "main": [
        [
          {
            "node": "Normalize Calendar and Payloads",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Hourly Check Trigger": {
      "main": [
        [
          {
            "node": "Get events from Google calendar",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait for Time to Come": {
      "main": [
        [
          {
            "node": "Extract Meeting Keywords",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Slack User Found": {
      "main": [
        [
          {
            "node": "Send Meeting Context in Slack DM",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Last Meeting Notes": {
      "main": [
        [
          {
            "node": "Is Previous Meeting",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Add 5 minute Early Time": {
      "main": [
        [
          {
            "node": "Wait for Time to Come",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Message for Slack": {
      "main": [
        [
          {
            "node": "Normalize Attendees and Slack Message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Meeting Keywords": {
      "main": [
        [
          {
            "node": "Get PRs from Repo",
            "type": "main",
            "index": 0
          },
          {
            "node": "HTTP Request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare PRs and issues List": {
      "main": [
        [
          {
            "node": "If",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Calenda Event Payload": {
      "main": [
        [
          {
            "node": "Get Last Meeting Notes",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter PRs Related to Meeting": {
      "main": [
        [
          {
            "node": "Merge Github issues and Github PR",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get User Slack Info from Email": {
      "main": [
        [
          {
            "node": "Check Slack User Found",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get events from Google calendar": {
      "main": [
        [
          {
            "node": "Format Calenda Event Payload",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize Calendar and Payloads": {
      "main": [
        [
          {
            "node": "Add 5 minute Early Time",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge Github issues and Github PR": {
      "main": [
        [
          {
            "node": "Prepare PRs and issues List",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize Attendees and Slack Message": {
      "main": [
        [
          {
            "node": "Fan Out Attendees",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}