From 13ab43de6c4da1b77eff6e706a66322675c1ea60 Mon Sep 17 00:00:00 2001 From: William Valentin Date: Thu, 14 May 2026 14:39:10 -0700 Subject: [PATCH] feat(n8n): add obsidian automation workflows --- swarm-common/n8n-workflows/obsidian-6SKSZWZwuJNwuO2P.json | 1 + swarm-common/n8n-workflows/obsidian-LF3i86l3NkxpayxL.json | 1 + swarm-common/n8n-workflows/obsidian-Ori3Bu5u5ODtxxyD.json | 1 + swarm-common/n8n-workflows/obsidian-PCtD3PuQjzKLyEEE.json | 1 + swarm-common/n8n-workflows/obsidian-UWLMOQQVxbTX6Sis.json | 1 + swarm-common/n8n-workflows/obsidian-YZyJ5G0Ur8D6TlM8.json | 1 + 6 files changed, 6 insertions(+) create mode 100644 swarm-common/n8n-workflows/obsidian-6SKSZWZwuJNwuO2P.json create mode 100644 swarm-common/n8n-workflows/obsidian-LF3i86l3NkxpayxL.json create mode 100644 swarm-common/n8n-workflows/obsidian-Ori3Bu5u5ODtxxyD.json create mode 100644 swarm-common/n8n-workflows/obsidian-PCtD3PuQjzKLyEEE.json create mode 100644 swarm-common/n8n-workflows/obsidian-UWLMOQQVxbTX6Sis.json create mode 100644 swarm-common/n8n-workflows/obsidian-YZyJ5G0Ur8D6TlM8.json diff --git a/swarm-common/n8n-workflows/obsidian-6SKSZWZwuJNwuO2P.json b/swarm-common/n8n-workflows/obsidian-6SKSZWZwuJNwuO2P.json new file mode 100644 index 0000000..949f093 --- /dev/null +++ b/swarm-common/n8n-workflows/obsidian-6SKSZWZwuJNwuO2P.json @@ -0,0 +1 @@ +[{"updatedAt":"2026-05-14T21:36:33.163Z","createdAt":"2026-05-14T21:36:33.163Z","id":"6SKSZWZwuJNwuO2P","name":"Obsidian Inbox Triage","description":null,"active":true,"isArchived":false,"nodes":[{"parameters":{},"id":"a244fdef-bf36-4903-bc52-d37bbc501f64","name":"Manual Trigger","type":"n8n-nodes-base.manualTrigger","typeVersion":1,"position":[0,0]},{"parameters":{"rule":{"interval":[{"field":"cronExpression","expression":"0 18 * * *"}]}},"id":"f7ccf023-35a2-4011-9f35-82b7d9eb804d","name":"Daily 18:00 PT","type":"n8n-nodes-base.scheduleTrigger","typeVersion":1.2,"position":[0,180]},{"parameters":{"url":"http://172.19.0.1:27123/vault/Inbox/","options":{"timeout":30000},"authentication":"genericCredentialType","genericAuthType":"httpHeaderAuth"},"id":"21e3b6ca-f129-4884-82a4-80c9217cb0f4","name":"List Inbox","type":"n8n-nodes-base.httpRequest","typeVersion":4.2,"position":[280,80],"credentials":{"httpHeaderAuth":{"id":"465Swz2b71O2KRAK","name":"Obsidian Local REST API"}},"continueOnFail":true},{"parameters":{"jsCode":"\nconst now = new Date(); const date = now.toISOString().slice(0,10);\nconst input = $input.first().json;\nconst files = (Array.isArray(input.files) ? input.files : []).filter(f => f.endsWith('.md') && !f.includes('Triage'));\nconst lines = files.length ? files.map(f => `- [ ] [[${f.replace(/^Inbox\\//,'').replace(/\\.md$/,'')}]] — classify as Project / Resource / Decision / Runbook / Archive`).join('\\n') : '- No untriaged Inbox markdown files found.';\nconst body = `# Inbox Triage ${date}\n\nGenerated: ${now.toISOString()}\n\n## Inbox items\n\n${lines}\n\n## Promote to Projects\n\n- [ ] \n\n## Promote to Resources\n\n- [ ] \n\n## Promote to Decisions\n\n- [ ] \n\n## Promote to Runbooks\n\n- [ ] \n\n## Archive / Delete / Defer\n\n- [ ] \n`;\nreturn [{json:{path:`Inbox/Triage/${date}.md`, body}}];\n"},"id":"0b4e13c6-47ac-4d89-89b9-65d5da966c07","name":"Build Triage Note","type":"n8n-nodes-base.code","typeVersion":2,"position":[560,80]},{"parameters":{"method":"PUT","url":"={{'http://172.19.0.1:27123/vault/' + encodeURIComponent($json.path).replace(/%2F/g, '/')}}","sendHeaders":true,"headerParameters":{"parameters":[{"name":"Content-Type","value":"text/markdown"}]},"sendBody":true,"contentType":"raw","rawContentType":"text/markdown","body":"={{$json.body}}","options":{"timeout":30000},"authentication":"genericCredentialType","genericAuthType":"httpHeaderAuth"},"id":"dde63028-700e-4abd-af07-cb7af7119c99","name":"Write Triage Note","type":"n8n-nodes-base.httpRequest","typeVersion":4.2,"position":[840,80],"credentials":{"httpHeaderAuth":{"id":"465Swz2b71O2KRAK","name":"Obsidian Local REST API"}}}],"connections":{"Manual Trigger":{"main":[[{"node":"List Inbox","type":"main","index":0}]]},"Daily 18:00 PT":{"main":[[{"node":"List Inbox","type":"main","index":0}]]},"List Inbox":{"main":[[{"node":"Build Triage Note","type":"main","index":0}]]},"Build Triage Note":{"main":[[{"node":"Write Triage Note","type":"main","index":0}]]}},"settings":{"executionOrder":"v1","callerPolicy":"workflowsFromSameOwner","availableInMCP":false},"staticData":{"node:Daily 18:00 PT":{"recurrenceRules":[]}},"meta":null,"pinData":null,"versionId":"aa7b9bb1-7e61-410a-ae86-594e2325c52b","activeVersionId":"aa7b9bb1-7e61-410a-ae86-594e2325c52b","versionCounter":4,"triggerCount":1,"tags":[],"shared":[{"updatedAt":"2026-05-14T21:36:33.167Z","createdAt":"2026-05-14T21:36:33.167Z","role":"workflow:owner","workflowId":"6SKSZWZwuJNwuO2P","projectId":"WGdp8QunI1tHpjXa","project":{"updatedAt":"2026-03-11T21:08:10.005Z","createdAt":"2026-03-11T21:05:11.541Z","id":"WGdp8QunI1tHpjXa","name":"will will ","type":"personal","icon":null,"description":null,"creatorId":"5ad50ead-6e6a-4d12-ab5b-e5db15835bb5"}}],"versionMetadata":{"name":null,"description":null}}] \ No newline at end of file diff --git a/swarm-common/n8n-workflows/obsidian-LF3i86l3NkxpayxL.json b/swarm-common/n8n-workflows/obsidian-LF3i86l3NkxpayxL.json new file mode 100644 index 0000000..b045706 --- /dev/null +++ b/swarm-common/n8n-workflows/obsidian-LF3i86l3NkxpayxL.json @@ -0,0 +1 @@ +[{"updatedAt":"2026-05-14T21:36:33.215Z","createdAt":"2026-05-14T21:36:33.215Z","id":"LF3i86l3NkxpayxL","name":"Obsidian Chat Summary Capture","description":null,"active":true,"isArchived":false,"nodes":[{"parameters":{"httpMethod":"POST","path":"obsidian-chat-summary","responseMode":"responseNode","options":{}},"id":"90069c7c-b6c9-4434-93f4-3b97061e590a","name":"Webhook - Chat Summary","type":"n8n-nodes-base.webhook","typeVersion":2,"position":[0,0],"webhookId":"obsidian-chat-summary"},{"parameters":{"jsCode":"\nconst input = $json.body ?? $json;\nconst now = new Date(); const iso = now.toISOString(); const date = iso.slice(0,10);\nconst type = String(input.type || 'chat').toLowerCase();\nconst folderMap = {meeting:'Meetings', call:'Meetings', zoom:'Meetings', teams:'Meetings', decision:'Decisions', runbook:'Runbooks', project:'Projects', resource:'Resources', daily:'Daily'};\nconst folder = folderMap[type] || 'Inbox/Chat Summaries';\nfunction clean(s){ return String(s||'Untitled Summary').replace(/[\\\\/:*?\"<>|#\\[\\]]/g,'').replace(/\\s+/g,' ').trim().slice(0,120) || 'Untitled Summary'; }\nconst title = clean(input.title || input.subject || `${type} summary`);\nconst summary = input.summary || input.text || input.content || '';\nconst content = input.markdown || input.content || summary;\nconst tags = Array.isArray(input.tags) ? input.tags : String(input.tags || '').split(',').map(s=>s.trim()).filter(Boolean);\nconst body = `---\ntitle: ${JSON.stringify(title)}\ntype: ${JSON.stringify(type)}\nsource: ${JSON.stringify(input.source || input.platform || 'webhook')}\ncreated: ${JSON.stringify(iso)}\ntags: ${JSON.stringify(['automation/n8n','chat-summary',...tags])}\n---\n\n# ${title}\n\n## Summary\n\n${summary || '_No summary provided._'}\n\n## Notes\n\n${content || '_No content provided._'}\n\n## Metadata\n\n\\`\\`\\`json\n${JSON.stringify(input.metadata || {}, null, 2)}\n\\`\\`\\`\n`;\nreturn [{json:{path:`${folder}/${date} - ${title}.md`, body, title, folder, type}}];\n"},"id":"e80e092c-4fc4-4159-ac7c-fc570ef1c761","name":"Prepare Chat Note","type":"n8n-nodes-base.code","typeVersion":2,"position":[280,0]},{"parameters":{"method":"PUT","url":"={{'http://172.19.0.1:27123/vault/' + encodeURIComponent($json.path).replace(/%2F/g, '/')}}","sendHeaders":true,"headerParameters":{"parameters":[{"name":"Content-Type","value":"text/markdown"}]},"sendBody":true,"contentType":"raw","rawContentType":"text/markdown","body":"={{$json.body}}","options":{"timeout":30000},"authentication":"genericCredentialType","genericAuthType":"httpHeaderAuth"},"id":"a616c85b-9898-42bc-866f-077037c07a41","name":"Write Chat Note","type":"n8n-nodes-base.httpRequest","typeVersion":4.2,"position":[560,0],"credentials":{"httpHeaderAuth":{"id":"465Swz2b71O2KRAK","name":"Obsidian Local REST API"}}},{"parameters":{"respondWith":"json","responseBody":"={{JSON.stringify({ok:true, path:$('Prepare Chat Note').first().json.path, title:$('Prepare Chat Note').first().json.title, folder:$('Prepare Chat Note').first().json.folder})}}","options":{}},"id":"6944cd52-8614-4658-8907-b54a44fc01fa","name":"Respond","type":"n8n-nodes-base.respondToWebhook","typeVersion":1.1,"position":[840,0]}],"connections":{"Webhook - Chat Summary":{"main":[[{"node":"Prepare Chat Note","type":"main","index":0}]]},"Prepare Chat Note":{"main":[[{"node":"Write Chat Note","type":"main","index":0}]]},"Write Chat Note":{"main":[[{"node":"Respond","type":"main","index":0}]]}},"settings":{"executionOrder":"v1","callerPolicy":"workflowsFromSameOwner","availableInMCP":false},"staticData":null,"meta":null,"pinData":null,"versionId":"49e05c18-c8d6-4eac-b507-1833840d57fe","activeVersionId":"49e05c18-c8d6-4eac-b507-1833840d57fe","versionCounter":3,"triggerCount":1,"tags":[],"shared":[{"updatedAt":"2026-05-14T21:36:33.223Z","createdAt":"2026-05-14T21:36:33.223Z","role":"workflow:owner","workflowId":"LF3i86l3NkxpayxL","projectId":"WGdp8QunI1tHpjXa","project":{"updatedAt":"2026-03-11T21:08:10.005Z","createdAt":"2026-03-11T21:05:11.541Z","id":"WGdp8QunI1tHpjXa","name":"will will ","type":"personal","icon":null,"description":null,"creatorId":"5ad50ead-6e6a-4d12-ab5b-e5db15835bb5"}}],"versionMetadata":{"name":null,"description":null}}] \ No newline at end of file diff --git a/swarm-common/n8n-workflows/obsidian-Ori3Bu5u5ODtxxyD.json b/swarm-common/n8n-workflows/obsidian-Ori3Bu5u5ODtxxyD.json new file mode 100644 index 0000000..c37ad27 --- /dev/null +++ b/swarm-common/n8n-workflows/obsidian-Ori3Bu5u5ODtxxyD.json @@ -0,0 +1 @@ +[{"updatedAt":"2026-05-14T21:36:33.279Z","createdAt":"2026-05-14T21:36:33.279Z","id":"Ori3Bu5u5ODtxxyD","name":"Obsidian URL to Note","description":null,"active":true,"isArchived":false,"nodes":[{"parameters":{"httpMethod":"POST","path":"obsidian-url-to-note","responseMode":"responseNode","options":{}},"id":"70c67af3-3642-404e-bca9-8024f1ae2c4f","name":"Webhook - URL to Note","type":"n8n-nodes-base.webhook","typeVersion":2,"position":[0,0],"webhookId":"obsidian-url-to-note"},{"parameters":{"jsCode":"\nconst input = $json.body ?? $json;\nconst url = String(input.url || input.link || '').trim();\nif (!/^https?:\\/\\//i.test(url)) throw new Error('POST JSON must include url starting with http:// or https://');\nreturn [{json:{url, folder: input.folder || 'Resources/Web Clips', tags: Array.isArray(input.tags)?input.tags:[], notes: input.notes || input.note || ''}}];\n"},"id":"9de66ad1-e538-455d-890a-be9b75a769d1","name":"Validate URL","type":"n8n-nodes-base.code","typeVersion":2,"position":[240,0]},{"parameters":{"method":"POST","url":"http://172.19.0.1:18812/extract","sendBody":true,"specifyBody":"json","jsonBody":"={{JSON.stringify({url:$json.url})}}","options":{"timeout":120000}},"id":"78ac965f-38c0-4821-b0ac-9a22a3b4d034","name":"Extract Content","type":"n8n-nodes-base.httpRequest","typeVersion":4.2,"position":[500,0]},{"parameters":{"jsCode":"\nconst original = $('Validate URL').first().json;\nconst ex = $json;\nconst title = ex.title || ex.metadata?.title || original.url;\nconst text = String(ex.markdown || ex.content || ex.text || ex.article || JSON.stringify(ex)).slice(0,60000);\nreturn [{json:{...original, extractedTitle:title, extractedText:text}}];\n"},"id":"51b95641-61c9-4d5e-8d1c-1b166f0a7dc0","name":"Prepare LLM Input","type":"n8n-nodes-base.code","typeVersion":2,"position":[760,0]},{"parameters":{"method":"POST","url":"http://172.19.0.1:18806/v1/chat/completions","sendBody":true,"specifyBody":"json","jsonBody":"={JSON.stringify({model:\"gemma-4-26B-A4B-it-UD-IQ2_M.gguf\", temperature:0.2, max_tokens:2048, messages:[{role:'system', content:'Convert extracted web content into concise Obsidian resource notes. Return only valid JSON with keys: title, summary, key_points, tags, note.'}, {role:'user', content:'URL: '+$json.url+'\\nTitle: '+$json.extractedTitle+'\\n\\nContent:\\n'+$json.extractedText}]})}","options":{"timeout":240000}},"id":"57f10533-1217-4486-bc79-33343782f54c","name":"Summarize with Local LLM","type":"n8n-nodes-base.httpRequest","typeVersion":4.2,"position":[1020,0],"continueOnFail":true},{"parameters":{"jsCode":"\nconst original = $('Prepare LLM Input').first().json;\nlet content = $json.choices?.[0]?.message?.content || '';\ncontent = String(content).replace(/^```json\\s*/i,'').replace(/^```\\s*/i,'').replace(/```$/,'').trim();\nlet parsed; try { parsed = JSON.parse(content); } catch(e) { parsed = {title: original.extractedTitle, summary: content || 'Summary unavailable.', key_points: [], note: original.extractedText.slice(0,8000), tags: []}; }\nfunction clean(s){ return String(s||'Untitled Resource').replace(/[\\\\/:*?\"<>|#\\[\\]]/g,'').replace(/\\s+/g,' ').trim().slice(0,120) || 'Untitled Resource'; }\nconst now = new Date(); const iso = now.toISOString(); const date = iso.slice(0,10);\nconst title = clean(parsed.title || original.extractedTitle);\nconst tags = Array.from(new Set(['automation/n8n','resource','web-clip',...(original.tags||[]),...(parsed.tags||[])]));\nconst points = Array.isArray(parsed.key_points) ? parsed.key_points.map(p=>`- ${p}`).join('\\n') : String(parsed.key_points||'');\nconst body = `---\ntitle: ${JSON.stringify(title)}\ntype: resource\nsource: ${JSON.stringify(original.url)}\ncreated: ${JSON.stringify(iso)}\ntags: ${JSON.stringify(tags)}\n---\n\n# ${title}\n\nSource: ${original.url}\n\n## Summary\n\n${parsed.summary || '_No summary generated._'}\n\n## Key points\n\n${points || '_No key points generated._'}\n\n## Notes\n\n${original.notes || ''}\n\n## Extracted note\n\n${parsed.note || ''}\n`;\nreturn [{json:{path:`${original.folder}/${date} - ${title}.md`, body, title, url: original.url}}];\n"},"id":"0e9af8e2-5ab0-4eac-9bd1-5578f946814f","name":"Build Resource Note","type":"n8n-nodes-base.code","typeVersion":2,"position":[1280,0]},{"parameters":{"method":"PUT","url":"={{'http://172.19.0.1:27123/vault/' + encodeURIComponent($json.path).replace(/%2F/g, '/')}}","sendHeaders":true,"headerParameters":{"parameters":[{"name":"Content-Type","value":"text/markdown"}]},"sendBody":true,"contentType":"raw","rawContentType":"text/markdown","body":"={{$json.body}}","options":{"timeout":30000},"authentication":"genericCredentialType","genericAuthType":"httpHeaderAuth"},"id":"725068d4-175e-462b-9050-fd42b229f8df","name":"Write Resource Note","type":"n8n-nodes-base.httpRequest","typeVersion":4.2,"position":[1540,0],"credentials":{"httpHeaderAuth":{"id":"465Swz2b71O2KRAK","name":"Obsidian Local REST API"}}},{"parameters":{"respondWith":"json","responseBody":"={{JSON.stringify({ok:true,path:$('Build Resource Note').first().json.path,title:$('Build Resource Note').first().json.title,url:$('Build Resource Note').first().json.url})}}","options":{}},"id":"d07a2d9e-b9e3-455a-bcdf-2604ab6db3a9","name":"Respond","type":"n8n-nodes-base.respondToWebhook","typeVersion":1.1,"position":[1800,0]}],"connections":{"Webhook - URL to Note":{"main":[[{"node":"Validate URL","type":"main","index":0}]]},"Validate URL":{"main":[[{"node":"Extract Content","type":"main","index":0}]]},"Extract Content":{"main":[[{"node":"Prepare LLM Input","type":"main","index":0}]]},"Prepare LLM Input":{"main":[[{"node":"Summarize with Local LLM","type":"main","index":0}]]},"Summarize with Local LLM":{"main":[[{"node":"Build Resource Note","type":"main","index":0}]]},"Build Resource Note":{"main":[[{"node":"Write Resource Note","type":"main","index":0}]]},"Write Resource Note":{"main":[[{"node":"Respond","type":"main","index":0}]]}},"settings":{"executionOrder":"v1","callerPolicy":"workflowsFromSameOwner","availableInMCP":false},"staticData":null,"meta":null,"pinData":null,"versionId":"70bd9e5f-b04f-4ba1-b6d1-82cfece2bc2f","activeVersionId":"70bd9e5f-b04f-4ba1-b6d1-82cfece2bc2f","versionCounter":3,"triggerCount":1,"tags":[],"shared":[{"updatedAt":"2026-05-14T21:36:33.285Z","createdAt":"2026-05-14T21:36:33.285Z","role":"workflow:owner","workflowId":"Ori3Bu5u5ODtxxyD","projectId":"WGdp8QunI1tHpjXa","project":{"updatedAt":"2026-03-11T21:08:10.005Z","createdAt":"2026-03-11T21:05:11.541Z","id":"WGdp8QunI1tHpjXa","name":"will will ","type":"personal","icon":null,"description":null,"creatorId":"5ad50ead-6e6a-4d12-ab5b-e5db15835bb5"}}],"versionMetadata":{"name":null,"description":null}}] \ No newline at end of file diff --git a/swarm-common/n8n-workflows/obsidian-PCtD3PuQjzKLyEEE.json b/swarm-common/n8n-workflows/obsidian-PCtD3PuQjzKLyEEE.json new file mode 100644 index 0000000..1bd5788 --- /dev/null +++ b/swarm-common/n8n-workflows/obsidian-PCtD3PuQjzKLyEEE.json @@ -0,0 +1 @@ +[{"updatedAt":"2026-05-14T21:36:33.045Z","createdAt":"2026-05-14T21:36:33.045Z","id":"PCtD3PuQjzKLyEEE","name":"Obsidian Health + Reindex","description":null,"active":true,"isArchived":false,"nodes":[{"parameters":{},"id":"f9152036-4ee6-48cf-9f71-fd59ce617c52","name":"Manual Trigger","type":"n8n-nodes-base.manualTrigger","typeVersion":1,"position":[0,0]},{"parameters":{"rule":{"interval":[{"field":"hours","hoursInterval":1}]}},"id":"7845e784-c35b-4912-9d72-2463a06d95d2","name":"Hourly Health Schedule","type":"n8n-nodes-base.scheduleTrigger","typeVersion":1.2,"position":[0,180]},{"parameters":{"url":"http://172.19.0.1:27123/","options":{"timeout":10000}},"id":"4976f00c-3539-4d3a-a87d-f7f3ac1adf19","name":"Check Obsidian REST","type":"n8n-nodes-base.httpRequest","typeVersion":4.2,"position":[280,80],"continueOnFail":true},{"parameters":{"method":"POST","url":"http://172.19.0.1:18810/reindex","options":{"timeout":300000}},"id":"8abf0596-3af6-4d56-b4d0-5284f13998ae","name":"Trigger Obsidian Reindex","type":"n8n-nodes-base.httpRequest","typeVersion":4.2,"position":[560,80],"continueOnFail":true},{"parameters":{"method":"POST","url":"http://172.19.0.1:18814/check","options":{"timeout":240000}},"id":"248b4109-2d60-43bc-b598-cb766edde11f","name":"Run RAG Embedding Check","type":"n8n-nodes-base.httpRequest","typeVersion":4.2,"position":[840,80],"continueOnFail":true},{"parameters":{"jsCode":"\nconst now = new Date().toISOString();\nconst reindex = $('Trigger Obsidian Reindex').first().json;\nconst rag = $('Run RAG Embedding Check').first().json;\nconst rest = $('Check Obsidian REST').first().json;\nconst ok = Boolean(rest.status === 'OK' || rest.manifest || rest.statusCode) && Boolean(rag.ok !== false) && Boolean(reindex.ok !== false);\nconst body = `# Obsidian Automation Health\n\nUpdated: ${now}\n\n## Status\n\n- Overall: ${ok ? 'OK' : 'Needs attention'}\n- Obsidian REST: ${rest.status || rest.statusCode || 'responded'}\n- Reindex trigger: ${JSON.stringify(reindex).slice(0, 500)}\n- RAG/embedding check: ${JSON.stringify(rag).slice(0, 1000)}\n\nThis note is automatically overwritten by n8n.\n`;\nreturn [{ json: { ok, path: 'Resources/Obsidian Automation Health.md', body } }];\n"},"id":"e67008ad-0d9e-4546-a180-3d4223b8d05c","name":"Build Health Note","type":"n8n-nodes-base.code","typeVersion":2,"position":[1120,80]},{"parameters":{"method":"PUT","url":"={{'http://172.19.0.1:27123/vault/' + encodeURIComponent($json.path).replace(/%2F/g, '/')}}","sendHeaders":true,"headerParameters":{"parameters":[{"name":"Content-Type","value":"text/markdown"}]},"sendBody":true,"contentType":"raw","rawContentType":"text/markdown","body":"={{$json.body}}","options":{"timeout":30000},"authentication":"genericCredentialType","genericAuthType":"httpHeaderAuth"},"id":"d86d8942-966a-48fd-ad99-cf23408f2ae4","name":"Write Health Note","type":"n8n-nodes-base.httpRequest","typeVersion":4.2,"position":[1400,80],"credentials":{"httpHeaderAuth":{"id":"465Swz2b71O2KRAK","name":"Obsidian Local REST API"}}}],"connections":{"Manual Trigger":{"main":[[{"node":"Check Obsidian REST","type":"main","index":0}]]},"Hourly Health Schedule":{"main":[[{"node":"Check Obsidian REST","type":"main","index":0}]]},"Check Obsidian REST":{"main":[[{"node":"Trigger Obsidian Reindex","type":"main","index":0}]]},"Trigger Obsidian Reindex":{"main":[[{"node":"Run RAG Embedding Check","type":"main","index":0}]]},"Run RAG Embedding Check":{"main":[[{"node":"Build Health Note","type":"main","index":0}]]},"Build Health Note":{"main":[[{"node":"Write Health Note","type":"main","index":0}]]}},"settings":{"executionOrder":"v1","callerPolicy":"workflowsFromSameOwner","availableInMCP":false},"staticData":{"node:Hourly Health Schedule":{"recurrenceRules":[]}},"meta":null,"pinData":null,"versionId":"2de2a0d3-ab17-47b5-b2ee-a9c5c20969cd","activeVersionId":"2de2a0d3-ab17-47b5-b2ee-a9c5c20969cd","versionCounter":4,"triggerCount":1,"tags":[],"shared":[{"updatedAt":"2026-05-14T21:36:33.056Z","createdAt":"2026-05-14T21:36:33.056Z","role":"workflow:owner","workflowId":"PCtD3PuQjzKLyEEE","projectId":"WGdp8QunI1tHpjXa","project":{"updatedAt":"2026-03-11T21:08:10.005Z","createdAt":"2026-03-11T21:05:11.541Z","id":"WGdp8QunI1tHpjXa","name":"will will ","type":"personal","icon":null,"description":null,"creatorId":"5ad50ead-6e6a-4d12-ab5b-e5db15835bb5"}}],"versionMetadata":{"name":null,"description":null}}] \ No newline at end of file diff --git a/swarm-common/n8n-workflows/obsidian-UWLMOQQVxbTX6Sis.json b/swarm-common/n8n-workflows/obsidian-UWLMOQQVxbTX6Sis.json new file mode 100644 index 0000000..2a02eac --- /dev/null +++ b/swarm-common/n8n-workflows/obsidian-UWLMOQQVxbTX6Sis.json @@ -0,0 +1 @@ +[{"updatedAt":"2026-05-14T21:36:33.337Z","createdAt":"2026-05-14T21:36:33.337Z","id":"UWLMOQQVxbTX6Sis","name":"Obsidian Weekly Decision Runbook Extractor","description":null,"active":true,"isArchived":false,"nodes":[{"parameters":{},"id":"f0b1fc1f-e1d9-4529-a1a2-b04bb942472f","name":"Manual Trigger","type":"n8n-nodes-base.manualTrigger","typeVersion":1,"position":[0,0]},{"parameters":{"rule":{"interval":[{"field":"weeks","triggerAtDay":[1],"triggerAtHour":8,"triggerAtMinute":0}]}},"id":"259798b5-2bff-4ec3-8b75-39353c053576","name":"Weekly Monday 08:00 PT","type":"n8n-nodes-base.scheduleTrigger","typeVersion":1.2,"position":[0,180]},{"parameters":{"jsCode":"\nreturn ['we decided','decision','runbook','procedure','rollback','workaround','root cause','next time'].map(query => ({json:{query}}));\n"},"id":"b8e28ca5-1d19-4e53-97c2-c3b1c88b2102","name":"Build Search Queries","type":"n8n-nodes-base.code","typeVersion":2,"position":[280,80]},{"parameters":{"method":"POST","url":"={{'http://172.19.0.1:27123/search/simple/?query=' + encodeURIComponent($json.query) + '&contextLength=300'}}","options":{"timeout":30000},"authentication":"genericCredentialType","genericAuthType":"httpHeaderAuth"},"id":"ef1d4e75-5a9d-42bf-8c46-646b94c16da3","name":"Search Obsidian","type":"n8n-nodes-base.httpRequest","typeVersion":4.2,"position":[560,80],"credentials":{"httpHeaderAuth":{"id":"465Swz2b71O2KRAK","name":"Obsidian Local REST API"}},"continueOnFail":true},{"parameters":{"jsCode":"\nconst now = new Date(); const date = now.toISOString().slice(0,10);\nconst rows=[];\nfor (const item of $input.all()) {\n const arr = Array.isArray(item.json) ? item.json : (Array.isArray(item.json.body) ? item.json.body : (Array.isArray(item.json.results) ? item.json.results : []));\n for (const r of arr) {\n const filename = r.filename || r.path || 'Unknown';\n const matches = Array.isArray(r.matches) ? r.matches : [];\n for (const m of matches) rows.push({filename, context:String(m.context||'').replace(/\\s+/g,' ').trim()});\n }\n}\nconst seen = new Set();\nconst uniq = rows.filter(r => { const k=r.filename+'|'+r.context.slice(0,100); if (seen.has(k)) return false; seen.add(k); return true; }).slice(0,60);\nconst decisionRe = /\\b(decision|decided|choose|chosen|because|tradeoff|approved|rejected)\\b/i;\nconst runbookRe = /\\b(runbook|procedure|steps|incident|fix|workaround|deploy|rollback|recovery|restart|root cause|next time)\\b/i;\nfunction section(title, arr, kind){\n if (!arr.length) return `## ${title}\\n\\n_No candidates found._\\n`;\n return `## ${title}\\n\\n` + arr.slice(0,20).map((r,i)=>`### ${i+1}. ${r.filename}\\n\\n- Suggested action: create/update a ${kind}.\\n- Source: [[${r.filename.replace(/\\.md$/,'')}]]\\n- Evidence: ${r.context.slice(0,700)}\\n`).join('\\n');\n}\nconst decisions=uniq.filter(r=>decisionRe.test(r.context));\nconst runbooks=uniq.filter(r=>runbookRe.test(r.context));\nconst body = `# Decision / Runbook Suggestions ${date}\\n\\nGenerated: ${now.toISOString()}\\n\\nReview candidates and promote useful items into durable Decision or Runbook notes. This note is overwritten weekly.\\n\\n${section('Decision Candidates', decisions, 'Decision note')}\\n\\n${section('Runbook Candidates', runbooks, 'Runbook note')}\\n\\n## Raw Summary\\n\\n- Total candidates: ${uniq.length}\\n- Decision candidates: ${decisions.length}\\n- Runbook candidates: ${runbooks.length}\\n`;\nreturn [{json:{path:'Decisions/Runbook Suggestions.md', body, total:uniq.length}}];\n","mode":"runOnceForAllItems"},"id":"6862ae15-2c5d-4805-9009-b3e72861be8e","name":"Build Suggestions Note","type":"n8n-nodes-base.code","typeVersion":2,"position":[840,80]},{"parameters":{"method":"PUT","url":"={{'http://172.19.0.1:27123/vault/' + encodeURIComponent($json.path).replace(/%2F/g, '/')}}","sendHeaders":true,"headerParameters":{"parameters":[{"name":"Content-Type","value":"text/markdown"}]},"sendBody":true,"contentType":"raw","rawContentType":"text/markdown","body":"={{$json.body}}","options":{"timeout":30000},"authentication":"genericCredentialType","genericAuthType":"httpHeaderAuth"},"id":"cbab2fb9-c980-4c92-8450-f36885727a86","name":"Write Suggestions Note","type":"n8n-nodes-base.httpRequest","typeVersion":4.2,"position":[1120,80],"credentials":{"httpHeaderAuth":{"id":"465Swz2b71O2KRAK","name":"Obsidian Local REST API"}}}],"connections":{"Manual Trigger":{"main":[[{"node":"Build Search Queries","type":"main","index":0}]]},"Weekly Monday 08:00 PT":{"main":[[{"node":"Build Search Queries","type":"main","index":0}]]},"Build Search Queries":{"main":[[{"node":"Search Obsidian","type":"main","index":0}]]},"Search Obsidian":{"main":[[{"node":"Build Suggestions Note","type":"main","index":0}]]},"Build Suggestions Note":{"main":[[{"node":"Write Suggestions Note","type":"main","index":0}]]}},"settings":{"executionOrder":"v1","callerPolicy":"workflowsFromSameOwner","availableInMCP":false},"staticData":{"node:Weekly Monday 08:00 PT":{"recurrenceRules":[]}},"meta":null,"pinData":null,"versionId":"d8e576e0-22e5-455a-95ce-1f20b443cc61","activeVersionId":"d8e576e0-22e5-455a-95ce-1f20b443cc61","versionCounter":4,"triggerCount":1,"tags":[],"shared":[{"updatedAt":"2026-05-14T21:36:33.340Z","createdAt":"2026-05-14T21:36:33.340Z","role":"workflow:owner","workflowId":"UWLMOQQVxbTX6Sis","projectId":"WGdp8QunI1tHpjXa","project":{"updatedAt":"2026-03-11T21:08:10.005Z","createdAt":"2026-03-11T21:05:11.541Z","id":"WGdp8QunI1tHpjXa","name":"will will ","type":"personal","icon":null,"description":null,"creatorId":"5ad50ead-6e6a-4d12-ab5b-e5db15835bb5"}}],"versionMetadata":{"name":null,"description":null}}] \ No newline at end of file diff --git a/swarm-common/n8n-workflows/obsidian-YZyJ5G0Ur8D6TlM8.json b/swarm-common/n8n-workflows/obsidian-YZyJ5G0Ur8D6TlM8.json new file mode 100644 index 0000000..f1d1a35 --- /dev/null +++ b/swarm-common/n8n-workflows/obsidian-YZyJ5G0Ur8D6TlM8.json @@ -0,0 +1 @@ +[{"updatedAt":"2026-05-14T21:36:33.117Z","createdAt":"2026-05-14T21:36:33.117Z","id":"YZyJ5G0Ur8D6TlM8","name":"Obsidian Daily Review","description":null,"active":true,"isArchived":false,"nodes":[{"parameters":{},"id":"01121020-b53b-4f27-8ad2-f6e1ddb656c4","name":"Manual Trigger","type":"n8n-nodes-base.manualTrigger","typeVersion":1,"position":[0,0]},{"parameters":{"rule":{"interval":[{"field":"cronExpression","expression":"30 7 * * *"}]}},"id":"4d6ec3bb-2953-43a8-bbed-e9a54199622d","name":"Daily 07:30 PT","type":"n8n-nodes-base.scheduleTrigger","typeVersion":1.2,"position":[0,180]},{"parameters":{"jsCode":"\nconst now = new Date();\nconst date = now.toISOString().slice(0,10);\nconst body = `---\ntype: daily-review\ndate: ${date}\ntags: [type/daily-review, automation/n8n]\n---\n\n# Daily Review ${date}\n\n## Top priorities\n\n- [ ] \n- [ ] \n- [ ] \n\n## Inbox sweep\n\n- [ ] Review [[Inbox]]\n- [ ] Promote useful captures into [[Projects Home]], [[Resources Home]], [[Decisions Home]], or [[Runbooks Home]]\n\n## Open loops\n\n- [ ] Check [[Projects Home]]\n- [ ] Check [[Meetings Home]] action items\n- [ ] Check [[Runbooks Home]] for procedures that need updates\n\n## Notes / log\n\n- \n\n## End-of-day reflection\n\n- What moved forward?\n- What is blocked?\n- What should start tomorrow?\n`;\nreturn [{ json: { path: `Daily/Reviews/${date} Daily Review.md`, body } }];\n"},"id":"8ffb36c5-de40-4811-8f92-61d9dde9982c","name":"Build Daily Review","type":"n8n-nodes-base.code","typeVersion":2,"position":[280,80]},{"parameters":{"method":"PUT","url":"={{'http://172.19.0.1:27123/vault/' + encodeURIComponent($json.path).replace(/%2F/g, '/')}}","sendHeaders":true,"headerParameters":{"parameters":[{"name":"Content-Type","value":"text/markdown"}]},"sendBody":true,"contentType":"raw","rawContentType":"text/markdown","body":"={{$json.body}}","options":{"timeout":30000},"authentication":"genericCredentialType","genericAuthType":"httpHeaderAuth"},"id":"5e2226bb-3c34-4f17-b968-039ddc1dfe35","name":"Write Daily Review","type":"n8n-nodes-base.httpRequest","typeVersion":4.2,"position":[560,80],"credentials":{"httpHeaderAuth":{"id":"465Swz2b71O2KRAK","name":"Obsidian Local REST API"}}}],"connections":{"Manual Trigger":{"main":[[{"node":"Build Daily Review","type":"main","index":0}]]},"Daily 07:30 PT":{"main":[[{"node":"Build Daily Review","type":"main","index":0}]]},"Build Daily Review":{"main":[[{"node":"Write Daily Review","type":"main","index":0}]]}},"settings":{"executionOrder":"v1","callerPolicy":"workflowsFromSameOwner","availableInMCP":false},"staticData":{"node:Daily 07:30 PT":{"recurrenceRules":[]}},"meta":null,"pinData":null,"versionId":"2d2a2217-4772-42eb-80ce-622ed419d209","activeVersionId":"2d2a2217-4772-42eb-80ce-622ed419d209","versionCounter":4,"triggerCount":1,"tags":[],"shared":[{"updatedAt":"2026-05-14T21:36:33.120Z","createdAt":"2026-05-14T21:36:33.120Z","role":"workflow:owner","workflowId":"YZyJ5G0Ur8D6TlM8","projectId":"WGdp8QunI1tHpjXa","project":{"updatedAt":"2026-03-11T21:08:10.005Z","createdAt":"2026-03-11T21:05:11.541Z","id":"WGdp8QunI1tHpjXa","name":"will will ","type":"personal","icon":null,"description":null,"creatorId":"5ad50ead-6e6a-4d12-ab5b-e5db15835bb5"}}],"versionMetadata":{"name":null,"description":null}}] \ No newline at end of file