{
  "name": "Slack chat router (example)",
  "nodes": [
    {
      "parameters": {
        "trigger": [
          "any_event",
          "message"
        ],
        "watchWorkspace": true,
        "options": {
          "resolveIds": false,
          "userIds": "={{ [\"U00000000BOT\"] }}"
        }
      },
      "type": "n8n-nodes-base.slackTrigger",
      "typeVersion": 1,
      "position": [
        -288,
        48
      ],
      "id": "a4fd7e45-2ec5-4588-8419-cdd0c787e0e6",
      "name": "Slack Trigger",
      "credentials": {
        "slackApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 3
                },
                "conditions": [
                  {
                    "leftValue": "={{ $json.user === \"U00000000OWNER\" && $json.type === \"message\" }}",
                    "rightValue": "",
                    "operator": {
                      "type": "boolean",
                      "operation": "true",
                      "singleValue": true
                    },
                    "id": "69ac51ac-eef9-422a-846a-9d23760f7daa"
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "Owner new message"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 3
                },
                "conditions": [
                  {
                    "id": "6be2d2be-bdfb-4487-9a6f-1b87abb452e8",
                    "leftValue": "={{ $json.user === \"U00000000OWNER\" && $json.type === \"reaction\" }}",
                    "rightValue": "",
                    "operator": {
                      "type": "string",
                      "operation": "equals",
                      "name": "filter.operator.equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "Owner Added Reaction"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 3
                },
                "conditions": [
                  {
                    "id": "3726290c-15b6-4c60-9720-28b109b45859",
                    "leftValue": "={{ $json.user !== \"U00000000OWNER\" && $json.type === \"message\" }}",
                    "rightValue": "",
                    "operator": {
                      "type": "boolean",
                      "operation": "true",
                      "singleValue": true
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "unknown user"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3.4,
      "position": [
        160,
        32
      ],
      "id": "fc990f48-cd17-43f1-b04b-a8036d67c370",
      "name": "Switch"
    },
    {
      "parameters": {
        "select": "user",
        "user": {
          "__rl": true,
          "value": "={{ $('Slack Trigger').item.json.user }}",
          "mode": "id"
        },
        "text": "={{ [\"Two atoms walk into a bar. One says 'I think I lost an electron.' The other replies, 'Are you sure?' 'I'm positive.'\",\"A neutron walks into a bar. The bartender says, 'For you, no charge.'\",\"Photons have mass? I didn't even know they were Catholic.\",\"I'd help you, but my owner has me on a strict no-stranger policy.\"][Math.floor(Math.random()*4)] }}\n\n_I'm a private AI assistant. I only respond to my owner._",
        "otherOptions": {
          "includeLinkToWorkflow": false,
          "thread_ts": {
            "replyValues": {
              "thread_ts": "={{ $('Slack Trigger').item.json.ts }}"
            }
          },
          "mrkdwn": true
        }
      },
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.4,
      "position": [
        528,
        304
      ],
      "id": "47bffa05-810e-4c70-bd3f-950b794e35d7",
      "name": "Send canned reply to non-owner",
      "credentials": {
        "slackApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "workflowId": {
          "__rl": true,
          "value": "exampleAgentCoreWfId",
          "mode": "list",
          "cachedResultName": "Chat agent core"
        },
        "workflowInputs": {
          "mappingMode": "defineBelow",
          "value": {
            "chatInput": "={{ $('Slack Trigger').item.json.text }}",
            "threadId": "={{ $('Slack Trigger').item.json.thread_ts || $('Slack Trigger').item.json.ts }}"
          },
          "matchingColumns": [],
          "schema": [
            {
              "id": "chatInput",
              "displayName": "chatInput",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "canBeUsedToMatch": true,
              "type": "string",
              "removed": false
            },
            {
              "id": "threadId",
              "displayName": "threadId",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "canBeUsedToMatch": true,
              "type": "string",
              "removed": false
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": true
        },
        "options": {}
      },
      "type": "n8n-nodes-base.executeWorkflow",
      "typeVersion": 1.3,
      "position": [
        768,
        -208
      ],
      "id": "8f38246b-7810-4875-a6a0-6c0d90273ee2",
      "name": "Call 'Agent core'",
      "retryOnFail": true,
      "maxTries": 2,
      "waitBetweenTries": 5000,
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "select": "user",
        "user": {
          "__rl": true,
          "value": "={{ $('Slack Trigger').item.json.user }}",
          "mode": "id"
        },
        "messageType": "block",
        "blocksUi": "={{ { \"blocks\": $('Call \\'Agent core\\'').item.json.output.blocks } }}",
        "otherOptions": {
          "includeLinkToWorkflow": false,
          "thread_ts": {
            "replyValues": {
              "thread_ts": "={{ $('Slack Trigger').item.json.thread_ts || $('Slack Trigger').item.json.ts }}"
            }
          },
          "mrkdwn": false
        }
      },
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.4,
      "position": [
        1216,
        -208
      ],
      "id": "580cf92e-b198-4eec-988b-f232f7fa345a",
      "name": "Send Block Kit reply",
      "credentials": {
        "slackApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "resource": "reaction",
        "channelId": {
          "__rl": true,
          "value": "={{ $json.channel }}",
          "mode": "id"
        },
        "timestamp": "={{ $json.ts }}",
        "name": "spinner"
      },
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.4,
      "position": [
        528,
        -208
      ],
      "id": "873145eb-46e1-4075-a7f8-10711447b94a",
      "name": "Add Loading Reaction",
      "credentials": {
        "slackApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "resource": "reaction",
        "operation": "remove",
        "channelId": {
          "__rl": true,
          "value": "={{ $('Switch').item.json.channel }}",
          "mode": "id"
        },
        "timestamp": "={{ $('Switch').item.json.ts }}",
        "name": "spinner"
      },
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.4,
      "position": [
        992,
        -208
      ],
      "id": "ee481219-af13-4a1a-9363-2b15791f553d",
      "name": "Remove Loading Reaction (success)",
      "credentials": {
        "slackApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "resource": "reaction",
        "operation": "remove",
        "channelId": {
          "__rl": true,
          "value": "={{ $('Switch').item.json.channel }}",
          "mode": "id"
        },
        "timestamp": "={{ $('Switch').item.json.ts }}",
        "name": "spinner"
      },
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.4,
      "position": [
        800,
        32
      ],
      "id": "e3cfba63-109f-4269-b5b2-1d9353a58167",
      "name": "Remove Loading Reaction (error)",
      "credentials": {
        "slackApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "content": "### Anti-loop filter (trigger-level)\n\nThe Slack Trigger's `options.userIds` is an **exclusion list**: events from any user in the list are dropped before the workflow runs. Put the bot's own user ID here so the bot's replies don't re-trigger the workflow.\n\nWhen the trigger handles the bot filter, no separate Filter node is needed downstream.",
        "height": 336,
        "width": 240
      },
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -336,
        -160
      ],
      "typeVersion": 1,
      "id": "64b85d5f-f0bc-4793-b7a3-88b9b0430118",
      "name": "Sticky: anti-loop"
    },
    {
      "parameters": {
        "content": "Switch routes by event type. Becomes a router for slash commands and shortcuts as new event types are added.",
        "height": 336,
        "width": 208
      },
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        112,
        -112
      ],
      "typeVersion": 1,
      "id": "1b4b8495-b74d-4bba-b79e-51280f69fbeb",
      "name": "Sticky: switch"
    },
    {
      "parameters": {
        "content": "Loading reaction (added before agent, removed on both success and error paths).",
        "height": 336,
        "width": 208
      },
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        480,
        -352
      ],
      "typeVersion": 1,
      "id": "5c88a0a2-c0d5-4e9d-99b5-6c979919f1ae",
      "name": "Sticky: loading reaction"
    },
    {
      "parameters": {
        "content": "### Block Kit envelope, NOT a raw array\n\n`blocksUi` must be an object shaped `{ \"blocks\": [...] }`, where the value is a real array, not just the blocks array on its own.\n\nThe agent returns `{ text, blocks }`, so wrap in a single expression that returns the object (reference the upstream by name, not `$json`):\n\n`={{ { \"blocks\": $('Call \\'Agent core\\'').item.json.output.blocks } }}`\n\nPassing only the array (`={{ $('Call \\'Agent core\\'').item.json.output.blocks }}`) silently fails: the Slack node accepts the input, the message posts with no rich content, and there is no error.",
        "height": 336,
        "width": 280
      },
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1184,
        -560
      ],
      "typeVersion": 1,
      "id": "7b1c2d3e-4f5a-4b6c-9d8e-1f2a3b4c5d6e",
      "name": "Sticky: block kit envelope"
    },
    {
      "parameters": {
        "select": "user",
        "user": {
          "__rl": true,
          "value": "={{ $('Slack Trigger').item.json.user }}",
          "mode": "id"
        },
        "text": "=There was a workflow error. https://<your-n8n-host>/workflow/<this-workflow-id>/executions/{{ $execution.id }}",
        "otherOptions": {
          "includeLinkToWorkflow": false,
          "thread_ts": {
            "replyValues": {
              "thread_ts": "={{ $('Slack Trigger').item.json.thread_ts || $('Slack Trigger').item.json.ts }}"
            }
          },
          "mrkdwn": false
        }
      },
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.4,
      "position": [
        1024,
        32
      ],
      "id": "2267a068-bf1a-48cf-9316-61ad1063c17b",
      "name": "Send error message with execution link",
      "credentials": {
        "slackApi": {
          "name": "<your credential>"
        }
      }
    }
  ],
  "connections": {
    "Slack Trigger": {
      "main": [
        [
          {
            "node": "Switch",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Switch": {
      "main": [
        [
          {
            "node": "Add Loading Reaction",
            "type": "main",
            "index": 0
          }
        ],
        [],
        [
          {
            "node": "Send canned reply to non-owner",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Call 'Agent core'": {
      "main": [
        [
          {
            "node": "Remove Loading Reaction (success)",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Remove Loading Reaction (error)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Add Loading Reaction": {
      "main": [
        [
          {
            "node": "Call 'Agent core'",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Remove Loading Reaction (success)": {
      "main": [
        [
          {
            "node": "Send Block Kit reply",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Remove Loading Reaction (error)": {
      "main": [
        [
          {
            "node": "Send error message with execution link",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}