This workflow corresponds to n8n.io template #skynetlabs-15 — we link there as the canonical source.
This workflow follows the Google Sheets → 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 →
{
"name": "15 - Async Standup Bot",
"nodes": [
{
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "30 9 * * 1-5"
}
]
}
},
"id": "trigger-cron",
"name": "Weekdays 9:30",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.1,
"position": [
200,
300
]
},
{
"parameters": {
"operation": "read",
"documentId": {
"__rl": true,
"value": "REPLACE_ME_ROSTER_SHEET_ID",
"mode": "id"
},
"sheetName": {
"__rl": true,
"value": "roster",
"mode": "name"
},
"options": {}
},
"id": "read-roster",
"name": "Read team roster",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4.5,
"position": [
420,
300
],
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"jsCode": "const rows = $input.all().map(i => i.json).filter(r => String(r.active).toLowerCase() === 'true' || r.active === true);\nreturn rows.map(r => ({ json: r }));"
},
"id": "filter-active",
"name": "Filter active members",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
640,
300
]
},
{
"parameters": {
"select": "user",
"user": {
"__rl": true,
"value": "={{ $json.slack_user_id }}",
"mode": "id"
},
"text": "=Morning {{ $json.name }} :sun_with_face:\n\nQuick async standup. Reply in this DM, or use /standup-skip if OOO.\n\n1) What did you ship yesterday?\n2) What's the plan today?\n3) Anything blocking you?\n\nI'll roll everyone's answers into #standup at 10:15.",
"otherOptions": {}
},
"id": "slack-dm",
"name": "DM each member",
"type": "n8n-nodes-base.slack",
"typeVersion": 2.2,
"position": [
860,
300
],
"credentials": {
"slackApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"amount": 45,
"unit": "minutes"
},
"id": "wait-45",
"name": "Wait 45 min",
"type": "n8n-nodes-base.wait",
"typeVersion": 1.1,
"position": [
1080,
300
]
},
{
"parameters": {
"jsCode": "const since = Math.floor((Date.now() - 60 * 60 * 1000) / 1000);\nreturn [{ json: { oldest: since } }];"
},
"id": "build-window",
"name": "Build time window",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1300,
300
]
},
{
"parameters": {
"resource": "message",
"operation": "getAll",
"channel": {
"__rl": true,
"value": "={{ $('Filter active members').first().json.slack_user_id }}",
"mode": "id"
},
"returnAll": false,
"limit": 30,
"filters": {
"oldest": "={{ $json.oldest }}"
}
},
"id": "read-dms",
"name": "Read each DM thread",
"type": "n8n-nodes-base.slack",
"typeVersion": 2.2,
"position": [
1520,
300
],
"credentials": {
"slackApi": {
"name": "<your credential>"
}
},
"continueOnFail": true
},
{
"parameters": {
"modelId": {
"__rl": true,
"value": "claude-sonnet-4-6",
"mode": "list"
},
"messages": {
"values": [
{
"content": "=You summarise async standup replies into one clean Slack post. Use Slack mrkdwn.\n\nTeam replies (mixed across people):\n{{ JSON.stringify($json) }}\n\nReturn ONLY valid JSON:\n{\n \"summary_md\": \"the full Slack post body\",\n \"blockers\": [\"name: blocker text\", \"...\"],\n \"missing\": [\"names that did not reply\"]\n}\n\nFormat for summary_md:\n*:wave: Async standup \u2014 {{ $now.format('EEE dd MMM') }}*\n\nThen one block per person:\n*Name*\n\u2022 Yesterday: ...\n\u2022 Today: ...\n\u2022 Blockers: ... (or 'none')\n\nEnd with a :rotating_light: line if anyone is blocked, tagging the team lead user ID <@U_LEAD>.",
"role": "user"
}
]
},
"options": {
"temperature": 0.3,
"maxTokens": 2000
}
},
"id": "claude-summary",
"name": "Claude summary",
"type": "@n8n/n8n-nodes-langchain.anthropic",
"typeVersion": 1.2,
"position": [
1740,
300
],
"credentials": {
"anthropicApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"jsCode": "const raw = $input.first().json.content?.[0]?.text || $input.first().json.text || '';\nconst match = raw.match(/\\{[\\s\\S]*\\}/);\nif (!match) throw new Error('No JSON');\nreturn [{ json: JSON.parse(match[0]) }];"
},
"id": "parse-summary",
"name": "Parse summary JSON",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1960,
300
]
},
{
"parameters": {
"channel": "REPLACE_ME_STANDUP_CHANNEL_ID",
"text": "={{ $json.summary_md }}",
"otherOptions": {}
},
"id": "slack-post-recap",
"name": "Post recap to #standup",
"type": "n8n-nodes-base.slack",
"typeVersion": 2.2,
"position": [
2180,
300
],
"credentials": {
"slackApi": {
"name": "<your credential>"
}
}
}
],
"connections": {
"Weekdays 9:30": {
"main": [
[
{
"node": "Read team roster",
"type": "main",
"index": 0
}
]
]
},
"Read team roster": {
"main": [
[
{
"node": "Filter active members",
"type": "main",
"index": 0
}
]
]
},
"Filter active members": {
"main": [
[
{
"node": "DM each member",
"type": "main",
"index": 0
}
]
]
},
"DM each member": {
"main": [
[
{
"node": "Wait 45 min",
"type": "main",
"index": 0
}
]
]
},
"Wait 45 min": {
"main": [
[
{
"node": "Build time window",
"type": "main",
"index": 0
}
]
]
},
"Build time window": {
"main": [
[
{
"node": "Read each DM thread",
"type": "main",
"index": 0
}
]
]
},
"Read each DM thread": {
"main": [
[
{
"node": "Claude summary",
"type": "main",
"index": 0
}
]
]
},
"Claude summary": {
"main": [
[
{
"node": "Parse summary JSON",
"type": "main",
"index": 0
}
]
]
},
"Parse summary JSON": {
"main": [
[
{
"node": "Post recap to #standup",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
},
"meta": {
"templateId": "skynetlabs-15"
},
"tags": [
{
"name": "skynetlabs-pack"
},
{
"name": "standup"
},
{
"name": "slack"
}
]
}
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.
anthropicApigoogleSheetsOAuth2ApislackApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
15 - Async Standup Bot. Uses googleSheets, slack, anthropic. Scheduled trigger; 10 nodes.
Source: https://github.com/waseemnasir2k26/skynet-automation-pack/blob/main/n8n/15-async-standup-bot.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.
06 - AEO Citation Monitor (4 LLMs). Uses googleSheets, anthropic, httpRequest, slack. Scheduled trigger; 11 nodes.
01 - LinkedIn DM ICP Scorer. Uses httpRequest, anthropic, slack, googleSheets. Scheduled trigger; 9 nodes.
09 - GSC anomaly bot. Uses httpRequest, anthropic, slack, googleSheets. Scheduled trigger; 8 nodes.
03 - Cold Email Warm-up + Reply Detector. Uses emailReadImap, anthropic, slack, googleSheets. Scheduled trigger; 7 nodes.
Imagine a dedicated financial expert tirelessly working behind the scenes, sifting through every transaction, every investment move, and every accounting entry. That's exactly what this automated syst