Morning Notion Task Digest to Telegram
A personal assistant recipe where Notion rules define scheduled and event-driven jobs, Upstash runs the orchestration, and Telegram receives the morning report.
What This Builds
This recipe builds a small personal automation system. Notion is the human-editable source of truth for rules, tasks, and inbox items. Upstash holds the runtime registry and executes scheduled or event-driven work. Telegram receives morning summaries and follow-up notifications.
The first useful behavior is simple: every morning at 09:00, the system reads today’s Notion tasks, prepares a short digest, writes the digest to a Notion inbox, and sends the same summary to Telegram.
Product Shape
This is an assistant system, not just a cron job. The scheduled worker can be lightweight, but the output lands in a shared inbox that the main assistant can read later. If the user continues the conversation in Telegram, the assistant can use the same Notion inbox, task database, rule database, Redis registry, and optional Search index as context.
Architecture
flowchart TD
NotionRules["Notion: Automation Rules"] --> SyncHook["Rule sync webhook"]
SyncHook --> Redis["Upstash | Redis runtime registry"]
Redis --> QStash["Upstash | QStash schedules"]
Redis --> EventRouter["Event router"]
QStash --> MorningWorkflow["Upstash | Workflow: morning digest"]
NotionEvents["Notion task/page events"] --> EventRouter
EventRouter --> MorningWorkflow
EventRouter --> HeavyAgent["Upstash | Box: heavy agent run"]
MorningWorkflow --> NotionTasks["Notion: Tasks DB"]
MorningWorkflow --> Search["Upstash | Search indexed context"]
MorningWorkflow --> Inbox["Notion: Assistant Inbox"]
MorningWorkflow --> Telegram["Telegram Bot API"]
HeavyAgent --> Inbox
HeavyAgent --> Telegram
Components
Notion
Use Notion as the source of truth for human-editable state:
Automation Rulesdatabase: enabled rules, cron expressions, event filters, target executor, prompt, and runtime status.Tasksdatabase: the real task source for morning digests and status-change reactions.Assistant Inboxdatabase: generated summaries, pending suggestions, and notifications that the assistant can read later.Runsdatabase: execution logs, last success, errors, and links to generated inbox items.
Upstash | Redis
Use Redis for runtime state that should not require re-reading Notion on every tick:
rule:{id}stores the normalized rule payload.schedule:{rule_id}maps a Notion rule to the provider schedule id.snapshot:{page_id}stores the last known Notion task status for event matching.lock:{rule_id}prevents duplicate runs.run:{run_id}stores short-lived execution state.
Upstash | QStash
Use QStash for real schedules and HTTP delivery. When a Notion schedule rule is created or changed, the sync webhook creates, updates, pauses, or deletes the matching QStash schedule. QStash then fires independently. It should not poll Notion every minute to discover due jobs.
Upstash | Workflow
Use Workflow for light durable work:
- Load the normalized rule from Redis.
- Fetch tasks from Notion.
- Optionally query Upstash | Search for relevant context.
- Call a small LLM prompt or lightweight assistant handler.
- Write a Notion inbox item.
- Send a Telegram message.
- Write a run log.
Upstash | Search
Use Search for indexed context, not as the source of truth. A sync job can upsert selected Notion pages, inbox entries, project notes, and rule descriptions into Search. The assistant then asks Search for relevant context instead of scanning everything.
Upstash | Box
Use Box only for heavy work: coding-agent loops, shell access, git operations, Playwright, filesystem-heavy jobs, or custom agent harnesses. Most morning digest jobs should stay in Workflow. If a rule says executor = heavy-agent, the router can wake a Box and run a prompt or command.
Telegram
Telegram is the notification and continuation surface. The morning digest message should include enough context to act immediately, plus stable links back to Notion inbox items. Follow-up messages can be routed to the main assistant, which reads the same inbox and Search context.
Rule Examples
Daily Morning Digest
name: Morning task digest
enabled: true
trigger:
type: schedule
cron: "0 9 * * *"
timezone: "Asia/Ho_Chi_Minh"
executor:
type: workflow
handler: morning-task-digest
inputs:
taskDatabase: notion_tasks
inboxDatabase: assistant_inbox
telegramChat: personal
Task Ready For Review
name: Review task when status changes
enabled: true
trigger:
type: notion-event
database: notion_tasks
when:
property: Status
from: In Progress
to: Ready for Review
executor:
type: heavy-agent
box: personal-assistant
prompt: "Review the task, inspect linked context, and write a concise review note."
outputs:
inbox: true
telegram: true
Why This Shape Works
The important boundary is that Notion remains the place where the user edits rules, but runtime execution is not based on constant Notion polling. Rule changes are synced into QStash schedules, Redis registry records, and event-router indexes. Scheduled jobs then run from the scheduler. Event jobs run from webhook signals and compare against stored snapshots only when a relevant Notion event arrives.
Minimal Prototype
Start with four pieces:
- A Notion
Automation Rulesdatabase with one daily digest rule. - A tiny webhook/sync endpoint that registers the QStash schedule and stores the normalized rule in Redis.
- One Upstash Workflow endpoint that reads Notion tasks, writes an inbox item, and sends Telegram.
- A Telegram bot token and chat id.
Add Upstash | Search after the first digest works. Add Upstash | Box only when the task requires a real agent runtime rather than a simple workflow.