AutomationFlowsAI & RAG › Schedule Weekly Focus-time Blocks with Google Calendar, Openai, and Slack

Schedule Weekly Focus-time Blocks with Google Calendar, Openai, and Slack

Bykenta @kii on n8n.io

This workflow runs every Sunday at 18:00 to scan your Google Calendar for next week, find free gaps of at least two hours within your working hours, auto-book them as “🧘 Focus Time” events, and then DM you a personalized deep-work plan in Slack using OpenAI. Runs every Sunday at…

Cron / scheduled trigger★★★★☆ complexityAI-powered16 nodesGoogle CalendarChain LlmOpenAI ChatSlack
AI & RAG Trigger: Cron / scheduled Nodes: 16 Complexity: ★★★★☆ AI nodes: yes Added:

This workflow corresponds to n8n.io template #17074 — we link there as the canonical source.

This workflow follows the Chainllm → OpenAI Chat 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": "YOeDNnjmjtyThben",
  "name": "Focus Time Defender \u2014 Auto-Block Deep Work Slots In Next Week's Calendar (Google Calendar \u2192 Slack)",
  "tags": [],
  "nodes": [
    {
      "id": "84f08fd6-b515-4b60-a824-5fa942563dd9",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -608,
        -96
      ],
      "parameters": {
        "width": 480,
        "height": 620,
        "content": "## \ud83e\uddd8 Focus Time Defender\n\nEvery Sunday evening this workflow scans **next week's calendar**, finds the free gaps of 2+ hours inside your working hours, and books them as **\ud83e\uddd8 Focus Time** events before meetings can eat them. You get a Slack DM with your personal deep-work plan \u2014 or a warning if your week is already too fragmented.\n\n### \ud83d\udd27 Setup\n1. Connect **Google Calendar**, **OpenAI** and **Slack** credentials.\n2. Tune **\u2699\ufe0f My Preferences**: working hours, minimum block length, max blocks per week.\n3. Set your Slack handle in both Slack nodes.\n4. Activate \u2014 runs every **Sunday at 18:00**.\n\n### \ud83d\udca1 Why it's useful\n\"I'll find time for deep work\" never survives contact with other people's calendars. Booking the slots first reverses the default."
      },
      "typeVersion": 1
    },
    {
      "id": "97624354-0dbb-4c28-aad7-56eb5d872932",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        368,
        80
      ],
      "parameters": {
        "color": 4,
        "width": 700,
        "height": 420,
        "content": "### 1\ufe0f\u20e3 Map next week\nLoad all events for the coming week and compute every free gap inside working hours (weekdays only)."
      },
      "typeVersion": 1
    },
    {
      "id": "5664b582-910a-4cc0-954e-bfac44d5f2a6",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1104,
        80
      ],
      "parameters": {
        "color": 5,
        "width": 660,
        "height": 560,
        "content": "### 2\ufe0f\u20e3 Claim the gaps\nIf usable gaps exist, book the best ones as \ud83e\uddd8 Focus Time events. If not, skip straight to the fragmentation warning."
      },
      "typeVersion": 1
    },
    {
      "id": "f11518be-c644-48fb-835e-e041a0b9db93",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1792,
        80
      ],
      "parameters": {
        "color": 6,
        "width": 656,
        "height": 516,
        "content": "### 3\ufe0f\u20e3 Your deep-work plan\nThe LLM writes a short personal plan suggesting what kind of work fits each protected block."
      },
      "typeVersion": 1
    },
    {
      "id": "5a9031e8-97ec-4a55-83a3-10c4cc314205",
      "name": "Every Sunday 18:00",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -64,
        336
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "weeks",
              "triggerAtHour": 18
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "5f0a20d0-8f67-4896-b30b-6b24bdfcaef1",
      "name": "\u2699\ufe0f My Preferences",
      "type": "n8n-nodes-base.set",
      "position": [
        144,
        336
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "pref-1",
              "name": "workStartHour",
              "type": "number",
              "value": 9
            },
            {
              "id": "pref-2",
              "name": "workEndHour",
              "type": "number",
              "value": 18
            },
            {
              "id": "pref-3",
              "name": "minBlockHours",
              "type": "number",
              "value": 2
            },
            {
              "id": "pref-4",
              "name": "maxBlocksPerWeek",
              "type": "number",
              "value": 5
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "f8bd3aeb-7e2b-4c64-b5d0-6143cc50afd7",
      "name": "Get Next Week's Events",
      "type": "n8n-nodes-base.googleCalendar",
      "position": [
        432,
        336
      ],
      "parameters": {
        "options": {},
        "calendar": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "operation": "getAll",
        "returnAll": true
      },
      "typeVersion": 1.3
    },
    {
      "id": "e6f5df43-ef4a-4609-b833-50ab1f783a74",
      "name": "Find Free Gaps",
      "type": "n8n-nodes-base.code",
      "position": [
        672,
        336
      ],
      "parameters": {
        "jsCode": "// Find free gaps of at least `minBlockHours` inside working hours, Monday\u2013Friday\nconst prefs = $('\u2699\ufe0f My Preferences').first().json;\nconst events = $input.all()\n  .map(i => i.json)\n  .filter(e => e.start?.dateTime && e.status !== 'cancelled')\n  .map(e => ({ start: new Date(e.start.dateTime), end: new Date(e.end.dateTime) }))\n  .sort((a, b) => a.start - b.start);\n\nconst gaps = [];\nconst now = new Date();\n\nfor (let d = 1; d <= 6; d++) {\n  const day = new Date(now);\n  day.setDate(now.getDate() + d);\n  const dow = day.getDay();\n  if (dow === 0 || dow === 6) continue; // weekdays only\n\n  const dayStart = new Date(day); dayStart.setHours(prefs.workStartHour, 0, 0, 0);\n  const dayEnd = new Date(day); dayEnd.setHours(prefs.workEndHour, 0, 0, 0);\n\n  const dayEvents = events.filter(e => e.start < dayEnd && e.end > dayStart);\n  let cursor = dayStart;\n\n  for (const e of [...dayEvents, { start: dayEnd, end: dayEnd }]) {\n    const gapHours = (e.start - cursor) / 36e5;\n    if (gapHours >= prefs.minBlockHours) {\n      gaps.push({\n        found: true,\n        start: cursor.toISOString(),\n        end: new Date(Math.min(e.start, cursor.getTime() + 3 * 36e5)).toISOString(),\n        durationHours: Number(Math.min(gapHours, 3).toFixed(1)),\n        weekday: day.toLocaleDateString('en-US', { weekday: 'long' })\n      });\n    }\n    if (e.end > cursor) cursor = e.end;\n  }\n}\n\nif (gaps.length === 0) {\n  return [{ json: { found: false } }];\n}\n\nreturn gaps.map(g => ({ json: g }));"
      },
      "typeVersion": 2
    },
    {
      "id": "7075c982-4012-4c21-ba50-49918598fbd7",
      "name": "Any Focus Slots?",
      "type": "n8n-nodes-base.if",
      "position": [
        912,
        336
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "if-1",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $json.found }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "26861c03-7c3e-490d-b851-6086e49cdd68",
      "name": "Cap Blocks Per Week",
      "type": "n8n-nodes-base.limit",
      "position": [
        1168,
        240
      ],
      "parameters": {
        "maxItems": "={{ $('\u2699\ufe0f My Preferences').first().json.maxBlocksPerWeek }}"
      },
      "typeVersion": 1
    },
    {
      "id": "1eea4e63-ad54-49ff-9c7a-790517f3441b",
      "name": "Book Focus Block",
      "type": "n8n-nodes-base.googleCalendar",
      "position": [
        1392,
        240
      ],
      "parameters": {
        "end": "={{ $json.end }}",
        "start": "={{ $json.start }}",
        "calendar": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "additionalFields": {
          "color": "9",
          "summary": "\ud83e\uddd8 Focus Time (protected by n8n)",
          "description": "Deep work block booked automatically by the Focus Time Defender workflow. Decline meeting invites that collide with this!"
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "1bc68df0-ec22-4f91-abf0-2cdba175ec4c",
      "name": "Bundle Booked Blocks",
      "type": "n8n-nodes-base.aggregate",
      "position": [
        1616,
        240
      ],
      "parameters": {
        "options": {},
        "aggregate": "aggregateAllItemData",
        "destinationFieldName": "blocks"
      },
      "typeVersion": 1
    },
    {
      "id": "58f4b712-4810-4c19-9bba-04705310eec7",
      "name": "Write My Focus Plan",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "position": [
        1856,
        240
      ],
      "parameters": {
        "text": "=I just protected these deep-work blocks in my calendar for next week:\n\n{{ JSON.stringify($('Cap Blocks Per Week').all().map(i => i.json), null, 2) }}\n\nWrite me a short, motivating Slack message (max 180 words):\n1. List each block (weekday + time range, human-readable)\n2. Suggest what type of work fits each slot (long blocks \u2192 hard creative work, shorter \u2192 reviews/writing)\n3. One practical tip to actually defend these blocks from meeting requests\n\nUse Slack formatting and keep it personal \u2014 this goes to one person, not a team.",
        "messages": {
          "messageValues": [
            {
              "message": "You are a supportive productivity coach who specializes in deep work."
            }
          ]
        },
        "promptType": "define"
      },
      "typeVersion": 1.5
    },
    {
      "id": "f1c908d3-c4c6-4e31-8e9e-89d1ef16d5a9",
      "name": "OpenAI Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        1856,
        432
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4o-mini"
        },
        "options": {}
      },
      "typeVersion": 1.2
    },
    {
      "id": "26318297-4714-4f8e-a74b-2c4b70d72cc6",
      "name": "DM My Focus Plan",
      "type": "n8n-nodes-base.slack",
      "position": [
        2208,
        240
      ],
      "parameters": {
        "text": "=\ud83e\uddd8 *Your deep-work plan for next week*\n\n{{ $json.text }}",
        "user": {
          "__rl": true,
          "mode": "username",
          "value": "your-slack-handle"
        },
        "select": "user",
        "otherOptions": {}
      },
      "typeVersion": 2.3
    },
    {
      "id": "9ec01fe1-a6be-4ff9-8836-44c101506c05",
      "name": "Warn: Week Too Fragmented",
      "type": "n8n-nodes-base.slack",
      "position": [
        1168,
        448
      ],
      "parameters": {
        "text": "\u26a0\ufe0f *Focus Time Defender*: I couldn't find a single free 2-hour slot in your working hours next week. Your calendar is fully fragmented \u2014 consider declining or shortening some meetings, then re-run me.",
        "user": {
          "__rl": true,
          "mode": "username",
          "value": "your-slack-handle"
        },
        "select": "user",
        "otherOptions": {}
      },
      "typeVersion": 2.3
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "8a4640bd-c675-4c80-b893-175b74e51e83",
  "nodeGroups": [],
  "connections": {
    "Find Free Gaps": {
      "main": [
        [
          {
            "node": "Any Focus Slots?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Any Focus Slots?": {
      "main": [
        [
          {
            "node": "Cap Blocks Per Week",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Warn: Week Too Fragmented",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Book Focus Block": {
      "main": [
        [
          {
            "node": "Bundle Booked Blocks",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Write My Focus Plan",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Every Sunday 18:00": {
      "main": [
        [
          {
            "node": "\u2699\ufe0f My Preferences",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Cap Blocks Per Week": {
      "main": [
        [
          {
            "node": "Book Focus Block",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Write My Focus Plan": {
      "main": [
        [
          {
            "node": "DM My Focus Plan",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Bundle Booked Blocks": {
      "main": [
        [
          {
            "node": "Write My Focus Plan",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\u2699\ufe0f My Preferences": {
      "main": [
        [
          {
            "node": "Get Next Week's Events",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Next Week's Events": {
      "main": [
        [
          {
            "node": "Find Free Gaps",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Pro

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

About this workflow

This workflow runs every Sunday at 18:00 to scan your Google Calendar for next week, find free gaps of at least two hours within your working hours, auto-book them as “🧘 Focus Time” events, and then DM you a personalized deep-work plan in Slack using OpenAI. Runs every Sunday at…

Source: https://n8n.io/workflows/17074/ — 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 workflow builds an AI meeting assistant who sends information-dense pre-meeting notifications for a user's upcoming meetings. A scheduled trigger fires hourly and checks for upcoming meetings wit

Gmail, Google Calendar, Information Extractor +3
AI & RAG

This workflow accepts a URL via an n8n form, fetches and extracts the main text from the web page, uses OpenAI (GPT-4o) to generate a structured research card (summary, tags, quotes, actions, sentimen

Google Calendar, Chain Llm, OpenAI Chat +3
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

My workflow 14. Uses rssFeedRead, chainLlm, lmChatOpenAi, openWeatherMap. Scheduled trigger; 40 nodes.

RSS Feed Read, Chain Llm, OpenAI Chat +6
AI & RAG

This workflow is designed for Japanese-speaking professionals, and learners who want to efficiently stay up to date with practical productivity, lifehack, and efficiency-related insights from Japanese

RSS Feed Read, Chain Llm, Google Gemini Chat +7