Dictate a project name (or short pitch) to Siri, get it dropped in the Notion 📁 Projects DB with Status=Active, then enriched async by an LLM that fills in Area / Status / Link / Target Date / Notes / Icon (page emoji) / and (if the dictation was rich enough) a 1–3 sentence scope blurb in the page body. Siri gets a fast 200 back; enrichment runs after.
Sister workflow to Todo Capture — same architecture, same credentials, same conventions.
Quick Reference
| Item | Value |
|---|---|
| n8n workflow ID | e0BX5mVEAqTOynqp |
| Workflow name | Project Capture (Siri → Notion + LLM enrichment) |
| Webhook URL | https://n8n.cloud.mdbook.one/webhook/project-capture |
| Method | POST |
| LLM backend | LibreChat agent (Qwen3.5:9b) via lmChatOpenAi |
| LibreChat agent | agent_sxbUMb6A7G1mt5663597u |
| LLM prompt (git) | mikayla/scripts:prompts/project-capture.md |
| Notion target | 📁 Projects DB → Status=Active |
| Status | n8n workflow ACTIVE; iOS Shortcut not yet versioned |
Architecture
Split-response pattern — Siri doesn’t wait for the LLM.
Webhook (Siri POST)
↓
Create Project (Notion: name only, Status=Active)
↓
Respond to Siri (200 immediately)
↓
Build Enrichment Prompt (today + raw title; no project list, unlike Todo Capture)
↓
Enrich w/ LLM (chainLlm + lmChatOpenAi → LibreChat)
↓
Parse + Build Update (reads $json.text, validates, builds Notion patch + optional body block)
↓
Update Project w/ (Notion PATCH /v1/pages/{pageId} —
Enrichment cleaned title, Area, Status, Link, Target Date, Notes,
Needs Review, AND page-level icon emoji)
↓
If Has Description (true → append; false → done)
↓
Append Description Block (Notion PATCH /v1/blocks/{pageId}/children —
paragraph block with the LLM scope blurb)
iOS Shortcut Spec
POST to the webhook with:
- Header:
Authorization: <bearer-or-shared-secret>— same shared secret as Todo Capture (reuses theHeader Auth accountcredlgNSPgd9yTwylM8b) - Header:
Content-Type: application/json - Body:
{ "title": "<dictated text>" }
Raw dictation goes in as-is — the LLM splits it into clean title + link + notes + icon + (optional) description. Short dictations like “new project rewire the rack” still work; longer ones like “build a mobile-first dashboard for my Bambu Lab printers to replace Bambu Handy via reverse proxy” get a paragraph appended to the page body. Either way, the page gets an emoji icon.
LLM Enrichment
Uses the same LangChain pattern as Todo Capture:
@n8n/n8n-nodes-langchain.chainLlm— main reasoning node@n8n/n8n-nodes-langchain.lmChatOpenAiattached viaai_languageModel— model nodeopenAiApicredential points at LibreChat (chat.mdbook.me); the model node targets agentagent_sxbUMb6A7G1mt5663597u- Output is read as
$json.textin the Parse node
The full classifier system prompt lives in git at mikayla/scripts:prompts/project-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 project name",
"areas": ["Homelab", "Code", ...],
"status": "Active" | "Backlog" | "Paused",
"link": "extracted URL or null",
"target_date": "YYYY-MM-DD or null",
"notes": "extra context or null",
"description": "1–3 sentence body blurb, or null for one-liner dictations",
"icon": "single emoji, required"
}Rules baked into the prompt
- Areas: Homelab / Code / Coaching / Teaching / Audio / Personal / Health / Errands / Music (multi-select; 1–2 commonly apply)
- Status: Active (default), Backlog (someday/idea), Paused (explicitly on hold). Done/Archived are never LLM-settable for a freshly-created project.
- Target dates ISO
YYYY-MM-DDonly, from explicit refs (incl. quarter-ends, “in N months”); vague refs → null descriptionis conditional: only emitted when the dictation contains substantive scope/goal info beyond the name. One-liners → null.iconis always required (single emoji). LLM prefers a subject-specific emoji over a generic area emoji; falls back to a per-area emoji when no specific match fits. Set as the Notion page-level icon, not a property.- Today’s date injected by n8n in America/New_York; Parse node validates ISO before sending to Notion
Credentials Needed
All reused from Todo Capture:
- Notion internal integration token (
LmNPdmds7KJiP78a) — must have access to the 📁 Projects DB - HTTP Header Auth credential (
lgNSPgd9yTwylM8b) — for the inbound webhook Authorization check - OpenAI API credential pointing at LibreChat (
E3JKwhS3rOMyn72x, shared “LibreChat- Youtube Summary” cred) — provides the LibreChat connection; the model node selects the dedicated Project Capture agent
No new creds required.
Schema Additions (Projects DB)
Already applied to the 📁 Projects DB (759dacc380be4c6594ab95d7d002d605):
Notes— rich_text — extra context the LLM extracted but couldn’t slot into a structured fieldNeeds Review— checkbox — set true when LLM JSON fails to parse/validate, or when nothing useful comes back- (recommended, not yet created) view
⚠️ Needs Reviewfiltered toNeeds Review = truefor triage
Existing Projects DB properties used: Name (title), Area (multi_select), Status (select), Link (url), Target Date (date). The page icon is set on the page object itself — no schema property needed.
Gotchas
- Database ID vs Data source ID. Notion’s public REST API wants the URL-style database ID
759dacc380be4c6594ab95d7d002d605. Thecollection://811b3380-...data source ID is for internal MCP/native nodes only. n8n HTTP nodes hit the public API, so use the database ID. - URL property key. This DB’s URL field is named
Link, notURL, so the JSON key is literallyLink— nouserDefined:prefix needed (only the Tasks DB’sURLfield has that quirk). - Page icon lives on the page, not in properties. The PATCH body sets
iconat the top level alongsideproperties:{"icon": {"type": "emoji", "emoji": "🖨️"}, "properties": {...}}. Don’t try to model it as a property. - LangChain output shape.
chainLlmreturns the model text on$json.text, NOT$json.outputor$json.message.content. - Page body is a separate API call.
/v1/pages/{id}PATCH doesn’t acceptchildren. Body blocks have to be appended via/v1/blocks/{pageId}/childrenPATCH. TheIf Has Descriptionnode gates this so one-liner dictations don’t fire an empty append. - 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=trueand the page keeps its raw title. - Default status is Active in n8n, not in the LLM. The initial
Create Projectnode forcesStatus=Activeso the page lands in your active board immediately. The LLM can later demote it to Backlog/Paused via the enrichment patch. - Failure mode. Malformed JSON or all-empty enrichment →
Needs Review=true, no body block appended, no icon set. 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 e0BX5mVEAqTOynqp → toggle Active off. Or delete the webhook credential to break it at the auth layer without touching the workflow itself.
Related
- Sister workflow: Todo Capture (Siri → Notion + LLM enrichment)
- iOS Shortcut config: not yet exported/versioned. Deferred TODO — lives only on the phone.
- LLM prompt:
mikayla/scripts:prompts/project-capture.md(versioned). LibreChat agent UI is still the runtime source of truth — keep them in sync by hand for now. - Projects DB schema: see Notion 📁 Projects database.
Changelog
- 2026-06-03 — First doc refresh since creation. Confirmed the n8n workflow is active (Quick Reference previously said INACTIVE). Fixed the sister-workflow link to the Quartz path. Clarified that the shared LibreChat cred provides the connection while the model node selects the dedicated agent. Open item: confirm agent
agent_sxbUMb6A7G1mt5663597uis actually provisioned in LibreChat — theEnrich w/ LLMnode’s own note still flags the agent ID as a placeholder.