AutomationFlowsAI & RAG › Daily Google Tasks Briefing in Slack with Ollama-powered Summaries

Daily Google Tasks Briefing in Slack with Ollama-powered Summaries

ByAxiomlab.dev @axiomlab on n8n.io

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…

Cron / scheduled trigger★★★★☆ complexityAI-powered15 nodesGoogle TasksChain LlmLm OllamaSlack
AI & RAG Trigger: Cron / scheduled Nodes: 15 Complexity: ★★★★☆ AI nodes: yes Added:

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 →

Download .json
{
  "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.

Pro

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 →

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

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

Gmail, Typeform Trigger, WhatsApp Trigger +8
AI & RAG

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

Jwt, HTTP Request, Slack +5
AI & RAG

The Recap AI - Short Form News Script Generator. Uses httpRequest, s3, chainLlm, slack. Scheduled trigger; 42 nodes.

HTTP Request, S3, Chain Llm +3
AI & RAG

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

Google Sheets, Google Gemini Chat, Google Sheets Tool +4
AI & RAG

Categories Content Creation AI Automation Publishing Social Media

Google Docs, HTTP Request, Slack +7