873 lines
30 KiB
JSON
873 lines
30 KiB
JSON
{
|
|
"updatedAt": "2026-05-14T00:04:59.343Z",
|
|
"createdAt": "2026-05-13T21:40:33.847Z",
|
|
"id": "PlZywwqL8MRNEAN6",
|
|
"name": "Evening Digest",
|
|
"description": null,
|
|
"active": true,
|
|
"isArchived": false,
|
|
"nodes": [
|
|
{
|
|
"parameters": {
|
|
"rule": {
|
|
"interval": [
|
|
{
|
|
"field": "cronExpression",
|
|
"expression": "0 21 * * *"
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"id": "a1b2c3d4-0001-4000-8000-000000000001",
|
|
"name": "Daily 9PM Schedule",
|
|
"type": "n8n-nodes-base.scheduleTrigger",
|
|
"typeVersion": 1.2,
|
|
"position": [
|
|
0,
|
|
0
|
|
],
|
|
"onError": "continueRegularOutput"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "GET",
|
|
"url": "http://127.0.0.1:5678/api/v1/executions?status=success&limit=100",
|
|
"authentication": "genericCredentialType",
|
|
"genericAuthType": "httpHeaderAuth",
|
|
"options": {
|
|
"response": {
|
|
"response": {
|
|
"responseFormat": "json"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"id": "a1b2c3d4-0001-4000-8000-000000000002",
|
|
"name": "n8n Success Executions",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.2,
|
|
"position": [
|
|
240,
|
|
-200
|
|
],
|
|
"onError": "continueRegularOutput",
|
|
"credentials": {
|
|
"httpHeaderAuth": {
|
|
"id": "UPAHgUJVRqZQceL4",
|
|
"name": "n8n Public API (Failure Digest)"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "GET",
|
|
"url": "http://127.0.0.1:5678/api/v1/executions?status=error&limit=50",
|
|
"authentication": "genericCredentialType",
|
|
"genericAuthType": "httpHeaderAuth",
|
|
"options": {
|
|
"response": {
|
|
"response": {
|
|
"responseFormat": "json"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"id": "a1b2c3d4-0001-4000-8000-000000000003",
|
|
"name": "n8n Failed Executions",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.2,
|
|
"position": [
|
|
240,
|
|
0
|
|
],
|
|
"onError": "continueRegularOutput",
|
|
"credentials": {
|
|
"httpHeaderAuth": {
|
|
"id": "UPAHgUJVRqZQceL4",
|
|
"name": "n8n Public API (Failure Digest)"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "GET",
|
|
"url": "http://172.19.0.1:18809/health",
|
|
"options": {
|
|
"response": {
|
|
"response": {
|
|
"responseFormat": "json"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"id": "a1b2c3d4-0001-4000-8000-000000000004",
|
|
"name": "Swarm Health",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.2,
|
|
"position": [
|
|
240,
|
|
200
|
|
],
|
|
"onError": "continueRegularOutput"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "GET",
|
|
"url": "http://172.19.0.1:27123/vault/Notes/",
|
|
"authentication": "genericCredentialType",
|
|
"genericAuthType": "httpHeaderAuth",
|
|
"options": {
|
|
"response": {
|
|
"response": {
|
|
"responseFormat": "json"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"id": "a1b2c3d4-0001-4000-8000-000000000005",
|
|
"name": "New Obsidian Notes",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.2,
|
|
"position": [
|
|
240,
|
|
400
|
|
],
|
|
"onError": "continueRegularOutput",
|
|
"credentials": {
|
|
"httpHeaderAuth": {
|
|
"id": "465Swz2b71O2KRAK",
|
|
"name": "Obsidian Local REST API"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"mode": "runOnceForAllItems",
|
|
"jsCode": "// Aggregate all collection results into a structured summary\nconst data = {};\n\n// Process successful executions\ntry {\n const successItems = $input.first()?.json?.data || [];\n const successByWorkflow = {};\n let totalSuccess = 0;\n for (const item of successItems) {\n const wfName = item.workflowData?.name || item.workflowId || 'Unknown';\n successByWorkflow[wfName] = (successByWorkflow[wfName] || 0) + 1;\n totalSuccess++;\n }\n data.successExecutions = { total: totalSuccess, byWorkflow: successByWorkflow };\n} catch(e) {\n data.successExecutions = { total: 0, byWorkflow: {}, error: e.message };\n}\n\n// Process failed executions\ntry {\n // Failed executions come from a separate input\n const failNode = $node['n8n Failed Executions']?.json;\n const failItems = failNode?.data || [];\n const failures = [];\n let totalFail = 0;\n for (const item of failItems) {\n const wfName = item.workflowData?.name || item.workflowId || 'Unknown';\n failures.push({\n workflow: wfName,\n id: item.id,\n stoppedAt: item.stoppedAt\n });\n totalFail++;\n }\n data.failedExecutions = { total: totalFail, failures: failures };\n} catch(e) {\n data.failedExecutions = { total: 0, failures: [], error: e.message };\n}\n\n// Swarm health\ntry {\n data.swarmHealth = $node['Swarm Health']?.json || { status: 'unavailable' };\n} catch(e) {\n data.swarmHealth = { status: 'error', error: e.message };\n}\n\n// New Obsidian notes\ntry {\n const obsResult = $node['New Obsidian Notes']?.json;\n const allFiles = obsResult?.files || [];\n // Filter for today's date in filename\n const today = new Intl.DateTimeFormat('en-CA', {\n timeZone: 'America/Los_Angeles',\n year: 'numeric', month: '2-digit', day: '2-digit'\n }).format(new Date()).replaceAll('/', '-');\n const todayFiles = allFiles.filter(f => {\n const name = typeof f === 'string' ? f : (f.name || f.path || '');\n return name.includes(today);\n });\n data.newNotes = todayFiles.map(f => typeof f === 'string' ? f : (f.name || f.path || JSON.stringify(f)));\n} catch(e) {\n data.newNotes = [];\n data.notesError = e.message;\n}\n\ndata.date = new Intl.DateTimeFormat('en-CA', {\n timeZone: 'America/Los_Angeles',\n year: 'numeric', month: '2-digit', day: '2-digit'\n}).format(new Date()).replaceAll('/', '-');\n\ndata.summary = JSON.stringify(data, null, 2);\n\nreturn [{ json: data }];"
|
|
},
|
|
"id": "a1b2c3d4-0001-4000-8000-000000000006",
|
|
"name": "Aggregate Data",
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
500,
|
|
100
|
|
],
|
|
"onError": "continueRegularOutput"
|
|
},
|
|
{
|
|
"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.3, max_tokens: 800, messages: [{ role: 'system', content: 'You are an evening digest assistant. Given data about today\\'s automation runs, failures, new notes, and infrastructure health, produce a concise evening digest under 400 words. Use emojis for section headers. Format for Telegram/Markdown. Sections: 🔧 Executions Summary, ⚠️ Failures, 📝 New Notes, 🏥 Infrastructure Health, 📋 Action Items. Be factual and concise.' }, { role: 'user', content: 'Here is today\\'s data:\\n' + $json.summary }] }) }}",
|
|
"options": {
|
|
"response": {
|
|
"response": {
|
|
"responseFormat": "json"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"id": "a1b2c3d4-0001-4000-8000-000000000007",
|
|
"name": "LLM Synthesis",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.2,
|
|
"position": [
|
|
740,
|
|
100
|
|
],
|
|
"onError": "continueRegularOutput"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"mode": "runOnceForAllItems",
|
|
"jsCode": "// Extract LLM response text and prepare messages for Telegram/Discord/Obsidian\nlet text = '';\ntry {\n const llmResponse = $input.first()?.json;\n text = llmResponse?.choices?.[0]?.message?.content || '';\n // Strip code fences if present\n text = text.replace(/^```(?:markdown)?\\s*/i, '').replace(/```\\s*$/i, '').trim();\n} catch(e) {\n text = 'Evening digest generation encountered an error.';\n}\n\nif (!text) {\n text = '🌙 Evening Digest\\n\\nNo data collected today. All collection nodes may have failed.';\n}\n\n// Escape special chars for Telegram MarkdownV1\nlet telegramText = text;\n// Replace problematic markdown chars for Telegram\ntelegramText = telegramText.replace(/([_*\\[\\]()~`>#+\\-=|{}.!])/g, (m) => {\n // Keep basic markdown formatting\n if (['*', '_', '`'].includes(m)) return m;\n return '\\\\' + m;\n});\n\nconst today = new Intl.DateTimeFormat('en-CA', {\n timeZone: 'America/Los_Angeles',\n year: 'numeric', month: '2-digit', day: '2-digit'\n}).format(new Date()).replaceAll('/', '-');\n\nreturn [{\n json: {\n text: telegramText,\n discordText: text.substring(0, 2000),\n obsidianContent: `---\\ntitle: Evening Digest\\narea: infrastructure\\ntags: [infrastructure, digest, automation, daily, evening]\\ncreated: ${today}\\nupdated: ${today}\\nstatus: active\\n---\\n\\n# Evening Digest - ${today}\\n\\n${text}\\n`,\n notePath: `Notes/${today} Evening Digest.md`,\n date: today\n }\n}];"
|
|
},
|
|
"id": "a1b2c3d4-0001-4000-8000-000000000008",
|
|
"name": "Prepare Messages",
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
980,
|
|
100
|
|
],
|
|
"onError": "continueRegularOutput"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"chatId": "8367012007",
|
|
"text": "={{ $json.text }}",
|
|
"additionalFields": {
|
|
"parse_mode": "Markdown"
|
|
}
|
|
},
|
|
"id": "a1b2c3d4-0001-4000-8000-000000000009",
|
|
"name": "Send Telegram",
|
|
"type": "n8n-nodes-base.telegram",
|
|
"typeVersion": 1,
|
|
"position": [
|
|
1220,
|
|
-100
|
|
],
|
|
"credentials": {
|
|
"telegramApi": {
|
|
"id": "aox4dyIWVSRdcH5z",
|
|
"name": "Telegram Bot (OpenClaw)"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "POST",
|
|
"url": "https://discord.com/api/v10/channels/1494453542243532932/messages",
|
|
"authentication": "genericCredentialType",
|
|
"genericAuthType": "httpHeaderAuth",
|
|
"sendBody": true,
|
|
"specifyBody": "json",
|
|
"jsonBody": "={{ JSON.stringify({ content: $json.discordText }) }}",
|
|
"options": {
|
|
"response": {
|
|
"response": {
|
|
"responseFormat": "text"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"id": "a1b2c3d4-0001-4000-8000-000000000010",
|
|
"name": "Send Discord",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.2,
|
|
"position": [
|
|
1220,
|
|
100
|
|
],
|
|
"credentials": {
|
|
"httpHeaderAuth": {
|
|
"id": "UgPqYcoCNNIgr55m",
|
|
"name": "Discord Bot Auth"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "PUT",
|
|
"url": "={{ 'http://172.19.0.1:27123/vault/' + encodeURIComponent($json.notePath).replace(/%2F/g, '/') }}",
|
|
"authentication": "genericCredentialType",
|
|
"genericAuthType": "httpHeaderAuth",
|
|
"sendBody": true,
|
|
"specifyBody": "raw",
|
|
"rawContentType": "text/markdown",
|
|
"body": "={{ $json.obsidianContent }}",
|
|
"options": {}
|
|
},
|
|
"id": "a1b2c3d4-0001-4000-8000-000000000011",
|
|
"name": "Save to Obsidian",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.2,
|
|
"position": [
|
|
1220,
|
|
300
|
|
],
|
|
"credentials": {
|
|
"httpHeaderAuth": {
|
|
"id": "465Swz2b71O2KRAK",
|
|
"name": "Obsidian Local REST API"
|
|
}
|
|
}
|
|
}
|
|
],
|
|
"connections": {
|
|
"Daily 9PM Schedule": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "n8n Success Executions",
|
|
"type": "main",
|
|
"index": 0
|
|
},
|
|
{
|
|
"node": "n8n Failed Executions",
|
|
"type": "main",
|
|
"index": 0
|
|
},
|
|
{
|
|
"node": "Swarm Health",
|
|
"type": "main",
|
|
"index": 0
|
|
},
|
|
{
|
|
"node": "New Obsidian Notes",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"n8n Success Executions": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Aggregate Data",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"n8n Failed Executions": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Aggregate Data",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Swarm Health": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Aggregate Data",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"New Obsidian Notes": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Aggregate Data",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Aggregate Data": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "LLM Synthesis",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"LLM Synthesis": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Prepare Messages",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Prepare Messages": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Send Telegram",
|
|
"type": "main",
|
|
"index": 0
|
|
},
|
|
{
|
|
"node": "Send Discord",
|
|
"type": "main",
|
|
"index": 0
|
|
},
|
|
{
|
|
"node": "Save to Obsidian",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
}
|
|
},
|
|
"settings": {
|
|
"executionOrder": "v1",
|
|
"callerPolicy": "workflowsFromSameOwner",
|
|
"availableInMCP": false,
|
|
"timezone": "America/Los_Angeles"
|
|
},
|
|
"staticData": {
|
|
"node:Daily 9PM Schedule": {
|
|
"recurrenceRules": []
|
|
}
|
|
},
|
|
"meta": null,
|
|
"pinData": null,
|
|
"versionId": "afb71f4d-6ac3-434d-b659-de003d47c339",
|
|
"activeVersionId": "afb71f4d-6ac3-434d-b659-de003d47c339",
|
|
"versionCounter": 11,
|
|
"triggerCount": 1,
|
|
"shared": [
|
|
{
|
|
"updatedAt": "2026-05-13T21:40:33.849Z",
|
|
"createdAt": "2026-05-13T21:40:33.849Z",
|
|
"role": "workflow:owner",
|
|
"workflowId": "PlZywwqL8MRNEAN6",
|
|
"projectId": "WGdp8QunI1tHpjXa",
|
|
"project": {
|
|
"updatedAt": "2026-03-11T21:08:10.005Z",
|
|
"createdAt": "2026-03-11T21:05:11.541Z",
|
|
"id": "WGdp8QunI1tHpjXa",
|
|
"name": "will will <will@wills-portal.com>",
|
|
"type": "personal",
|
|
"icon": null,
|
|
"description": null,
|
|
"creatorId": "5ad50ead-6e6a-4d12-ab5b-e5db15835bb5"
|
|
}
|
|
}
|
|
],
|
|
"tags": [],
|
|
"activeVersion": {
|
|
"updatedAt": "2026-05-13T21:40:33.854Z",
|
|
"createdAt": "2026-05-13T21:40:33.854Z",
|
|
"versionId": "afb71f4d-6ac3-434d-b659-de003d47c339",
|
|
"workflowId": "PlZywwqL8MRNEAN6",
|
|
"nodes": [
|
|
{
|
|
"parameters": {
|
|
"rule": {
|
|
"interval": [
|
|
{
|
|
"field": "cronExpression",
|
|
"expression": "0 21 * * *"
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"id": "a1b2c3d4-0001-4000-8000-000000000001",
|
|
"name": "Daily 9PM Schedule",
|
|
"type": "n8n-nodes-base.scheduleTrigger",
|
|
"typeVersion": 1.2,
|
|
"position": [
|
|
0,
|
|
0
|
|
],
|
|
"onError": "continueRegularOutput"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "GET",
|
|
"url": "http://127.0.0.1:5678/api/v1/executions?status=success&limit=100",
|
|
"authentication": "genericCredentialType",
|
|
"genericAuthType": "httpHeaderAuth",
|
|
"options": {
|
|
"response": {
|
|
"response": {
|
|
"responseFormat": "json"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"id": "a1b2c3d4-0001-4000-8000-000000000002",
|
|
"name": "n8n Success Executions",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.2,
|
|
"position": [
|
|
240,
|
|
-200
|
|
],
|
|
"onError": "continueRegularOutput",
|
|
"credentials": {
|
|
"httpHeaderAuth": {
|
|
"id": "UPAHgUJVRqZQceL4",
|
|
"name": "n8n Public API (Failure Digest)"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "GET",
|
|
"url": "http://127.0.0.1:5678/api/v1/executions?status=error&limit=50",
|
|
"authentication": "genericCredentialType",
|
|
"genericAuthType": "httpHeaderAuth",
|
|
"options": {
|
|
"response": {
|
|
"response": {
|
|
"responseFormat": "json"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"id": "a1b2c3d4-0001-4000-8000-000000000003",
|
|
"name": "n8n Failed Executions",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.2,
|
|
"position": [
|
|
240,
|
|
0
|
|
],
|
|
"onError": "continueRegularOutput",
|
|
"credentials": {
|
|
"httpHeaderAuth": {
|
|
"id": "UPAHgUJVRqZQceL4",
|
|
"name": "n8n Public API (Failure Digest)"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "GET",
|
|
"url": "http://172.19.0.1:18809/health",
|
|
"options": {
|
|
"response": {
|
|
"response": {
|
|
"responseFormat": "json"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"id": "a1b2c3d4-0001-4000-8000-000000000004",
|
|
"name": "Swarm Health",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.2,
|
|
"position": [
|
|
240,
|
|
200
|
|
],
|
|
"onError": "continueRegularOutput"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "GET",
|
|
"url": "http://172.19.0.1:27123/vault/Notes/",
|
|
"authentication": "genericCredentialType",
|
|
"genericAuthType": "httpHeaderAuth",
|
|
"options": {
|
|
"response": {
|
|
"response": {
|
|
"responseFormat": "json"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"id": "a1b2c3d4-0001-4000-8000-000000000005",
|
|
"name": "New Obsidian Notes",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.2,
|
|
"position": [
|
|
240,
|
|
400
|
|
],
|
|
"onError": "continueRegularOutput",
|
|
"credentials": {
|
|
"httpHeaderAuth": {
|
|
"id": "465Swz2b71O2KRAK",
|
|
"name": "Obsidian Local REST API"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"mode": "runOnceForAllItems",
|
|
"jsCode": "// Aggregate all collection results into a structured summary\nconst data = {};\n\n// Process successful executions\ntry {\n const successItems = $input.first()?.json?.data || [];\n const successByWorkflow = {};\n let totalSuccess = 0;\n for (const item of successItems) {\n const wfName = item.workflowData?.name || item.workflowId || 'Unknown';\n successByWorkflow[wfName] = (successByWorkflow[wfName] || 0) + 1;\n totalSuccess++;\n }\n data.successExecutions = { total: totalSuccess, byWorkflow: successByWorkflow };\n} catch(e) {\n data.successExecutions = { total: 0, byWorkflow: {}, error: e.message };\n}\n\n// Process failed executions\ntry {\n // Failed executions come from a separate input\n const failNode = $node['n8n Failed Executions']?.json;\n const failItems = failNode?.data || [];\n const failures = [];\n let totalFail = 0;\n for (const item of failItems) {\n const wfName = item.workflowData?.name || item.workflowId || 'Unknown';\n failures.push({\n workflow: wfName,\n id: item.id,\n stoppedAt: item.stoppedAt\n });\n totalFail++;\n }\n data.failedExecutions = { total: totalFail, failures: failures };\n} catch(e) {\n data.failedExecutions = { total: 0, failures: [], error: e.message };\n}\n\n// Swarm health\ntry {\n data.swarmHealth = $node['Swarm Health']?.json || { status: 'unavailable' };\n} catch(e) {\n data.swarmHealth = { status: 'error', error: e.message };\n}\n\n// New Obsidian notes\ntry {\n const obsResult = $node['New Obsidian Notes']?.json;\n const allFiles = obsResult?.files || [];\n // Filter for today's date in filename\n const today = new Intl.DateTimeFormat('en-CA', {\n timeZone: 'America/Los_Angeles',\n year: 'numeric', month: '2-digit', day: '2-digit'\n }).format(new Date()).replaceAll('/', '-');\n const todayFiles = allFiles.filter(f => {\n const name = typeof f === 'string' ? f : (f.name || f.path || '');\n return name.includes(today);\n });\n data.newNotes = todayFiles.map(f => typeof f === 'string' ? f : (f.name || f.path || JSON.stringify(f)));\n} catch(e) {\n data.newNotes = [];\n data.notesError = e.message;\n}\n\ndata.date = new Intl.DateTimeFormat('en-CA', {\n timeZone: 'America/Los_Angeles',\n year: 'numeric', month: '2-digit', day: '2-digit'\n}).format(new Date()).replaceAll('/', '-');\n\ndata.summary = JSON.stringify(data, null, 2);\n\nreturn [{ json: data }];"
|
|
},
|
|
"id": "a1b2c3d4-0001-4000-8000-000000000006",
|
|
"name": "Aggregate Data",
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
500,
|
|
100
|
|
],
|
|
"onError": "continueRegularOutput"
|
|
},
|
|
{
|
|
"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.3, max_tokens: 800, messages: [{ role: 'system', content: 'You are an evening digest assistant. Given data about today\\'s automation runs, failures, new notes, and infrastructure health, produce a concise evening digest under 400 words. Use emojis for section headers. Format for Telegram/Markdown. Sections: 🔧 Executions Summary, ⚠️ Failures, 📝 New Notes, 🏥 Infrastructure Health, 📋 Action Items. Be factual and concise.' }, { role: 'user', content: 'Here is today\\'s data:\\n' + $json.summary }] }) }}",
|
|
"options": {
|
|
"response": {
|
|
"response": {
|
|
"responseFormat": "json"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"id": "a1b2c3d4-0001-4000-8000-000000000007",
|
|
"name": "LLM Synthesis",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.2,
|
|
"position": [
|
|
740,
|
|
100
|
|
],
|
|
"onError": "continueRegularOutput"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"mode": "runOnceForAllItems",
|
|
"jsCode": "// Extract LLM response text and prepare messages for Telegram/Discord/Obsidian\nlet text = '';\ntry {\n const llmResponse = $input.first()?.json;\n text = llmResponse?.choices?.[0]?.message?.content || '';\n // Strip code fences if present\n text = text.replace(/^```(?:markdown)?\\s*/i, '').replace(/```\\s*$/i, '').trim();\n} catch(e) {\n text = 'Evening digest generation encountered an error.';\n}\n\nif (!text) {\n text = '🌙 Evening Digest\\n\\nNo data collected today. All collection nodes may have failed.';\n}\n\n// Escape special chars for Telegram MarkdownV1\nlet telegramText = text;\n// Replace problematic markdown chars for Telegram\ntelegramText = telegramText.replace(/([_*\\[\\]()~`>#+\\-=|{}.!])/g, (m) => {\n // Keep basic markdown formatting\n if (['*', '_', '`'].includes(m)) return m;\n return '\\\\' + m;\n});\n\nconst today = new Intl.DateTimeFormat('en-CA', {\n timeZone: 'America/Los_Angeles',\n year: 'numeric', month: '2-digit', day: '2-digit'\n}).format(new Date()).replaceAll('/', '-');\n\nreturn [{\n json: {\n text: telegramText,\n discordText: text.substring(0, 2000),\n obsidianContent: `---\\ntitle: Evening Digest\\narea: infrastructure\\ntags: [infrastructure, digest, automation, daily, evening]\\ncreated: ${today}\\nupdated: ${today}\\nstatus: active\\n---\\n\\n# Evening Digest - ${today}\\n\\n${text}\\n`,\n notePath: `Notes/${today} Evening Digest.md`,\n date: today\n }\n}];"
|
|
},
|
|
"id": "a1b2c3d4-0001-4000-8000-000000000008",
|
|
"name": "Prepare Messages",
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
980,
|
|
100
|
|
],
|
|
"onError": "continueRegularOutput"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"chatId": "8367012007",
|
|
"text": "={{ $json.text }}",
|
|
"additionalFields": {
|
|
"parse_mode": "Markdown"
|
|
}
|
|
},
|
|
"id": "a1b2c3d4-0001-4000-8000-000000000009",
|
|
"name": "Send Telegram",
|
|
"type": "n8n-nodes-base.telegram",
|
|
"typeVersion": 1,
|
|
"position": [
|
|
1220,
|
|
-100
|
|
],
|
|
"credentials": {
|
|
"telegramApi": {
|
|
"id": "aox4dyIWVSRdcH5z",
|
|
"name": "Telegram Bot (OpenClaw)"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "POST",
|
|
"url": "https://discord.com/api/v10/channels/1494453542243532932/messages",
|
|
"authentication": "genericCredentialType",
|
|
"genericAuthType": "httpHeaderAuth",
|
|
"sendBody": true,
|
|
"specifyBody": "json",
|
|
"jsonBody": "={{ JSON.stringify({ content: $json.discordText }) }}",
|
|
"options": {
|
|
"response": {
|
|
"response": {
|
|
"responseFormat": "text"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"id": "a1b2c3d4-0001-4000-8000-000000000010",
|
|
"name": "Send Discord",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.2,
|
|
"position": [
|
|
1220,
|
|
100
|
|
],
|
|
"credentials": {
|
|
"httpHeaderAuth": {
|
|
"id": "UgPqYcoCNNIgr55m",
|
|
"name": "Discord Bot Auth"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "PUT",
|
|
"url": "={{ 'http://172.19.0.1:27123/vault/' + encodeURIComponent($json.notePath).replace(/%2F/g, '/') }}",
|
|
"authentication": "genericCredentialType",
|
|
"genericAuthType": "httpHeaderAuth",
|
|
"sendBody": true,
|
|
"specifyBody": "raw",
|
|
"rawContentType": "text/markdown",
|
|
"body": "={{ $json.obsidianContent }}",
|
|
"options": {}
|
|
},
|
|
"id": "a1b2c3d4-0001-4000-8000-000000000011",
|
|
"name": "Save to Obsidian",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.2,
|
|
"position": [
|
|
1220,
|
|
300
|
|
],
|
|
"credentials": {
|
|
"httpHeaderAuth": {
|
|
"id": "465Swz2b71O2KRAK",
|
|
"name": "Obsidian Local REST API"
|
|
}
|
|
}
|
|
}
|
|
],
|
|
"connections": {
|
|
"Daily 9PM Schedule": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "n8n Success Executions",
|
|
"type": "main",
|
|
"index": 0
|
|
},
|
|
{
|
|
"node": "n8n Failed Executions",
|
|
"type": "main",
|
|
"index": 0
|
|
},
|
|
{
|
|
"node": "Swarm Health",
|
|
"type": "main",
|
|
"index": 0
|
|
},
|
|
{
|
|
"node": "New Obsidian Notes",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"n8n Success Executions": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Aggregate Data",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"n8n Failed Executions": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Aggregate Data",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Swarm Health": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Aggregate Data",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"New Obsidian Notes": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Aggregate Data",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Aggregate Data": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "LLM Synthesis",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"LLM Synthesis": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Prepare Messages",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Prepare Messages": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Send Telegram",
|
|
"type": "main",
|
|
"index": 0
|
|
},
|
|
{
|
|
"node": "Send Discord",
|
|
"type": "main",
|
|
"index": 0
|
|
},
|
|
{
|
|
"node": "Save to Obsidian",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
}
|
|
},
|
|
"authors": "will will",
|
|
"name": null,
|
|
"description": null,
|
|
"autosaved": false,
|
|
"workflowPublishHistory": [
|
|
{
|
|
"createdAt": "2026-05-13T21:40:40.515Z",
|
|
"id": 1432,
|
|
"workflowId": "PlZywwqL8MRNEAN6",
|
|
"versionId": "afb71f4d-6ac3-434d-b659-de003d47c339",
|
|
"event": "activated",
|
|
"userId": "5ad50ead-6e6a-4d12-ab5b-e5db15835bb5"
|
|
},
|
|
{
|
|
"createdAt": "2026-05-14T00:04:59.370Z",
|
|
"id": 1483,
|
|
"workflowId": "PlZywwqL8MRNEAN6",
|
|
"versionId": "afb71f4d-6ac3-434d-b659-de003d47c339",
|
|
"event": "activated",
|
|
"userId": "5ad50ead-6e6a-4d12-ab5b-e5db15835bb5"
|
|
},
|
|
{
|
|
"createdAt": "2026-05-14T00:04:59.415Z",
|
|
"id": 1485,
|
|
"workflowId": "PlZywwqL8MRNEAN6",
|
|
"versionId": "afb71f4d-6ac3-434d-b659-de003d47c339",
|
|
"event": "activated",
|
|
"userId": "5ad50ead-6e6a-4d12-ab5b-e5db15835bb5"
|
|
},
|
|
{
|
|
"createdAt": "2026-05-14T00:04:59.362Z",
|
|
"id": 1482,
|
|
"workflowId": "PlZywwqL8MRNEAN6",
|
|
"versionId": "afb71f4d-6ac3-434d-b659-de003d47c339",
|
|
"event": "deactivated",
|
|
"userId": "5ad50ead-6e6a-4d12-ab5b-e5db15835bb5"
|
|
},
|
|
{
|
|
"createdAt": "2026-05-14T00:04:59.388Z",
|
|
"id": 1484,
|
|
"workflowId": "PlZywwqL8MRNEAN6",
|
|
"versionId": "afb71f4d-6ac3-434d-b659-de003d47c339",
|
|
"event": "deactivated",
|
|
"userId": "5ad50ead-6e6a-4d12-ab5b-e5db15835bb5"
|
|
}
|
|
]
|
|
}
|
|
}
|