Our standups died a slow death. By March 2026 only 7 of 12 people made the 9:05 call, half of those joined muted, and the meeting ran 22 minutes for content that fit in three Slack bullet points. We replaced it. Every morning at 8:30 IST a workflow crawls Notion for yesterday's updates, asks Claude to summarise per team, and posts a structured digest to #daily-pulse. Reading time: 90 seconds. Standup time recovered: ~5 person-hours a week.
TL;DR
A Cron node fires every weekday at 8:30 IST. n8n hits Notion's search API for pages updated in the last 24 hours across 5 team databases (engineering, design, product, sales, ops). For each team, the workflow batches the page contents and asks Claude Sonnet 4.5 to write a 4-point summary: what shipped, what is in progress, what is blocked, and one question for the team. The 5 summaries are stitched into a single Slack message and posted to #daily-pulse with at-mentions where action is needed.
Why this matters now — April 2026
Three things changed. Notion's API v2 (Dec 2025) added a clean "filter by last_edited_time" query so you do not have to fetch-then-filter — saves 90% of the API quota. Slack's Block Kit got richer "context" blocks (Mar 2026) so you can render compact, scannable digests instead of paragraph walls. And Claude Sonnet 4.5's 200k-token window means you can feed an entire team's worth of pages in a single call without chunking.
A widely-shared post on Hacker News in February 2026 ("Standups are dead, async digests killed them") got 1,200+ comments — most disagreeing politely, but the underlying point landed for us. We kept twice-weekly group calls for vibes; the daily ritual went async.
The 5-block workflow
Prerequisites
- n8n v1.121+ (Cron node v1.4 timezone-aware required)
- Notion workspace with internal integration token. Each team database must be shared with the integration
- The Notion database IDs for each team you want to digest (5 in our case)
- Anthropic API key with Claude Sonnet 4.5 access
- Slack workspace, bot with chat:write and a dedicated channel like #daily-pulse
- A Notion "team" property convention — each page tagged with a Team property so we know which bucket it belongs to
Step 1 — The cron trigger
n8n's Schedule Trigger v1.4. Set the timezone explicitly to Asia/Kolkata to avoid the daylight-saving confusion that bit us in 2025.
{
"parameters": {
"rule": {
"interval": [
{ "field": "cronExpression", "expression": "0 30 8 * * 1-5" }
]
},
"options": {
"timezone": "Asia/Kolkata"
}
},
"id": "cron-0830-ist",
"name": "Daily 8:30 IST",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.4,
"position": [240, 300]
} The cron expression 0 30 8 1-5 is "minute 30 of hour 8, every weekday." We tried 9:00 first; people read better at 8:30 before checking the rest of Slack.
Step 2 — Notion crawl with filter
For each of the 5 team databases, an HTTP Request node hits Notion's /v1/databases/{id}/query endpoint with a filter:
{
"filter": {
"timestamp": "last_edited_time",
"last_edited_time": {
"on_or_after": "{{ DateTime.now().minus({ hours: 24 }).toISO() }}"
}
},
"page_size": 100,
"sorts": [{ "timestamp": "last_edited_time", "direction": "descending" }]
}The native Notion node works too; we use the HTTP Request because we want explicit control over pagination. Most teams produce 8–25 pages a day in our workspace.
For each returned page, a second loop fetches the page blocks (GET /v1/blocks/{page_id}/children) to get the actual content, not just titles. We flatten the blocks into a clean text representation in a Code node:
function flattenBlocks(blocks) {
return blocks.map(b => {
const t = b.type;
const rich = b[t]?.rich_text?.map(r => r.plain_text).join('') || '';
if (t === 'heading_1') return '# ' + rich;
if (t === 'heading_2') return '## ' + rich;
if (t === 'heading_3') return '### ' + rich;
if (t === 'bulleted_list_item') return '- ' + rich;
if (t === 'numbered_list_item') return '1. ' + rich;
if (t === 'to_do') return (b.to_do.checked ? '[x] ' : '[ ] ') + rich;
if (t === 'callout') return '> ' + rich;
if (t === 'code') return '\`\`\`\n' + rich + '\n\`\`\`';
return rich;
}).filter(Boolean).join('\n');
}
const pages = $input.all();
const grouped = {};
for (const p of pages) {
const team = p.json.properties?.Team?.select?.name || 'Unassigned';
if (!grouped[team]) grouped[team] = [];
grouped[team].push({
title: p.json.properties?.Name?.title?.[0]?.plain_text || 'Untitled',
url: p.json.url,
last_edited_by: p.json.last_edited_by?.id,
text: flattenBlocks(p.json.children || [])
});
}
return Object.entries(grouped).map(([team, items]) => ({ json: { team, items } }));Output is one item per team, each carrying the flattened page text.
Step 3 — Per-team Claude summary
A Loop Over Items node (n8n v1.121's stable version) iterates teams, calling Claude per team:
You are writing a daily digest for the {{ $json.team }} team at Softechinfra. The reader is the rest of the company — leadership and other teams. Voice: direct, no hype, no buzzwords.
Produce exactly this Slack-flavoured markdown:
*🟢 Shipped*
- bullet (max 4 bullets, each one line max 100 chars)
*🟡 In Progress*
- bullet (max 4 bullets)
*🔴 Blocked / Needs Help*
- bullet, prefix with @teamname if action needed (max 3 bullets)
*❓ One question for this team*
One short question that surfaces a decision someone needs to make today.
Rules:
- Skip empty sections (do not output the header if no items).
- Group similar items into one bullet, do not repeat.
- If no pages had any "blocked" content, write nothing under that section.
- Banned phrases: "leverage", "robust", "synergy", "synergies", "deep dive".
- Max total: 280 words.User message body:
Team: {{ $json.team }}
Date range: last 24 hours
Pages updated:
{{ $json.items.map(p => '— ' + p.title + ' ([link](' + p.url + '))\n' + p.text.slice(0, 1500)).join('\n\n---\n\n') }}The 1,500-char-per-page slice keeps total input around 12k tokens per team — well within Sonnet's window, and cheap. Notion API hits and the Slack post are free.
The Claude response per team is captured in a Set node and we proceed once all 5 are done.
Step 4 — Slack Block Kit composition
A Code node stitches the 5 team summaries into a single Slack message using Block Kit. The structure: header, date, divider, [team header + summary] × 5, footer with a link to the n8n execution for debugging.
const date = new Date().toLocaleDateString('en-IN', { weekday: 'long', day: 'numeric', month: 'short' });
const summaries = $input.all().map(i => i.json); // each has { team, summary }
const blocks = [
{ type: 'header', text: { type: 'plain_text', text: '☀️ Daily Pulse — ' + date } },
{ type: 'context', elements: [{ type: 'mrkdwn', text: '_Auto-generated from Notion updates in the last 24h. Reply in-thread with corrections._' }] },
{ type: 'divider' }
];
for (const s of summaries) {
blocks.push({ type: 'section', text: { type: 'mrkdwn', text: '*' + s.team + '*\n' + s.summary } });
blocks.push({ type: 'divider' });
}
blocks.push({ type: 'context', elements: [{ type: 'mrkdwn', text: '<https://n8n.softechinfra.com/execution/' + $execution.id + '|View execution> · :notion: <https://www.notion.so/softechinfra|Open team space>' }] });
return { json: { blocks } }; A Slack node posts blocks to #daily-pulse with the bot user identity.
Sample digest output (real, anonymised)
This is the digest from Monday 21 April 2026, posted at 8:31 IST:
☀️ Daily Pulse — Monday, 21 Apr
_Auto-generated from Notion updates in the last 24h. Reply in-thread with corrections._>
--->
Engineering
🟢 Shipped
- n8n receptionist workflow live for Magpie Logistics — 47 nodes, soak test passed
- Hetzner CX22 → CPX31 migration done, n8n RAM headroom doubled>
🟡 In Progress
- Tally XML schema refactor for 6.1 compatibility (Anjali leading, ETA Wed)>
🔴 Blocked / Needs Help
- @design Calendly brief workflow needs final logo SVG for Slack header — blocker since Fri>
❓ One question for this team
Do we lock the new "production checklist" template before Wed's release, or after the Magpie post-mortem?>
--->
Design
🟢 Shipped
- 3 hero illustrations for the blog refresh, exported in WebP + AVIF>
🟡 In Progress
- Sales deck v3 — 60% done, waiting on case-study photo from Karthik>
❓ One question for this team
Are we matching the new brand teal across the n8n workflow screenshots, or keeping product-default?>
--->
Sales
🟢 Shipped
- 4 demos done last week (3 inbound, 1 referral). 2 advanced to Tier-A
- HubSpot ICP rubric v2.1 deployed>
🔴 Blocked / Needs Help
- @engineering need a 5-minute demo recording of the Calendly brief workflow for tomorrow's call>
--->
Ops
🟢 Shipped
- April invoices closed, ITR-3 prep started
- DPDP Act addendum signed with Anthropic>
--->
_View execution · :notion: Open team space_
That digest is 280 words. Every person in #daily-pulse reads it in under 2 minutes. The cross-team @-mentions ("@design needs SVG") actually get replied in-thread, which is half the magic.
Cost comparison vs the standup
For a 12-person team meeting daily 9:00-9:22 IST:
The standup cost is the loaded hour-rate × 22 minutes × 12 people × 22 working days. Even if you discount it 50% for "people would be slacking off anyway," the digest still wins by an order of magnitude.
When NOT to do this
You have a remote-first team that has never met. Standups have a social bonding function the digest cannot replace. Keep a Monday + Thursday human call; replace Tue/Wed/Fri with digests.
Your team does not document in Notion. If your work lives in Linear tickets, GitHub PRs, Figma, and Slack DMs scattered across surfaces, the digest is incomplete by design. Build the documentation discipline first (or replace the Notion crawl with multi-source — Linear + GitHub + Figma — which is 3× the nodes and probably 60+ on n8n).
Your team is under 5 people. A 5-person team can run a useful standup in 4 minutes. Below that headcount the digest infra is overkill.
A real case — our team, March-April 2026
We migrated 12 people over 3 weeks. Week 1: digest ran alongside standup. Week 2: standup dropped to MWF. Week 3: standup gone, replaced with a 25-minute Monday all-hands.
Outcomes after 6 weeks:
The same Notion-Claude-Slack pipeline pattern powers the internal communications layer behind a client platform, when student-writing feedback cycles need to be summarised across teaching pods, the architecture is identical. Different content, same workflow shape.
Common mistakes
Mistake 1 — Including the digest in every team's Slack channel. Avoid noise. One company-wide channel works because everyone reads the cross-team mentions; per-team channels create silos.
Mistake 2 — Letting Claude name people who did not author the work. The Notion API exposes last_edited_by as an ID. Resolve it to a name + Slack handle via Slack's users.list, then feed the mapping to Claude in the system prompt. Otherwise it hallucinates "Priya edited this" when Anjali actually did.
Mistake 3 — Trying to summarise too far back. 24 hours is the right window. 48-72 hours creates a wall of text and loses the "what is fresh today" signal.
Mistake 4 — Skipping the empty-section rule. Without "skip empty sections" in the prompt, Claude writes filler like "🔴 Blocked — Nothing blocked today!" which becomes noise. Strip it.
Mistake 5 — Running it on weekends. Sunday-night digests are demoralising. Cron 1-5 (Mon-Fri) only.
FAQ
Can I run this from Asana / Linear / Jira instead of Notion?
Yes. Each has a REST API. Linear's GraphQL is the cleanest — one query returns all issues updated in last 24h with comments and status changes. Workflow logic stays identical; only step 2 changes.
How do I handle confidential pages?
Two options. Most accurate: tag confidential pages with a Notion property include_in_digest = false and filter them out. Lazier: scope your Notion integration to only the databases you want digested; private pages outside those scopes are invisible to the crawl anyway.
Can the digest include action item assignments?
Yes. Claude can output an explicit actions array, and a downstream branch creates Linear tasks or Notion to-dos for each. We have not added this in production yet — too easy to spam your tracker.
What about Hindi-only or bilingual teams?
Add a language parameter to the Claude prompt: "Output in {{ team.preferred_language }}". For our team it is English; for one client team we run it in Hinglish (their request, our team prefers it).
Does it work with Notion's new "AI blocks"?
Yes — AI block content is part of the regular block tree and gets flattened normally. We get cleaner summaries than from the native Notion AI assistant because Sonnet 4.5 has more context and the rules are tighter.
Can leadership get a different version of the digest?
Yes. Branch after the per-team summaries: send the full digest to #daily-pulse, send a leadership-only top-line ("3 shipments, 1 blocker, 2 questions") to #leadership-only. Adds 2 nodes.
What if the cron run fails?
Two safeguards. n8n's "Error Workflow" feature pings a separate error workflow that DMs the ops lead. We also send a heartbeat ping to Better Uptime at the end of the digest workflow — no ping in 10 minutes after expected fire = page.
Want this digest built for your team?
We ship the full 14-node workflow above, wired to your Notion (or Linear / Asana / Jira), your Slack, and tuned to your team's tone in a 30-min workshop with your team lead. Suitable if you have 8+ people doing daily standup and the meeting is no longer earning the time. No slides — bring a week of standup notes and we will show you what the digest would have looked like.
Book a 20-min Call