This workflow follows the Chainllm → Execute Workflow Trigger recipe pattern — see all workflows that pair these two integrations.
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 →
{
"updatedAt": "2025-12-24T08:53:12.750Z",
"createdAt": "2025-12-23T09:30:25.218Z",
"id": "yj2EUpsI7s3mLlRH",
"name": "Capture_Thread",
"description": null,
"active": false,
"isArchived": false,
"nodes": [
{
"parameters": {
"inputSource": "passthrough"
},
"type": "n8n-nodes-base.executeWorkflowTrigger",
"typeVersion": 1.1,
"position": [
-2096,
640
],
"id": "eab3a9d4-6d3a-4560-8e60-612e6f5c9df3",
"name": "ExecuteWorkflowTrigger"
},
{
"parameters": {
"jsCode": "// Build query to get thread history\nconst ctx = $json.ctx;\n\nreturn {\n json: {\n ctx: {\n ...ctx,\n db_queries: [{\n key: 'thread_history',\n sql: 'SELECT timestamp, role, text FROM thread_history WHERE thread_id = $1 ORDER BY timestamp ASC;',\n params: [ctx.event.thread_id]\n }]\n }\n }\n};",
"mode": "runOnceForEachItem"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
-1872,
544
],
"id": "build-thread-history-query",
"name": "BuildThreadHistoryQuery"
},
{
"parameters": {
"workflowId": {
"__rl": true,
"value": "CgUAxK0i4YhrZ2Wp",
"mode": "list",
"cachedResultName": "Execute_Queries",
"cachedResultUrl": "/workflow/CgUAxK0i4YhrZ2Wp"
},
"workflowInputs": {
"mappingMode": "defineBelow",
"value": {
"ctx": "={{ $json.ctx }}"
}
},
"options": {
"waitForSubWorkflow": true
}
},
"type": "n8n-nodes-base.executeWorkflow",
"typeVersion": 1.2,
"position": [
-1648,
544
],
"id": "execute-thread-history",
"name": "GetThreadHistory"
},
{
"parameters": {
"jsCode": "// Merge DB results into ctx pattern\nconst ctx = $json.ctx;\n\n// Get thread messages from db results\nconst messages = ctx.db.thread_history.rows || [];\n\n// Format thread history for LLM (reversed for chronological order)\nconst threadHistory = messages.toReversed().map(msg => {\n return `${msg.role.toUpperCase()}: ${msg.text}`;\n}).join('\\n');\n\nreturn {\n json: {\n ctx: {\n ...ctx,\n db: {\n ...ctx.db,\n thread_id: ctx.event.thread_id,\n thread_history: threadHistory,\n message_count: messages.length\n }\n }\n }\n};",
"mode": "runOnceForEachItem"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
-1424,
544
],
"id": "eb096fdc-babc-49e4-9213-36f22ae98b6e",
"name": "PrepareContext"
},
{
"parameters": {
"promptType": "define",
"text": "=You are analyzing a conversation thread to extract key insights and actionable items.\n\n## Thread History\n{{ $json.ctx.db.thread_history }}\n\n## Task\nExtract and classify the most important items from the thread into **exactly one** category each:\n\n**reflection** - Internal knowledge about the user (personal insights, patterns, preferences, decisions, or commitments) \n**fact** - External knowledge about the world, people, events, or things (objective information not tied to the user's internal state) \n**todo** - Concrete, actionable tasks or next steps (specific and doable)\n\n## Few-Shot Examples\n\n**Example Thread 1:**\n\"I realized I get my best work done in the mornings right after coffee. My mom's birthday is coming up on June 12th, I need to get her a gift. John told me he really likes dark roast with no sugar. I've decided to stop scheduling meetings before noon. Also, I should probably block out 2-hour chunks for deep work. Sarah mentioned she's allergic to peanuts.\"\n\n**Good Extraction:**\nreflection|I get my best work done in the mornings right after coffee\nreflection|I've decided to stop scheduling meetings before noon\ntodo|Get mom a gift for her June 12th birthday\ntodo|Block out 2-hour chunks for deep work\nfact|Mom's birthday is June 12th\nfact|John really likes dark roast with no sugar\nfact|Sarah is allergic to peanuts\n\n**Example Thread 2:**\n\"Maybe I should try walking more, it might help with focus. Dad prefers calls in the evening. I'm going to switch to async updates for the team. Don't forget to send the report by Friday. The office WiFi password is 'guest123'. I tend to lose steam after lunch if I eat carbs.\"\n\n**Good Extraction:**\nreflection|I'm going to switch to async updates for the team\nreflection|I tend to lose steam after lunch if I eat carbs\ntodo|Send the report by Friday\nfact|Dad prefers calls in the evening\nfact|The office WiFi password is 'guest123'\nreflection|Walking more might help with focus (tentative insight)\n\n**Bad Examples (Do NOT do these):**\n- \u274c `reflection|Send the report by Friday` (action = todo, not reflection)\n- \u274c `fact|I realized I work best in the morning` (user insight = reflection, not fact)\n- \u274c `todo|Dad prefers calls in the evening` (info about another person = fact, not todo)\n- \u274c Including both a reflection AND a todo for the same item\n- \u274c Creating tasks that are vague or not actionable (e.g., \"think about...\")\n\n## Output Format\nReturn one line per item:\n`type|text`\n\nReturn ONLY the categorized items, no explanations.",
"needsFallback": true,
"batching": {}
},
"type": "@n8n/n8n-nodes-langchain.chainLlm",
"typeVersion": 1.7,
"position": [
-976,
544
],
"id": "f10c50b2-ae2f-463b-8378-6b36c12d2b21",
"name": "ExtractItemsLlm"
},
{
"parameters": {
"jsCode": "// Parse LLM output in pipe format: \"type|text\"\nlet llmOutput = $json.text.trim();\nconst ctx = $('PrepareContext').first().json.ctx;\n\ntry {\n const lines = llmOutput.split('\\n').filter(line => line.includes('|'));\n const extractions = [];\n let displayOrder = 1;\n \n lines.forEach(line => {\n const parts = line.split('|');\n if (parts.length < 2) return;\n \n const itemType = parts[0].trim();\n const text = parts.slice(1).join('|').trim(); // Handle pipes in text\n \n // Validate item_type\n if (!['reflection', 'fact', 'todo'].includes(itemType)) {\n console.error(`Invalid item_type: ${itemType}`);\n return;\n }\n \n extractions.push({\n thread_id: ctx.db.thread_id,\n item_type: itemType,\n text: text,\n display_order: displayOrder++\n });\n });\n \n // Return ctx with llm namespace added\n return {\n json: {\n ctx: {\n ...ctx,\n llm: {\n raw_output: llmOutput,\n extractions: extractions,\n has_extractions: extractions.length > 0\n }\n }\n }\n }];\n} catch (error) {\n // On error, return empty extractions\n return {\n json: {\n ctx: {\n ...ctx,\n llm: {\n raw_output: llmOutput,\n extractions: [],\n has_extractions: false,\n parse_error: error.message\n }\n }\n }\n }];\n}",
"mode": "runOnceForEachItem"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
-624,
544
],
"id": "93bcf029-9040-466f-957c-2a9c8d87a451",
"name": "ParseExtractions"
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 1
},
"conditions": [
{
"id": "e3ae6cd9-7b12-406f-b233-afdc77ea403e",
"leftValue": "={{ $json.ctx.llm.extractions }}",
"rightValue": "",
"operator": {
"type": "array",
"operation": "notEmpty",
"singleValue": true
}
}
],
"combinator": "and"
},
"options": {}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
-176,
544
],
"id": "3a3d0695-4532-4b46-bbd1-6fc531e8ad12",
"name": "HasExtractions?"
},
{
"parameters": {
"jsCode": "// Build query for trace and void old extractions\nconst ctx = $('SetInferenceStart').first().json.ctx;\nconst inferenceStart = ctx.timing?.inference_start || Date.now();\nconst durationMs = Date.now() - inferenceStart;\nconst llmOutput = $('ExtractItemsLlm').first().json.text;\nconst parsedCtx = $json.ctx;\n\n// Build filled prompt\nconst promptText = `You are analyzing a conversation thread to extract key insights and actionable items.\n\n## Thread History\n${ctx.db.thread_history}\n\n## Task\nExtract and classify the most important items from the thread...`;\n\n// Format trace_chain for PostgreSQL uuid[] type\nconst traceChain = ctx.event.trace_chain || [];\nconst traceChainPg = '{' + traceChain.join(',') + '}';\n\nreturn {\n json: {\n ctx: {\n ...parsedCtx,\n db_queries: [\n {\n key: 'trace',\n sql: `WITH new_trace AS (\n INSERT INTO traces (event_id, step_name, data, trace_chain)\n VALUES (\n $1::uuid,\n 'thread_extraction',\n jsonb_build_object(\n 'input', jsonb_build_object(\n 'thread_history', $2,\n 'conversation_id', $3::text\n ),\n 'prompt', $4,\n 'completion', $5,\n 'result', jsonb_build_object(\n 'extraction_count', $6::integer,\n 'has_extractions', true\n ),\n 'model', 'nvidia/nemotron-nano-9b-v2:free',\n 'duration_ms', $7::integer\n ),\n $8::uuid[]\n )\n RETURNING id\n)\nSELECT \n new_trace.id as trace_id,\n $8::uuid[] || new_trace.id as updated_trace_chain\nFROM new_trace;`,\n params: [\n ctx.event.event_id,\n ctx.db.thread_history,\n ctx.db.thread_id,\n promptText,\n llmOutput,\n parsedCtx.llm.extractions?.length || 0,\n durationMs,\n traceChainPg\n ]\n },\n {\n key: 'void_old',\n sql: `UPDATE projections SET status = 'voided', voided_at = NOW(), voided_reason = 'replaced_by_new_extraction' WHERE projection_type = 'thread_extraction' AND data->>'thread_id' = $1 AND status = 'pending';`,\n params: [ctx.db.thread_id]\n }\n ]\n }\n }\n};",
"mode": "runOnceForEachItem"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
-400,
544
],
"id": "prepare-trace-data-save-chat",
"name": "PrepareTraceData"
},
{
"parameters": {
"workflowId": {
"__rl": true,
"value": "CgUAxK0i4YhrZ2Wp",
"mode": "list",
"cachedResultName": "Execute_Queries",
"cachedResultUrl": "/workflow/CgUAxK0i4YhrZ2Wp"
},
"workflowInputs": {
"mappingMode": "defineBelow",
"value": {
"ctx": "={{ $json.ctx }}"
}
},
"options": {
"waitForSubWorkflow": true
}
},
"type": "n8n-nodes-base.executeWorkflow",
"typeVersion": 1.2,
"position": [
48,
448
],
"id": "write-thread-extraction-trace",
"name": "WriteThreadExtractionTrace"
},
{
"parameters": {
"jsCode": "// Build SQL query to insert extractions as projections\nconst ctx = $json.ctx;\nconst extractions = ctx.llm.extractions;\nconst extractionTraceId = ctx.db.trace.row.trace_id;\n\nif (!extractions || extractions.length === 0) {\n return [];\n}\n\n// Format trace_chain for PostgreSQL uuid[] type\nconst traceChain = ctx.event.trace_chain || [];\nconst updatedTraceChain = [...traceChain, extractionTraceId];\nconst traceChainPg = '{' + updatedTraceChain.join(',') + '}';\n\n// 7 parameters per row: event_id, trace_id, trace_chain, projection_type, data (jsonb), status, timezone\nconst values = extractions.map((ext, idx) => {\n const offset = idx * 7;\n return `($${offset + 1}::uuid, $${offset + 2}::uuid, $${offset + 3}::uuid[], $${offset + 4}, $${offset + 5}::jsonb, $${offset + 6}, $${offset + 7})`;\n}).join(', ');\n\nconst insertSql = `\nINSERT INTO projections (\n event_id,\n trace_id,\n trace_chain,\n projection_type,\n data,\n status,\n timezone\n)\nVALUES ${values}\nRETURNING *;\n`;\n\n// The params array matches the $1, $2, $3, $4, $5, $6, $7... sequence (7 per extraction)\nconst params = [];\nextractions.forEach(ext => {\n params.push(ctx.event.event_id); // event_id\n params.push(extractionTraceId); // trace_id\n params.push(traceChainPg); // trace_chain\n params.push('thread_extraction'); // projection_type\n params.push(JSON.stringify({ // data as JSONB\n thread_id: ext.thread_id,\n item_type: ext.item_type,\n text: ext.text,\n display_order: ext.display_order\n }));\n params.push('pending'); // status\n params.push(ctx.event.timezone || null); // timezone\n});\n\nreturn {\n json: {\n ctx: {\n ...ctx,\n db: {\n ...ctx.db,\n trace_id: extractionTraceId\n },\n db_queries: [{\n key: 'extractions',\n sql: insertSql,\n params: params\n }]\n }\n }\n};",
"mode": "runOnceForEachItem"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
272,
448
],
"id": "6f856663-e8d6-4f8c-9c9c-41a6eab0d27b",
"name": "BuildInsertQuery"
},
{
"parameters": {
"workflowId": {
"__rl": true,
"value": "CgUAxK0i4YhrZ2Wp",
"mode": "list",
"cachedResultName": "Execute_Queries",
"cachedResultUrl": "/workflow/CgUAxK0i4YhrZ2Wp"
},
"workflowInputs": {
"mappingMode": "defineBelow",
"value": {
"ctx": "={{ $json.ctx }}"
}
},
"options": {
"waitForSubWorkflow": true
}
},
"type": "n8n-nodes-base.executeWorkflow",
"typeVersion": 1.2,
"position": [
496,
448
],
"id": "48cebe42-d9c8-4de1-a10a-d1e09935ad25",
"name": "SaveExtractionsToDb"
},
{
"parameters": {
"jsCode": "// Build Discord summary message\nconst ctx = $json.ctx;\nconst extractions = ctx.llm.extractions;\n\nconst numberEmojis = ['1\ufe0f\u20e3', '2\ufe0f\u20e3', '3\ufe0f\u20e3', '4\ufe0f\u20e3', '5\ufe0f\u20e3', '6\ufe0f\u20e3', '7\ufe0f\u20e3', '8\ufe0f\u20e3', '9\ufe0f\u20e3', '\ud83d\udd1f'];\n\nconst notes = extractions.filter(e => \n e.item_type === 'reflection' || e.item_type === 'fact'\n);\nconst todos = extractions.filter(e => e.item_type === 'todo');\n\nlet content = '\ud83d\udcca **Thread Summary**\\n\\n';\n\nif (notes.length > 0) {\n content += '\ud83d\udca1 **Insights & Facts**\\n';\n notes.forEach(item => {\n const emoji = numberEmojis[item.display_order - 1] || '\u2022';\n content += `${emoji} ${item.text}\\n`;\n });\n content += '\\n';\n}\n\nif (todos.length > 0) {\n content += '\ud83d\udccb **Action Items**\\n';\n todos.forEach(item => {\n const emoji = numberEmojis[item.display_order - 1] || '\u2022';\n content += `${emoji} ${item.text}\\n`;\n });\n content += '\\n';\n}\n\ncontent += '---\\n';\ncontent += 'Tap number emoji to save\\n';\ncontent += '\u274c Dismiss \u2022 \ud83d\uddd1\ufe0f Delete thread';\n\nreturn {\n json: {\n ctx: {\n ...ctx,\n response: {\n summary_content: content,\n emoji_count: extractions.length\n }\n }\n }\n};",
"mode": "runOnceForEachItem"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
720,
448
],
"id": "8cfff2da-39dd-4c84-abab-f5a723655499",
"name": "BuildSummaryMessage"
},
{
"parameters": {
"jsCode": "// Get summary message ID from Discord response\nconst summaryMessage = $json;\nconst summaryMessageId = summaryMessage.id;\n\nconst ctx = $('BuildSummaryMessage').first().json.ctx;\nconst extractions = ctx.llm.extractions;\n\nconst numberEmojis = ['1\ufe0f\u20e3', '2\ufe0f\u20e3', '3\ufe0f\u20e3', '4\ufe0f\u20e3', '5\ufe0f\u20e3', '6\ufe0f\u20e3', '7\ufe0f\u20e3', '8\ufe0f\u20e3', '9\ufe0f\u20e3', '\ud83d\udd1f'];\n\n// Build emoji reaction URLs\nconst reactionUrls = [];\n\n// Add number emojis for each extraction\nextractions.forEach(ext => {\n const emoji = numberEmojis[ext.display_order - 1];\n if (emoji) {\n // URL encode the emoji\n const encoded = encodeURIComponent(emoji);\n reactionUrls.push({\n url: `https://discord.com/api/v10/channels/${ctx.event.channel_id}/messages/${summaryMessageId}/reactions/${encoded}/@me`,\n emoji: emoji\n });\n }\n});\n\n// Add control emojis\nreactionUrls.push(\n {\n url: `https://discord.com/api/v10/channels/${ctx.event.channel_id}/messages/${summaryMessageId}/reactions/%E2%9D%8C/@me`,\n emoji: '\u274c'\n },\n {\n url: `https://discord.com/api/v10/channels/${ctx.event.channel_id}/messages/${summaryMessageId}/reactions/%F0%9F%97%91%EF%B8%8F/@me`,\n emoji: '\ud83d\uddd1\ufe0f'\n }\n);\n\nreturn reactionUrls.map(r => ({\n json: {\n ctx: ctx,\n summary_message_id: summaryMessageId,\n reaction_url: r.url,\n emoji: r.emoji\n }\n}));",
"mode": "runOnceForEachItem"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1168,
448
],
"id": "d7ff0aa4-b3d1-42f5-a10d-37aad4ec2f56",
"name": "PrepareEmojiReactions"
},
{
"parameters": {
"method": "PUT",
"url": "={{ $json.reaction_url }}",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "discordBotApi",
"options": {}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1616,
448
],
"id": "124efe0a-5911-42ba-bd1f-4478da67fdff",
"name": "AddEmojiReactions",
"retryOnFail": true,
"maxTries": 3,
"waitBetweenTries": 1000,
"credentials": {
"discordBotApi": {
"name": "<your credential>"
}
},
"onError": "continueRegularOutput"
},
{
"parameters": {
"jsCode": "// Build query to update summary message ID on projections\nconst ctx = $('PrepareEmojiReactions').first().json.ctx;\nconst summaryMessageId = $('PrepareEmojiReactions').first().json.summary_message_id;\n\nreturn {\n json: {\n ctx: {\n ...ctx,\n db_queries: [{\n key: 'update_summary',\n sql: `UPDATE projections SET data = data || jsonb_build_object('summary_message_id', $1) WHERE projection_type = 'thread_extraction' AND data->>'thread_id' = $2 AND status = 'pending';`,\n params: [summaryMessageId, ctx.db.thread_id]\n }]\n }\n }\n};",
"mode": "runOnceForEachItem"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1616,
256
],
"id": "build-update-summary-query",
"name": "BuildUpdateSummaryQuery"
},
{
"parameters": {
"workflowId": {
"__rl": true,
"value": "CgUAxK0i4YhrZ2Wp",
"mode": "list",
"cachedResultName": "Execute_Queries",
"cachedResultUrl": "/workflow/CgUAxK0i4YhrZ2Wp"
},
"workflowInputs": {
"mappingMode": "defineBelow",
"value": {
"ctx": "={{ $json.ctx }}"
}
},
"options": {
"waitForSubWorkflow": true
}
},
"type": "n8n-nodes-base.executeWorkflow",
"typeVersion": 1.2,
"position": [
1840,
256
],
"id": "cc84e221-84fb-49bb-b72b-e0589a531893",
"name": "UpdateSummaryMessageId"
},
{
"parameters": {
"method": "DELETE",
"url": "=https://discord.com/api/v10/channels/{{ $('Build Summary Message').first().json.ctx.event.channel_id }}/messages/{{ $('Build Summary Message').first().json.ctx.event.message_id }}/reactions/\ud83d\udcad/@me",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "discordBotApi",
"options": {}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
-1872,
928
],
"id": "3a889796-3250-4fef-af78-7b779e545595",
"name": "Remove\ud83d\udcadReaction",
"retryOnFail": true,
"maxTries": 3,
"waitBetweenTries": 1000,
"credentials": {
"discordBotApi": {
"name": "<your credential>"
}
},
"onError": "continueRegularOutput"
},
{
"parameters": {
"resource": "message",
"guildId": {
"__rl": true,
"value": "={{ $json.ctx.event.guild_id }}",
"mode": "id"
},
"channelId": {
"__rl": true,
"value": "={{ $json.ctx.event.thread_id }}",
"mode": "id"
},
"content": "\u274c No items extracted from this thread. You must have had quite an interesting conversation.",
"options": {}
},
"type": "n8n-nodes-base.discord",
"typeVersion": 2,
"position": [
48,
640
],
"id": "db0c5fb7-27f3-460d-b931-d0610a934431",
"name": "PostNoExtractionsMessage",
"retryOnFail": true,
"maxTries": 3,
"waitBetweenTries": 1000,
"credentials": {
"discordBotApi": {
"name": "<your credential>"
}
},
"onError": "continueRegularOutput"
},
{
"parameters": {
"method": "DELETE",
"url": "=https://discord.com/api/v10/channels/{{ $json.ctx.event.channel_id }}/messages/{{ $json.ctx.event.message_id }}/reactions/\ud83d\udd35/@me",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "discordBotApi",
"options": {}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
-1872,
736
],
"id": "remove-blue-reaction-save-chat-no-extract",
"name": "Remove\ud83d\udd35Reaction(noExtract)",
"retryOnFail": true,
"maxTries": 3,
"waitBetweenTries": 1000,
"credentials": {
"discordBotApi": {
"name": "<your credential>"
}
},
"onError": "continueRegularOutput"
},
{
"parameters": {
"model": "nvidia/nemotron-nano-9b-v2:free",
"options": {
"timeout": 10000
}
},
"type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
"typeVersion": 1,
"position": [
-840,
768
],
"id": "1021e602-7ef3-4c22-bc16-74a99d6e8c30",
"name": "NemotronNano9b",
"credentials": {
"openRouterApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"model": "xiaomi/mimo-v2-flash:free",
"options": {
"timeout": 10000
}
},
"type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
"typeVersion": 1,
"position": [
-968,
768
],
"id": "aff3ef03-d804-40a6-98d9-b498298f4b69",
"name": "MimoV2Flash",
"credentials": {
"openRouterApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"resource": "message",
"operation": "react",
"guildId": {
"__rl": true,
"value": "={{ $json.ctx.event.guild_id }}",
"mode": "id"
},
"channelId": {
"__rl": true,
"value": "={{ $json.ctx.event.channel_id }}",
"mode": "id"
},
"messageId": "={{ $json.ctx.event.message_id }}",
"emoji": "\ud83d\udcad"
},
"type": "n8n-nodes-base.discord",
"typeVersion": 2,
"position": [
-1872,
352
],
"id": "ee2bc94f-b03b-4d5c-a04e-3e80e8e3acf1",
"name": "ReactWith\ud83d\udcad",
"retryOnFail": true,
"maxTries": 3,
"waitBetweenTries": 1000,
"credentials": {
"discordBotApi": {
"name": "<your credential>"
}
},
"onError": "continueRegularOutput"
},
{
"parameters": {
"resource": "message",
"guildId": {
"__rl": true,
"value": "={{ $json.ctx.event.guild_id }}",
"mode": "id"
},
"channelId": {
"__rl": true,
"value": "={{ $json.ctx.event.channel_id }}",
"mode": "id"
},
"content": "={{ $json.ctx.response.summary_content }}",
"options": {}
},
"type": "n8n-nodes-base.discord",
"typeVersion": 2,
"position": [
944,
448
],
"id": "59068362-0e97-4e90-90c3-98373b60e25f",
"name": "SendAMessage",
"retryOnFail": true,
"maxTries": 3,
"waitBetweenTries": 1000,
"credentials": {
"discordBotApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"options": {}
},
"type": "n8n-nodes-base.splitInBatches",
"typeVersion": 3,
"position": [
1392,
448
],
"id": "ebfeb17a-a211-4a67-adf9-ec9c26e418cc",
"name": "LoopOverItems"
},
{
"parameters": {
"amount": 1
},
"type": "n8n-nodes-base.wait",
"typeVersion": 1.1,
"position": [
1840,
520
],
"id": "9a504ad1-2ee7-435b-9c81-ff106ef75821",
"name": "Wait1S"
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "start-time",
"name": "ctx.timing.inference_start",
"value": "={{ Date.now() }}",
"type": "number"
}
]
},
"includeOtherFields": true,
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
-1200,
544
],
"id": "set-inference-start-save-chat",
"name": "SetInferenceStart"
}
],
"connections": {
"ExecuteWorkflowTrigger": {
"main": [
[
{
"node": "BuildThreadHistoryQuery",
"type": "main",
"index": 0
},
{
"node": "ReactWith\ud83d\udcad",
"type": "main",
"index": 0
},
{
"node": "Remove\ud83d\udcadReaction",
"type": "main",
"index": 0
},
{
"node": "Remove\ud83d\udd35Reaction(noExtract)",
"type": "main",
"index": 0
}
]
]
},
"BuildThreadHistoryQuery": {
"main": [
[
{
"node": "GetThreadHistory",
"type": "main",
"index": 0
}
]
]
},
"GetThreadHistory": {
"main": [
[
{
"node": "PrepareContext",
"type": "main",
"index": 0
}
]
]
},
"PrepareContext": {
"main": [
[
{
"node": "SetInferenceStart",
"type": "main",
"index": 0
}
]
]
},
"ExtractItemsLlm": {
"main": [
[
{
"node": "ParseExtractions",
"type": "main",
"index": 0
}
]
]
},
"ParseExtractions": {
"main": [
[
{
"node": "PrepareTraceData",
"type": "main",
"index": 0
}
]
]
},
"PrepareTraceData": {
"main": [
[
{
"node": "HasExtractions?",
"type": "main",
"index": 0
}
]
]
},
"HasExtractions?": {
"main": [
[
{
"node": "WriteThreadExtractionTrace",
"type": "main",
"index": 0
}
],
[
{
"node": "PostNoExtractionsMessage",
"type": "main",
"index": 0
}
]
]
},
"WriteThreadExtractionTrace": {
"main": [
[
{
"node": "BuildInsertQuery",
"type": "main",
"index": 0
}
]
]
},
"BuildInsertQuery": {
"main": [
[
{
"node": "SaveExtractionsToDb",
"type": "main",
"index": 0
}
]
]
},
"SaveExtractionsToDb": {
"main": [
[
{
"node": "BuildSummaryMessage",
"type": "main",
"index": 0
}
]
]
},
"BuildSummaryMessage": {
"main": [
[
{
"node": "SendAMessage",
"type": "main",
"index": 0
}
]
]
},
"PrepareEmojiReactions": {
"main": [
[
{
"node": "LoopOverItems",
"type": "main",
"index": 0
}
]
]
},
"AddEmojiReactions": {
"main": [
[
{
"node": "Wait1S",
"type": "main",
"index": 0
}
]
]
},
"UpdateSummaryMessageId": {
"main": [
[]
]
},
"Remove\ud83d\udcadReaction": {
"main": [
[]
]
},
"NemotronNano9b": {
"ai_languageModel": [
[
{
"node": "ExtractItemsLlm",
"type": "ai_languageModel",
"index": 1
}
]
]
},
"MimoV2Flash": {
"ai_languageModel": [
[
{
"node": "ExtractItemsLlm",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"ReactWith\ud83d\udcad": {
"main": [
[]
]
},
"SendAMessage": {
"main": [
[
{
"node": "PrepareEmojiReactions",
"type": "main",
"index": 0
}
]
]
},
"LoopOverItems": {
"main": [
[
{
"node": "BuildUpdateSummaryQuery",
"type": "main",
"index": 0
}
],
[
{
"node": "AddEmojiReactions",
"type": "main",
"index": 0
}
]
]
},
"BuildUpdateSummaryQuery": {
"main": [
[
{
"node": "UpdateSummaryMessageId",
"type": "main",
"index": 0
}
]
]
},
"Wait1S": {
"main": [
[
{
"node": "LoopOverItems",
"type": "main",
"index": 0
}
]
]
},
"SetInferenceStart": {
"main": [
[
{
"node": "ExtractItemsLlm",
"type": "main",
"index": 0
}
]
]
},
"PostNoExtractionsMessage": {
"main": [
[]
]
}
},
"settings": {
"callerPolicy": "workflowsFromSameOwner",
"errorWorkflow": "NOJ7FqVhVLqw0n8D",
"availableInMCP": false,
"executionOrder": "v1"
},
"staticData": null,
"meta": null,
"versionId": "18b4123d-c4d3-481a-a667-3a5ba97d7f32",
"activeVersionId": null,
"versionCounter": 185,
"triggerCount": 0,
"shared": [
{
"updatedAt": "2025-12-23T09:30:25.218Z",
"createdAt": "2025-12-23T09:30:25.218Z",
"role": "workflow:owner",
"workflowId": "yj2EUpsI7s3mLlRH",
"projectId": "erM3nntdLL53noWi",
"project": {
"updatedAt": "2025-12-23T09:23:39.658Z",
"createdAt": "2025-12-23T09:16:56.460Z",
"id": "erM3nntdLL53noWi",
"name": "Chris Irineo <chriskevini@gmail.com>",
"type": "personal",
"icon": null,
"description": null,
"projectRelations": [
{
"updatedAt": "2025-12-23T09:16:56.460Z",
"createdAt": "2025-12-23T09:16:56.460Z",
"userId": "2a851a2d-b7e5-4b3c-aefb-6eaaa79e0659",
"projectId": "erM3nntdLL53noWi",
"user": {
"updatedAt": "2025-12-24T08:40:46.063Z",
"createdAt": "2025-12-23T09:16:54.881Z",
"id": "2a851a2d-b7e5-4b3c-aefb-6eaaa79e0659",
"email": "chriskevini@gmail.com",
"firstName": "Chris",
"lastName": "Irineo",
"personalizationAnswers": {
"version": "v4",
"personalization_survey_submitted_at": "2025-12-23T09:23:43.723Z",
"personalization_survey_n8n_version": "1.123.5"
},
"settings": {
"userActivated": true,
"firstSuccessfulWorkflowId": "CgUAxK0i4YhrZ2Wp",
"userActivatedAt": 1766487000077,
"easyAIWorkflowOnboarded": true
},
"disabled": false,
"mfaEnabled": false,
"lastActiveAt": "2025-12-24",
"isPending": false
}
}
]
}
}
],
"tags": [],
"activeVersion": null
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
discordBotApiopenRouterApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Capture_Thread. Uses executeWorkflowTrigger, chainLlm, httpRequest, discord. Event-driven trigger; 26 nodes.
Source: https://github.com/chriskevini/kairon/blob/ab924f228ceb22522b9a4dfa1ab4589eb86273ad/n8n-workflows/Capture_Thread.json — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
Capture_Projection. Uses executeWorkflowTrigger, httpRequest, chainLlm, lmChatOpenRouter. Event-driven trigger; 18 nodes.
Continue_Thread. Uses executeWorkflowTrigger, chainLlm, lmChatOpenRouter, discord. Event-driven trigger; 14 nodes.
This workflow is designed for n8n users who manage multiple production workflows and want to: Receive intelligent, actionable error alerts instead of raw stack traces Understand root causes without ma
End-to-End Video Creation from user idea or transcript AI-Powered Scriptwriting using LLMs (e.g., DeepSeek via OpenRouter) Voiceover Generation with customizable TTS voices Image Scene Generation usin
This comprehensive N8N automation template revolutionizes content creation by delivering a complete end-to-end solution for AI-powered blog generation. Transform simple ideas into fully SEO-optimized,