This workflow corresponds to n8n.io template #8354 — we link there as the canonical source.
This workflow follows the Chainllm → Slack 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 →
{
"id": "7oFFGgWK8j6WPZQS",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Tasks Briefing",
"tags": [],
"nodes": [
{
"id": "3ffa1295-e39b-4610-9f65-3512e48e04a4",
"name": "Code (Build LLM Prompt)",
"type": "n8n-nodes-base.code",
"position": [
720,
432
],
"parameters": {
"jsCode": "/* Build a single prompt for the LLM to produce a Slack-ready brief.\n * No tool calls\u2014just return concise Markdown text.\n */\nconst tasks = $input.all().map(i => i.json);\n\nconst compact = tasks.map(t => ({\n title: t.title || '(untitled)',\n notes: t.notes || '',\n due: t.due || t.updated || '',\n webViewLink: t.webViewLink || '',\n links: (t.links || []).map(l => `${l.type || 'link'}: ${l.link || ''}`),\n parent: t.parent || null,\n}));\n\nconst instructions = `You are an executive assistant. Create a concise Slack-ready morning brief for Google Tasks due TODAY.\nRequirements:\n- Start with a one-sentence overview (calm, actionable).\n- Then bullets: **Title** \u2014 1-sentence goal; 1\u20132 next steps; default owner \"Me\"; ETA (morning/afternoon/evening).\n- If notes contain a URL or webViewLink exists, show one key link inline.\n- Group obvious subtasks under a parent with indentation.\n- Keep it under ~120 words. No fluff.\n- Output plain Markdown suitable for Slack.`;\n\nconst context = `DATA (JSON):\\n${JSON.stringify(compact, null, 2)}`;\n\nreturn [{ json: { input: `${instructions}\\n\\n${context}` } }];\n"
},
"typeVersion": 2
},
{
"id": "482aa3f0-0adc-41ad-8109-35e5c44be974",
"name": "Get many tasks",
"type": "n8n-nodes-base.googleTasks",
"position": [
-176,
672
],
"parameters": {
"task": "MTQzNzI1NzAyOTQxNTk3NzM5NDc6MDow",
"operation": "getAll",
"returnAll": true,
"additionalFields": {}
},
"credentials": {
"googleTasksOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "5f38a733-4ea4-48a5-9d51-a310b20a2399",
"name": "If",
"type": "n8n-nodes-base.if",
"position": [
256,
672
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "f0f18c51-df5b-432f-ab71-b8fa036b4b97",
"operator": {
"type": "string",
"operation": "notEquals"
},
"leftValue": "={{ $json.__empty }}",
"rightValue": "empty"
}
]
}
},
"typeVersion": 2
},
{
"id": "0b43a198-7f5b-4832-961c-b141f098382d",
"name": "Basic LLM Chain1",
"type": "@n8n/n8n-nodes-langchain.chainLlm",
"position": [
928,
432
],
"parameters": {
"text": "={{ $json.input }}",
"batching": {},
"promptType": "define"
},
"typeVersion": 1.7
},
{
"id": "9e33de10-085c-4658-9bc2-cff7aa5d0a5d",
"name": "Ollama Model1",
"type": "@n8n/n8n-nodes-langchain.lmOllama",
"position": [
736,
672
],
"parameters": {
"model": "qwen3:4b",
"options": {}
},
"credentials": {
"ollamaApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "c8f712cd-3810-4bf1-98cb-8deba4dee8b7",
"name": "Send a message1",
"type": "n8n-nodes-base.slack",
"position": [
1344,
656
],
"parameters": {
"text": "={{ $json.cleanText }}",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "name",
"value": "REPLACE_WITH_SLACK_CHANNEL_NAME"
},
"otherOptions": {}
},
"credentials": {
"slackApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.3
},
{
"id": "82d65a9d-f437-4739-aa71-df8c25f0a930",
"name": "Code",
"type": "n8n-nodes-base.code",
"position": [
992,
656
],
"parameters": {
"jsCode": "// Remove <think>...</think> blocks from the LLM output\nlet text = $json.text || \"\";\n\ntext = text.replace(/<think>[\\s\\S]*?<\\/think>/gi, \"\").trim();\n\nreturn [{ json: { cleanText: text } }];\n"
},
"typeVersion": 2
},
{
"id": "fb99dd91-1b64-4ef5-9c1c-1ec840a732e1",
"name": "Code (Filter Due Today)",
"type": "n8n-nodes-base.code",
"position": [
64,
672
],
"parameters": {
"jsCode": "/* Filter Google Tasks that are due TODAY in Asia/Dhaka.\n * Emits N items (one per task) when there are tasks due today.\n * Emits a single item { __empty: true } when none.\n */\nconst TZ = 'Asia/Dhaka';\nconst toTZ = (d) => new Date(d.toLocaleString('en-US', { timeZone: TZ }));\nconst now = new Date();\nconst start = toTZ(new Date(now.getFullYear(), now.getMonth(), now.getDate()));\nconst end = toTZ(new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1));\nfunction isDueToday(dueRaw) {\n if (!dueRaw) return false;\n const iso = dueRaw.length === 10 ? `${dueRaw}T00:00:00Z` : dueRaw;\n const d = toTZ(new Date(iso));\n return d >= start && d < end;\n}\nconst dueToday = [];\nfor (const item of $input.all()) {\n const t = item.json || {};\n const status = (t.status || '').toLowerCase();\n if (status === 'completed' || status === 'hidden' || status === 'deleted') continue;\n if (isDueToday(t.due || '')) {\n dueToday.push({ json: t });\n }\n}\nif (dueToday.length === 0) {\n return [{ json: { __empty: \"empty\" } }];\n}\nreturn dueToday;"
},
"typeVersion": 2
},
{
"id": "aaccef83-3d04-4d61-ab2d-3177003e85cf",
"name": "Slack1",
"type": "n8n-nodes-base.slack",
"position": [
464,
688
],
"parameters": {
"text": "\ud83c\udf24\ufe0f No Google Tasks due today. I\u2019ll check again tomorrow ",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "name",
"value": "REPLACE_WITH_SLACK_CHANNEL_NAME"
},
"otherOptions": {}
},
"credentials": {
"slackApi": {
"name": "<your credential>"
}
},
"typeVersion": 2
},
{
"id": "567f37f5-2267-4576-ba02-1385fe9ad4a4",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-320,
336
],
"parameters": {
"color": 7,
"width": 304,
"height": 512,
"content": "## Scheduled Trigger\nEvery Morning at 7 AM Fetch all the tasks"
},
"typeVersion": 1
},
{
"id": "a7560047-6b24-46ae-a7cf-4315b32d19fe",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
16,
560
],
"parameters": {
"color": 7,
"width": 576,
"height": 288,
"content": "## Filter Tasks\nSend tasks due today to LLM or notify user that there are no tasks scheduled today"
},
"typeVersion": 1
},
{
"id": "f10cdca4-b703-4606-812c-8e2a823779dc",
"name": "Trigger at Morning",
"type": "n8n-nodes-base.cron",
"position": [
-224,
448
],
"parameters": {
"triggerTimes": {
"item": [
{
"hour": 7
}
]
}
},
"typeVersion": 1
},
{
"id": "ad6b3cde-4e0b-44d4-aca5-03b51356a3da",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
624,
336
],
"parameters": {
"color": 7,
"width": 608,
"height": 512,
"content": "## Process Tasks Briefing\nProduce a solid briefing for the user with LLM and clean the output removing the Think tags"
},
"typeVersion": 1
},
{
"id": "6d980e56-2085-4ddb-bce6-f2d1601c0446",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
1264,
560
],
"parameters": {
"color": 7,
"width": 320,
"height": 288,
"content": "## Notify in Slack\nSend the task briefing as a slack message"
},
"typeVersion": 1
},
{
"id": "ddedc07a-1434-45f9-acf8-b1c8d41ef3e1",
"name": "Sticky Note7",
"type": "n8n-nodes-base.stickyNote",
"position": [
-896,
-384
],
"parameters": {
"width": 512,
"height": 2016,
"content": "## Tasks Briefing\n\nThis template posts a clean, Slack-ready **morning summary of your Google Tasks due today**. It fetches tasks, filters only those due \u201ctoday\u201d in your timezone, asks a local **LLM (via LangChain + Ollama)** to produce a short summary (no steps, just a concise brief), strips any hidden `<think>` blocks, and delivers the message to your chosen Slack channel.\n\n## How it works\n\n1. **Trigger at Morning (Cron)** \u2013 runs at **7:00 AM** (you can change the hour) to kick things off daily.\n2. **Get many tasks (Google Tasks node)** \u2013 pulls tasks from your selected Google Tasklist.\n3. **Code (Filter Due Today)** \u2013 normalizes dates to your timezone, keeps only tasks due today, and emits a fallback flag if none exist.\n4. **If** \u2013 routes:\n\n * **True (has tasks)** \u2192 continues to the LLM summary path.\n * **False (no tasks)** \u2192 sends a \u201cNo tasks due today\u201d message to Slack.\n5. **Code (Build LLM Prompt)** \u2013 builds a compact, Markdown-only prompt for the model (no tool calls).\n6. **Basic LLM Chain (LangChain)** + **Ollama Model** \u2013 generates a short summary for Slack.\n7. **Code (Cleanup)** \u2013 removes any `<think>\u2026</think>` content if the model includes it.\n8. **Send a message (Slack)** \u2013 posts the final brief to your Slack channel.\n\n## Required credentials\n\n* **Google Tasks OAuth2 API** \u2013 to read tasks from your Google Tasklist.\n* **Slack API** \u2013 to post the summary into a channel.\n* **Ollama** \u2013 local model endpoint (e.g., `qwen3:4b`); used by the LangChain LLM nodes.\n\n## Setup Instructions\n\n1. **Google Tasks credential**\n\n * In Google Cloud Console: enable **Google Tasks API**, create an **OAuth Client (Web)**, and set the redirect URI shown by n8n.\n * In n8n **Credentials**, add **Google Tasks OAuth2 API** with scope:\n\n * `https://www.googleapis.com/auth/tasks` (read/write) or\n * `https://www.googleapis.com/auth/tasks.readonly` (read-only).\n * In the **Get many tasks** node, select your credential and your **Tasklist**.\n\n2. **Slack credential & channel**\n\n * In n8n **Credentials**, add **Slack API** (bot/user token with `chat:write`).\n * In **Send a message** nodes, select your Slack credential and set the **Channel** (e.g., `#new-leads`).\n\n3. **Ollama model (LangChain)**\n\n * Ensure **Ollama** is running on your host (default `http://localhost:11434`).\n * Pull a model (e.g., `ollama pull qwen3:4b`) or use another supported model (`llama3:8b`, etc.).\n * In **Ollama Model** node, select your **Ollama** credential and set the **model** name to match what you pulled.\n\n4. **Timezone & schedule**\n\n * The **Cron** node is set to **7:00 AM**. Adjust as needed.\n * The **Code (Filter Due Today)** node is configured for **Asia/Dhaka**; change the `TZ` constant if you prefer a different timezone.\n\n5. **(Optional) Cleanup safety**\n\n * The template includes a **Code (Cleanup)** node that strips `<think>\u2026</think>` blocks from model output. Keep this connected before the Slack node.\n\n6. **Test the flow**\n\n * Run the workflow once manually:\n\n * If you have tasks due today, you should see a concise summary posted to your Slack channel.\n * If none are due, you\u2019ll receive a friendly \u201cNo tasks due today\u201d message.\n\n7. **Activate**\n\n * When everything looks good, toggle the workflow **Active** to receive the daily summary automatically.\n\n"
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "86f277b0-90ef-4463-b819-7205a795c460",
"connections": {
"If": {
"main": [
[
{
"node": "Code (Build LLM Prompt)",
"type": "main",
"index": 0
}
],
[
{
"node": "Slack1",
"type": "main",
"index": 0
}
]
]
},
"Code": {
"main": [
[
{
"node": "Send a message1",
"type": "main",
"index": 0
}
]
]
},
"Ollama Model1": {
"ai_languageModel": [
[
{
"node": "Basic LLM Chain1",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Get many tasks": {
"main": [
[
{
"node": "Code (Filter Due Today)",
"type": "main",
"index": 0
}
]
]
},
"Basic LLM Chain1": {
"main": [
[
{
"node": "Code",
"type": "main",
"index": 0
}
]
]
},
"Trigger at Morning": {
"main": [
[
{
"node": "Get many tasks",
"type": "main",
"index": 0
}
]
]
},
"Code (Build LLM Prompt)": {
"main": [
[
{
"node": "Basic LLM Chain1",
"type": "main",
"index": 0
}
]
]
},
"Code (Filter Due Today)": {
"main": [
[
{
"node": "If",
"type": "main",
"index": 0
}
]
]
}
}
}
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.
googleTasksOAuth2ApiollamaApislackApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This template posts a clean, Slack-ready morning summary of your Google Tasks due today. It fetches tasks, filters only those due “today” in your timezone, asks a local LLM (via LangChain + Ollama) to produce a short summary (no steps, just a concise brief), strips any hidden…
Source: https://n8n.io/workflows/8354/ — 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.
This n8n-powered workflow automates the entire lifecycle of real estate lead intake, qualification, routing, assignment, and reporting across multiple channels. It brings WhatsApp inquiries and websit
This workflow empowers app developers and community management teams by automating the generation and posting of responses to user reviews on the Apple App Store. Designed to streamline the engagement
The Recap AI - Short Form News Script Generator. Uses httpRequest, s3, chainLlm, slack. Scheduled trigger; 42 nodes.
This workflow is the AI analysis and alerting engine for a complete social media monitoring system. It's designed to work with data scraped from X (formerly Twitter) using a tool like the Apify Tweet
Categories Content Creation AI Automation Publishing Social Media