Dictate a task to Siri, get it dropped in the Notion Tasks DB with Status=Next, then enriched async by an LLM that fills in Area/Energy/Status/Project/Due Date/URL. Siri gets a fast 200 back; enrichment runs after.
Sister workflow to Project Capture — same architecture, same credentials, same conventions.
Quick Reference
| Item | Value |
|---|---|
| n8n workflow ID | uaQCrtTUYl8g4saD |
| Workflow name | Todo Capture (Siri → Notion + LLM enrichment) |
| Webhook URL | https://n8n.cloud.mdbook.one/webhook/todo-capture |
| Method | POST |
| LLM backend | LibreChat agent (Qwen3.5:9b) via lmChatOpenAi |
| LibreChat agent | agent_h2M-pQF66cfp0SCK9Vy5S |
| LLM prompt (git) | mikayla/scripts:prompts/todo-capture.md |
| Notion target | Tasks DB → Status=Next |
| Status | ACTIVE — live in n8n (creds wired, webhook authed) |
Architecture
Split-response pattern — Siri doesn’t wait for the LLM.
Webhook (Siri POST)
↓
Create Task (Notion: name only, Status=Next)
↓
Respond to Siri (200 immediately)
↓
Fetch Active Projects (Notion: Projects DB where Status=Active)
↓
Build Enrichment Prompt (assembles user-message: date + title + project list; rules live on the agent)
↓
Enrich w/ LLM (chainLlm + lmChatOpenAi → LibreChat)
↓
Parse + Build Update (reads $json.text, validates, builds Notion patch)
↓
Update Task w/ Enrichment (Notion: patches Area/Energy/Status/Project/Due/URL/Notes,
or sets Needs Review=true on failure)
No inbox triage step. Every task lands with a real Status the moment it’s captured.
iOS Shortcut Spec
POST to the webhook with:
- Header:
Authorization: <bearer-or-shared-secret>— placeholder, fill in your own - Header:
Content-Type: application/json - Body:
{ "title": "<dictated text>" }
Raw dictation goes in as-is — the LLM splits it into clean title + URL + notes.
LLM Enrichment
Uses LangChain pattern (same as the YouTube Summary workflow):
@n8n/n8n-nodes-langchain.chainLlm— main reasoning node@n8n/n8n-nodes-langchain.lmChatOpenAiattached viaai_languageModel— model nodeopenAiApicredential points at LibreChat (chat.mdbook.me), agent does the actual model selection- Output is read as
$json.textin the Parse node
The full classifier system prompt lives in git at mikayla/scripts:prompts/todo-capture.md. Source of truth for the running prompt is still the LibreChat agent UI — keep them in sync by hand for now.
Classifier output schema
{
"title": "cleaned task name",
"url": "extracted URL or null",
"notes": "extra context or null",
"areas": ["Homelab", "Code", ...],
"energy": "Quick" | "Medium" | "Long" | "Deep",
"status": "Next" | "Someday" | "Waiting",
"project_id": "Notion page ID or null",
"due_date": "YYYY-MM-DD or null"
}Rules baked into the prompt
- Energy buckets: Quick (<15m), Medium (15m–1hr), Long (1–3hr), Deep (3hr+)
- Status:
Next(default — actionable now or soon),Someday(explicit someday/maybe/eventually language),Waiting(dictation explicitly mentions waiting on someone or something external).Doing,Done,Cancelledare never LLM-settable on a freshly captured task. - Areas: Homelab / Code / Coaching / Teaching / Audio / Personal / Health / Errands / Music
- Project match is strict — no fuzzy guessing, return null if unsure
- Due dates ISO
YYYY-MM-DDonly, from explicit refs in title; vague refs → null - Today’s date injected by n8n in America/New_York; Parse node validates ISO before sending to Notion
Credentials Needed
- Notion internal integration token — must have access to the 🎯 Tasks parent page (covers Tasks + Projects DBs)
- HTTP Header Auth credential — for the inbound webhook Authorization check
- OpenAI API credential pointing at LibreChat — can reuse
LibreChat- Youtube Summarycred or make a dedicated one for the todo enricher agent
All placeholders in n8n — never paste real tokens into LLM chat windows.
Schema (Tasks DB)
Status select options (Inbox dropped 2026-05-15): Next, Doing, Waiting, Someday, Done, Cancelled. Initial Create Task node forces Status=Next so the task lands on the active board immediately; the LLM can demote to Someday or Waiting via enrichment.
Needs Review— checkbox property, set to true when LLM enrichment fails or output is invalid⚠️ Needs Review— view filtered toNeeds Review = truefor triage⚠️ No Status— view filtered toStatus IS EMPTY; safety net for any task that somehow lands without a status (should always be empty)
Gotchas
- Database ID vs Data source ID. Notion’s public REST API wants the URL-style database ID. The
collection://data source ID is for internal MCP/native nodes only. Wrong one → 404 “resource not found.” n8n HTTP nodes hit the public API, so use the database ID. - URL property key. This workflow hits the raw Notion REST API, so the Parse node writes the field under its literal property name
URL(properties.URL = { url }). TheuserDefined:URLprefix is a Notion MCP convention only — it does not apply to these HTTP-node calls. Don’t add it here. - LangChain output shape.
chainLlmreturns the model text on$json.text, NOT$json.outputor$json.message.content. Easy to get wrong if you’re copying from a regular HTTP-call pattern. - Schema is load-bearing. If you change field names, types, or value enums in the classifier prompt, also update the Parse + Build Update node in n8n. Validation failure →
Needs Review=true. - Default status is Next in n8n, not in the LLM. The initial
Create Tasknode forcesStatus=Nextso the task lands on the Now Board immediately. The LLM can later demote it toSomeday/Waitingvia the enrichment patch.Doing/Done/Cancelledare never LLM-settable. - Failure mode. If the LLM returns malformed JSON or any required field fails validation, the Parse node leaves the placeholder
Status=Nextin place, setsNeeds Review=true, and skips the rest of the patch. Manual triage via the Needs Review view. - Timezone. All date math runs in America/New_York, injected from n8n’s current time, not the LLM’s notion of “today.”
Disabling
n8n UI → workflow uaQCrtTUYl8g4saD → toggle Active off. Or delete the webhook credential to break it at the auth layer without touching the workflow itself.
Related
- Sister workflow: Project Capture (Siri → Notion + LLM enrichment)
- iOS Shortcut config: not yet exported/versioned. Deferred TODO — lives only on the phone.
- LLM prompt:
mikayla/scripts:prompts/todo-capture.md(versioned). LibreChat agent UI is still the runtime source of truth — keep them in sync by hand for now. - Tasks DB / Projects DB schemas: see Notion 🎯 Tasks page.
Changelog
- 2026-06-03 — Doc refresh: workflow confirmed active in n8n (Quick Reference previously said INACTIVE). Corrected the URL-key gotcha — the raw REST node uses the literal
URLkey, not theuserDefined:URLMCP form. Noted the Parse node is on the v3 output schema (adds cleanedtitle,url,due_dateon top of the v2statusfield). Fixed the sister-workflow link to the Quartz path. - 2026-05-15 — Retired the Inbox triage step.
InboxStatus option dropped from the Tasks DB;📥 Inboxview repurposed as⚠️ No Status(safety net for tasks without a status). n8n now creates tasks withStatus=Nexton the initial node, mirroring Project Capture. LLM prompt v2 adds astatusfield (Next/Someday/Waiting) so the enricher can demote when the dictation calls for it.