AutomationFlowsAI & RAG › /intel — RAG Slash Command

/intel — RAG Slash Command

/intel — RAG slash command. Uses httpRequest. Webhook trigger; 12 nodes.

Webhook trigger★★★★☆ complexity12 nodesHTTP Request
AI & RAG Trigger: Webhook Nodes: 12 Complexity: ★★★★☆ Added:
/intel — RAG Slash Command — n8n workflow card showing HTTP Request integration

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
{
  "_comment": [
    "/intel slash command handler \u2014 RAG over the competitive-intel knowledge base.",
    "1. Webhook (responseMode=onReceived) returns immediate 200 to Slack to satisfy the 3s ack requirement.",
    "2. Code parses the slash-command body (form-encoded): extracts competitor (Pigment|Anaplan|Planful|Drivetrain|Vena) and timeframe (default 90d) from `text`.",
    "3. HF embed query -> Supabase RPC match_competitor_intel (with competitor_filter + days_back) -> Claude Sonnet answer (grounded; never hallucinates) -> POST to response_url.",
    "4. Empty-result handling: 'No intelligence found for X in last Yd. Last signal: <date or never>.' Never invents content.",
    "5. n8n Cloud FREE TIER NOTE: open Config and replace placeholders. No $env references."
  ],
  "name": "/intel \u2014 RAG slash command",
  "nodes": [
    {
      "parameters": {
        "content": "## /intel slash command\n\n**\u26a0\ufe0f Before first run:** open **Config** and fill: `anthropic_api_key`, `huggingface_api_key`, `supabase_url`, `supabase_service_role_key`, `slack_signing_secret` (optional, used for request verification).\n\n**Slack app config:** point the slash command at `POST {n8n_base}/webhook/intel`. Slack will POST `application/x-www-form-urlencoded` with `token, team_id, command, text, response_url, user_id, user_name, ...`.\n\n**Usage:** `/intel <competitor>? <timeframe>?`\n- `/intel Pigment last 30 days` \u2014 filter to Pigment, 30-day window\n- `/intel last 14 days` \u2014 all competitors, 14-day window\n- `/intel` \u2014 all competitors, default 90 days\n\n**Flow:** webhook (immediate 200) -> Config -> parse query -> HF embed -> Supabase RPC -> Claude Sonnet -> POST answer to `response_url`. Latency budget: ~3-6s end-to-end.",
        "height": 320,
        "width": 720
      },
      "id": "i0000000-0000-0000-0000-0000000000aa",
      "name": "\ud83d\udccc /intel overview",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -220,
        -120
      ]
    },
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "intel",
        "responseMode": "onReceived",
        "responseData": "noData",
        "responseCode": 200,
        "options": {
          "rawBody": false,
          "noResponseBody": true
        }
      },
      "id": "i1111111-1111-1111-1111-111111111111",
      "name": "Webhook \u2014 /intel",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        -160,
        360
      ]
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "c-aak",
              "name": "anthropic_api_key",
              "type": "string",
              "value": "__ANTHROPIC_API_KEY__"
            },
            {
              "id": "c-hfk",
              "name": "huggingface_api_key",
              "type": "string",
              "value": "__HUGGINGFACE_API_KEY__"
            },
            {
              "id": "c-sbu",
              "name": "supabase_url",
              "type": "string",
              "value": "https://__YOUR_PROJECT__.supabase.co"
            },
            {
              "id": "c-srk",
              "name": "supabase_service_role_key",
              "type": "string",
              "value": "__SUPABASE_SERVICE_ROLE_KEY__"
            },
            {
              "id": "c-em",
              "name": "embedding_model",
              "type": "string",
              "value": "sentence-transformers/all-MiniLM-L6-v2"
            },
            {
              "id": "c-ms",
              "name": "llm_model_synthesize",
              "type": "string",
              "value": "claude-sonnet-4-6"
            },
            {
              "id": "c-lpk",
              "name": "langfuse_public_key",
              "type": "string",
              "value": "__LANGFUSE_PUBLIC_KEY__"
            },
            {
              "id": "c-lsk",
              "name": "langfuse_secret_key",
              "type": "string",
              "value": "__LANGFUSE_SECRET_KEY__"
            },
            {
              "id": "c-lh",
              "name": "langfuse_host",
              "type": "string",
              "value": "https://cloud.langfuse.com"
            }
          ]
        },
        "options": {}
      },
      "id": "i2222222-2222-2222-2222-222222222222",
      "name": "Config",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        60,
        360
      ]
    },
    {
      "parameters": {
        "jsCode": "// Slack slash commands POST application/x-www-form-urlencoded.\n// n8n Webhook node parses form bodies into $json.body when content-type is form-urlencoded.\nconst body = $('Webhook \u2014 /intel').first().json.body || $('Webhook \u2014 /intel').first().json;\nconst text = (body.text || '').trim();\nconst response_url = body.response_url || null;\nconst user_name = body.user_name || 'unknown';\n\n// Parse competitor name (case-insensitive match) + timeframe.\nconst competitors = ['Pigment','Anaplan','Planful','Drivetrain','Vena'];\nlet competitor_filter = null;\nfor (const c of competitors) {\n  const re = new RegExp(`\\\\b${c}\\\\b`, 'i');\n  if (re.test(text)) { competitor_filter = c; break; }\n}\n\n// Timeframe: 'last N days' | 'last N weeks' | 'last N months' | default 90 days\nlet days_back = 90;\nconst m = text.match(/last\\s+(\\d+)\\s*(day|week|month)s?/i);\nif (m) {\n  const n = parseInt(m[1], 10);\n  const unit = m[2].toLowerCase();\n  days_back = unit === 'day' ? n : unit === 'week' ? n * 7 : n * 30;\n}\n\n// Build the embedding query: drop the parsed competitor + timeframe, keep the rest as semantic intent.\nlet semantic_query = text\n  .replace(new RegExp(`\\\\b(${competitors.join('|')})\\\\b`, 'gi'), '')\n  .replace(/last\\s+\\d+\\s*(day|week|month)s?/gi, '')\n  .replace(/\\s+/g, ' ').trim();\nif (!semantic_query) semantic_query = competitor_filter ? `recent intelligence about ${competitor_filter}` : 'recent competitive intelligence';\n\nif (!response_url) {\n  return [{ json: { _hard_error: 'missing_response_url', received: body } }];\n}\n\nreturn [{ json: { competitor_filter, days_back, semantic_query, response_url, user_name, raw_text: text } }];\n"
      },
      "id": "i3333333-3333-3333-3333-333333333333",
      "name": "Code \u2014 parse query",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        280,
        360
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "=https://router.huggingface.co/hf-inference/models/{{ $('Config').first().json.embedding_model || 'sentence-transformers/all-MiniLM-L6-v2' }}/pipeline/feature-extraction",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "=Bearer {{ $('Config').first().json.huggingface_api_key }}"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"inputs\": {{ JSON.stringify($json.semantic_query) }},\n  \"options\": { \"wait_for_model\": true }\n}",
        "options": {
          "response": {
            "response": {
              "neverError": true,
              "responseFormat": "json"
            }
          },
          "timeout": 25000
        }
      },
      "id": "i4444444-4444-4444-4444-444444444444",
      "name": "HF \u2014 embed query",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        500,
        360
      ],
      "continueOnFail": true,
      "alwaysOutputData": true,
      "onError": "continueRegularOutput",
      "retryOnFail": true,
      "maxTries": 2,
      "waitBetweenTries": 5000
    },
    {
      "parameters": {
        "method": "POST",
        "url": "={{ $('Config').first().json.supabase_url }}/rest/v1/rpc/match_competitor_intel",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "apikey",
              "value": "={{ $('Config').first().json.supabase_service_role_key }}"
            },
            {
              "name": "Authorization",
              "value": "=Bearer {{ $('Config').first().json.supabase_service_role_key }}"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"query_embedding\": {{ JSON.stringify((() => { const all = $input.all().map(x => x.json); if (all.length === 1 && Array.isArray(all[0]) && Array.isArray(all[0][0])) return all[0][0]; if (all.length === 1 && Array.isArray(all[0])) return all[0]; if (all.every(v => typeof v === 'number')) return all; return all[0]; })()) }},\n  \"match_count\": 8,\n  \"competitor_filter\": {{ JSON.stringify($('Code \u2014 parse query').first().json.competitor_filter) }},\n  \"days_back\": {{ $('Code \u2014 parse query').first().json.days_back }}\n}",
        "options": {
          "response": {
            "response": {
              "neverError": true,
              "responseFormat": "json"
            }
          },
          "timeout": 12000
        }
      },
      "id": "i5555555-5555-5555-5555-555555555555",
      "name": "Supabase \u2014 RAG search",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        720,
        360
      ],
      "continueOnFail": true,
      "alwaysOutputData": true,
      "onError": "continueRegularOutput",
      "retryOnFail": true,
      "maxTries": 2,
      "waitBetweenTries": 3000
    },
    {
      "parameters": {
        "jsCode": "// Decide whether to short-circuit with an empty-result Slack message,\n// or proceed to LLM synthesis.\n// v34: tight filter + cap. n8n was occasionally producing very long input lists\n// (probably re-running the node per item from earlier nodes). We now:\n//   1. only count items that look like real hits (competitor_name + content)\n//   2. cap at 8 so the Sonnet body stays small (matches RPC's match_count: 8)\nconst allItems = $input.all().map(i => i.json).filter(Boolean);\nlet rag = allItems;\nif (rag.length === 1 && Array.isArray(rag[0]?.results)) rag = rag[0].results;\nconst q = $('Code \u2014 parse query').first().json;\nconst validHits = rag.filter(r =>\n  r && typeof r === 'object' && r.competitor_name && (r.content || '').length > 0\n);\nconst hits = validHits.slice(0, 8);\n\nif (hits.length === 0) {\n  // Look up the most recent signal for this competitor (or any) to give the user a real anchor.\n  const targetLabel = q.competitor_filter ? `**${q.competitor_filter}**` : 'any competitor';\n  const text = `\ud83d\udd0d *No intelligence found for ${targetLabel} in last ${q.days_back} days.*\\nTry a wider window \u2014 e.g. \\`/intel ${q.competitor_filter || 'Pigment'} last 180 days\\`.`;\n  return [{ json: {\n    short_circuit: true,\n    response_url: q.response_url,\n    slack_payload: {\n      response_type: 'ephemeral',\n      text,\n      blocks: [\n        { type: 'section', text: { type: 'mrkdwn', text } },\n        { type: 'context', elements: [\n          { type: 'mrkdwn', text: `_Query: \\`${q.raw_text || '(empty)'}\\`  \u00b7  filter: ${q.competitor_filter || 'none'}  \u00b7  window: ${q.days_back}d_` }\n        ] }\n      ]\n    }\n  } }];\n}\n\nreturn [{ json: { short_circuit: false, hits, query: q } }];\n"
      },
      "id": "i6666666-6666-6666-6666-666666666666",
      "name": "Code \u2014 empty-result guard",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        940,
        360
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "cond-sc",
              "leftValue": "={{ $json.short_circuit }}",
              "rightValue": "={{ true }}",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "i7777777-7777-7777-7777-777777777777",
      "name": "IF \u2014 empty result?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        1160,
        360
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.anthropic.com/v1/messages",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "x-api-key",
              "value": "={{ $('Config').first().json.anthropic_api_key }}"
            },
            {
              "name": "anthropic-version",
              "value": "2023-06-01"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({\n  model: $('Config').first().json.llm_model_synthesize || 'claude-sonnet-4-6',\n  max_tokens: 800,\n  temperature: 0.2,\n  system: \"You are a competitive intelligence analyst answering Slack queries from sales reps. Use ONLY the snippets provided in <retrieved_intel>. Never invent facts. If the snippets don't directly answer the question, say so explicitly and cite what you DO have. British English. Concise \u2014 3-6 short sentences max. End with one '_Source(s):_' line listing competitor + scrape date for each snippet you used. Output plain markdown (Slack mrkdwn dialect), no JSON.\",\n  messages: [{ role: 'user', content:\n    '<query>\\n' + ($json.query.raw_text || '') +\n    '\\n(filter: ' + ($json.query.competitor_filter || 'all competitors') +\n    ' \u00b7 window: last ' + ($json.query.days_back || 90) + ' days)\\n</query>\\n\\n' +\n    '<retrieved_intel>\\n' + JSON.stringify(($json.hits || []).map(h => ({\n      competitor: h.competitor_name,\n      type: h.signal_type,\n      content: (h.content || '').slice(0, 600),\n      source_url: h.source_url,\n      scraped_at: h.scraped_at,\n      similarity: Number(h.similarity || 0).toFixed(2)\n    }))) +\n    '\\n</retrieved_intel>\\n\\nAnswer the query. Be specific about which competitor each fact belongs to. If the retrieved intel does not directly answer the question, say so and report what is available instead.'\n  }]\n}) }}",
        "options": {
          "response": {
            "response": {
              "neverError": true,
              "responseFormat": "json"
            }
          },
          "timeout": 30000
        }
      },
      "id": "i8888888-8888-8888-8888-888888888888",
      "name": "Claude Sonnet \u2014 answer",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1400,
        460
      ],
      "continueOnFail": true,
      "alwaysOutputData": true,
      "onError": "continueRegularOutput",
      "retryOnFail": true,
      "maxTries": 2,
      "waitBetweenTries": 30000
    },
    {
      "parameters": {
        "jsCode": "// Render the final Slack payload from Sonnet's answer + retrieved hits.\n// v33: defensive hit count (n8n's per-item iteration can inflate hits.length)\n//      + substitute Notion battlecard URLs for battlecard sources (which have\n//      no source_url and would otherwise render as about:blank links).\nconst llm = $json;\nconst upstream = $('Code \u2014 empty-result guard').first().json;\nconst q = upstream.query || {};\n// Always coerce hits to a real array for safe .length / .slice / .map.\nconst rawHits = upstream.hits;\nconst hits = Array.isArray(rawHits) ? rawHits : (rawHits ? [rawHits] : []);\nconst hitCount = hits.length;\n\nconst BATTLECARD_NOTION_URLS = {\n  Pigment:    'https://www.notion.so/354cab25fcdb818ba2fdc0ac249f8515',\n  Anaplan:    'https://www.notion.so/354cab25fcdb81c0bfefc1cab7d1e637',\n  Planful:    'https://www.notion.so/354cab25fcdb814791f0c4535059021e',\n  Drivetrain: 'https://www.notion.so/354cab25fcdb81abaf92d7ee69630f2e',\n  Vena:       'https://www.notion.so/354cab25fcdb81f6a99ae7f5f0d86442'\n};\nconst urlFor = (h) => {\n  if (h.source_url) return h.source_url;\n  if (h.source === 'battlecard' && BATTLECARD_NOTION_URLS[h.competitor_name]) return BATTLECARD_NOTION_URLS[h.competitor_name];\n  return 'https://www.notion.so/354cab25fcdb815db9a3d396b412a0ec';\n};\n\nlet answer;\ntry {\n  answer = llm?.content?.[0]?.text || null;\n  if (!answer) throw new Error('no_content');\n  // v35: Slack mrkdwn uses *bold*, not **bold**. Sonnet sometimes emits standard\n  // Markdown despite the system prompt; normalise here so the message renders.\n  answer = answer\n    .replace(/\\*\\*([^*\\n]+)\\*\\*/g, '*$1*')\n    .replace(/__([^_\\n]+)__/g, '*$1*');\n} catch (e) {\n  answer = '\u26a0\ufe0f Couldn\\'t synthesise an answer right now (LLM error). Showing raw matches below.';\n}\n\nconst headerText = `\ud83d\udd0d */intel ${q.competitor_filter || 'all'}* \u2014 last ${q.days_back} days`;\nconst sourcesContext = hits.slice(0, 3).map(h => `<${urlFor(h)}|${h.competitor_name} \u00b7 ${h.signal_type} \u00b7 ${(h.scraped_at || '').slice(0,10)}>`).join('  \u00b7  ');\n\nconst slack_payload = {\n  response_type: 'in_channel',\n  text: headerText,\n  blocks: [\n    { type: 'section', text: { type: 'mrkdwn', text: `*${headerText}*\\n${answer}` } },\n    { type: 'context', elements: [\n      { type: 'mrkdwn', text: `_Top sources: ${sourcesContext || '(none)'}_` },\n      { type: 'mrkdwn', text: `_Asked by @${q.user_name}  \u00b7  ${hitCount} hits  \u00b7  query: \\`${q.raw_text || '(empty)'}\\`_` }\n    ] }\n  ]\n};\n\nreturn [{ json: { response_url: q.response_url, slack_payload } }];\n"
      },
      "id": "i8888888-8888-8888-8888-888888888889",
      "name": "Code \u2014 render answer",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1640,
        460
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "={{ $json.response_url }}",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify($json.slack_payload) }}",
        "options": {
          "response": {
            "response": {
              "neverError": true,
              "responseFormat": "text"
            }
          },
          "timeout": 10000
        }
      },
      "id": "i9999999-9999-9999-9999-999999999999",
      "name": "Slack \u2014 POST response_url",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1880,
        360
      ],
      "continueOnFail": true,
      "alwaysOutputData": true,
      "onError": "continueRegularOutput",
      "retryOnFail": true,
      "maxTries": 2,
      "waitBetweenTries": 5000
    },
    {
      "parameters": {
        "method": "POST",
        "url": "={{ $('Config').first().json.langfuse_host }}/api/public/traces",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "=Basic {{ Buffer.from($('Config').first().json.langfuse_public_key + ':' + $('Config').first().json.langfuse_secret_key).toString('base64') }}"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"name\": \"intel_query\",\n  \"input\": {{ ($('Claude Sonnet \u2014 answer').first().json.usage && $('Claude Sonnet \u2014 answer').first().json.usage.input_tokens) || 0 }},\n  \"output\": {{ ($('Claude Sonnet \u2014 answer').first().json.usage && $('Claude Sonnet \u2014 answer').first().json.usage.output_tokens) || 0 }},\n  \"metadata\": {\n    \"model\": {{ JSON.stringify($('Claude Sonnet \u2014 answer').first().json.model || $('Config').first().json.llm_model_synthesize) }},\n    \"run_id\": {{ JSON.stringify('intel_' + ($('Code \u2014 parse query').first().json.user_name || 'anon')) }},\n    \"competitor\": {{ JSON.stringify($('Code \u2014 parse query').first().json.competitor_filter) }},\n    \"days_back\": {{ $('Code \u2014 parse query').first().json.days_back }},\n    \"hits\": {{ ($('Code \u2014 empty-result guard').first().json.hits || []).length }},\n    \"cost_estimate\": {{ ((($('Claude Sonnet \u2014 answer').first().json.usage || {}).input_tokens || 0) * 0.000003) + ((($('Claude Sonnet \u2014 answer').first().json.usage || {}).output_tokens || 0) * 0.000015) }}\n  }\n}",
        "options": {
          "response": {
            "response": {
              "neverError": true,
              "responseFormat": "json"
            }
          },
          "timeout": 8000
        }
      },
      "id": "lfi00001-0000-0000-0000-00000000000c",
      "name": "Langfuse \u2014 log intel query",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1640,
        640
      ],
      "continueOnFail": true,
      "alwaysOutputData": true,
      "onError": "continueRegularOutput",
      "retryOnFail": false
    }
  ],
  "connections": {
    "Webhook \u2014 /intel": {
      "main": [
        [
          {
            "node": "Config",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Config": {
      "main": [
        [
          {
            "node": "Code \u2014 parse query",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code \u2014 parse query": {
      "main": [
        [
          {
            "node": "HF \u2014 embed query",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HF \u2014 embed query": {
      "main": [
        [
          {
            "node": "Supabase \u2014 RAG search",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Supabase \u2014 RAG search": {
      "main": [
        [
          {
            "node": "Code \u2014 empty-result guard",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code \u2014 empty-result guard": {
      "main": [
        [
          {
            "node": "IF \u2014 empty result?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF \u2014 empty result?": {
      "main": [
        [
          {
            "node": "Slack \u2014 POST response_url",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Claude Sonnet \u2014 answer",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Claude Sonnet \u2014 answer": {
      "main": [
        [
          {
            "node": "Code \u2014 render answer",
            "type": "main",
            "index": 0
          },
          {
            "node": "Langfuse \u2014 log intel query",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code \u2014 render answer": {
      "main": [
        [
          {
            "node": "Slack \u2014 POST response_url",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1",
    "saveManualExecutions": true,
    "callerPolicy": "workflowsFromSameOwner",
    "errorWorkflow": ""
  },
  "staticData": null,
  "tags": [
    {
      "name": "scenario-rag"
    },
    {
      "name": "slash-command"
    }
  ],
  "triggerCount": 1,
  "versionId": "1.0.0"
}
Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

/intel — RAG slash command. Uses httpRequest. Webhook trigger; 12 nodes.

Source: https://github.com/arjitmat/gtm-intelligence-agent/blob/9ed50a103ef002227d109af15515d165c27a3f53/n8n/intel_query_workflow.json — 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

Jigsaw API key for image processing, I use this as a gatekeeper/second pair of eyes. LINK to their website https://jigsawstack.com/ SECOND A postgress DATABASE (I use Supabase) LlamaCloud for the pars

HTTP Request, Postgres, Stop And Error +2
AI & RAG

Onsite Photos to Jobs (SMS Agent). Uses dataTable, twilio, httpRequest, airtable. Webhook trigger; 62 nodes.

Data Table, Twilio, HTTP Request +1
AI & RAG

AML Alert Triage. Uses httpRequest. Webhook trigger; 57 nodes.

HTTP Request
AI & RAG

W1 - IN WhatsApp Adapter (Secure + Fast ACK). Uses postgres, redis, httpRequest. Webhook trigger; 50 nodes.

Postgres, Redis, HTTP Request
AI & RAG

W1 - IN WhatsApp Adapter (Secure + Fast ACK). Uses postgres, redis, httpRequest. Webhook trigger; 48 nodes.

Postgres, Redis, HTTP Request