{
  "updatedAt": "2026-05-14T00:21:08.433Z",
  "createdAt": "2026-05-13T21:41:17.798Z",
  "id": "g3IdGZCK1EtTsv9T",
  "name": "Morning Brief",
  "description": null,
  "active": true,
  "isArchived": false,
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "30 6 * * *"
            }
          ]
        }
      },
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.3,
      "position": [
        0,
        0
      ],
      "id": "16110cb5-e50a-4d99-a613-448057221422",
      "name": "Daily 06:30 PT"
    },
    {
      "parameters": {
        "method": "GET",
        "url": "http://wttr.in/Seattle?format=j1",
        "options": {
          "timeout": 10000
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        300,
        -400
      ],
      "id": "a119dfe9-46db-43ca-98b2-f0690bc0f6f5",
      "name": "Weather",
      "continueOnFail": true
    },
    {
      "parameters": {
        "method": "GET",
        "url": "http://172.19.0.1:18809/health",
        "options": {
          "timeout": 10000
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        300,
        -250
      ],
      "id": "05f60eba-ab11-4fe0-b761-d1ca9ae557d4",
      "name": "Swarm Health",
      "continueOnFail": true
    },
    {
      "parameters": {
        "method": "GET",
        "url": "http://127.0.0.1:5678/healthz",
        "options": {
          "timeout": 10000
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        300,
        -100
      ],
      "id": "4b5c3f4c-7f11-4e0c-9c56-3b8596a1d25d",
      "name": "n8n Health",
      "continueOnFail": true
    },
    {
      "parameters": {
        "method": "GET",
        "url": "http://172.19.0.1:18804/health/liveliness",
        "options": {
          "timeout": 10000
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        300,
        50
      ],
      "id": "a8e4e45c-60a1-4f90-8ecc-49782d7be900",
      "name": "LiteLLM Health",
      "continueOnFail": true
    },
    {
      "parameters": {
        "method": "GET",
        "url": "http://127.0.0.1:5678/api/v1/executions",
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "workflowId",
              "value": "9sFwRyUDz51csAp7"
            },
            {
              "name": "limit",
              "value": "5"
            },
            {
              "name": "status",
              "value": "success"
            }
          ]
        },
        "options": {
          "timeout": 15000
        },
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        300,
        200
      ],
      "id": "c688abdf-9b63-43b4-81da-7c81388b73f8",
      "name": "Email Highlights",
      "continueOnFail": true,
      "credentials": {
        "httpHeaderAuth": {
          "id": "UPAHgUJVRqZQceL4",
          "name": "n8n Public API (Failure Digest)"
        }
      }
    },
    {
      "parameters": {
        "method": "GET",
        "url": "=https://www.googleapis.com/calendar/v3/calendars/primary/events?timeMin={{ $now.format('yyyy-MM-dd') }}T00:00:00-07:00&timeMax={{ $now.plus({days:1}).format('yyyy-MM-dd') }}T23:59:59-07:00&singleEvents=true&orderBy=startTime",
        "authentication": "oAuth2",
        "options": {
          "timeout": 10000
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        300,
        350
      ],
      "id": "d3c5a4ce-9f81-4da8-8dc8-7256bd96285b",
      "name": "Calendar",
      "credentials": {
        "oAuth2Api": {
          "id": "458fY4bs1z49OTeZ",
          "name": "Google OAuth"
        }
      },
      "continueOnFail": true
    },
    {
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "\nfunction getSafe(nodeName) {\n  try {\n    const items = $(nodeName).all();\n    if (items && items.length > 0 && items[0].json) {\n      return items[0].json;\n    }\n  } catch (e) {}\n  return { error: 'Node failed or returned no data' };\n}\n\nconst weather = getSafe('Weather');\nconst swarmHealth = getSafe('Swarm Health');\nconst n8nHealth = getSafe('n8n Health');\nconst litellmHealth = getSafe('LiteLLM Health');\nconst emailData = getSafe('Email Highlights');\nconst calendar = getSafe('Calendar');\n\n// Extract weather summary\nlet weatherSummary = {};\nif (weather.current_condition && weather.current_condition[0]) {\n  const c = weather.current_condition[0];\n  weatherSummary = {\n    temp_F: c.FeelsLikeF || c.temp_F,\n    description: c.weatherDesc ? c.weatherDesc[0].value : 'unknown',\n    humidity: c.humidity,\n    wind_mph: c.windspeedMiles\n  };\n} else {\n  weatherSummary = { error: 'Weather data unavailable' };\n}\n\n// Count healthy/unhealthy containers\nlet infraSummary = { healthy: 0, unhealthy: 0, details: [] };\nif (Array.isArray(swarmHealth)) {\n  for (const c of swarmHealth) {\n    if (c.health === 'healthy' || c.status === 'running') {\n      infraSummary.healthy++;\n    } else {\n      infraSummary.unhealthy++;\n    }\n    infraSummary.details.push({ name: c.name || c.Names, status: c.status, health: c.health });\n  }\n} else if (swarmHealth.containers && Array.isArray(swarmHealth.containers)) {\n  for (const c of swarmHealth.containers) {\n    if (c.health === 'healthy' || c.status === 'running') {\n      infraSummary.healthy++;\n    } else {\n      infraSummary.unhealthy++;\n    }\n    infraSummary.details.push({ name: c.name, status: c.status, health: c.health });\n  }\n} else if (swarmHealth.error) {\n  infraSummary = { error: 'Swarm health endpoint unavailable' };\n}\n\nconst n8nOk = (n8nHealth && !n8nHealth.error);\nconst litellmOk = (litellmHealth && !litellmHealth.error);\n\n// Extract email info from execution data\nlet emailHighlights = [];\nif (emailData && emailData.data && Array.isArray(emailData.data)) {\n  for (const exec of emailData.data.slice(0, 5)) {\n    emailHighlights.push({\n      id: exec.id,\n      finished: exec.stoppedAt || 'unknown'\n    });\n  }\n}\n\n// Calendar events\nlet calendarEvents = [];\nif (calendar && calendar.items && Array.isArray(calendar.items)) {\n  for (const ev of calendar.items.slice(0, 10)) {\n    calendarEvents.push({\n      summary: ev.summary || '(no title)',\n      start: (ev.start && (ev.start.dateTime || ev.start.date)) || 'unknown',\n      end: (ev.end && (ev.end.dateTime || ev.end.date)) || 'unknown'\n    });\n  }\n}\n\nconst dataForLLM = {\n  date: new Date().toISOString().split('T')[0],\n  weather: weatherSummary,\n  infrastructure: {\n    swarm: infraSummary,\n    n8n: n8nOk ? 'healthy' : 'unhealthy',\n    litellm: litellmOk ? 'healthy' : 'unhealthy'\n  },\n  email: emailHighlights.length > 0 ? emailHighlights : [{ info: 'No recent email triage data' }],\n  calendar: calendarEvents.length > 0 ? calendarEvents : [{ info: 'Calendar unavailable or no events today' }]\n};\n\nreturn [{ json: { dataJson: JSON.stringify(dataForLLM, null, 2) } }];\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        650,
        0
      ],
      "id": "1d2b39db-3649-4316-8ce9-b5c83c981017",
      "name": "Merge Data"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "http://172.19.0.1:18806/v1/chat/completions",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\"model\": \"gemma-4-26B-A4B-it-UD-IQ2_M.gguf\", \"messages\": [{\"role\": \"system\", \"content\": \"You are a personal morning brief assistant. Given raw data about weather, infrastructure, email, and calendar, produce a concise morning brief under 400 words. Use emojis for section headers. Format for Telegram using HTML (use <b> for bold, <code> for code). Keep it scannable and actionable. If any section data is missing or shows errors, note it briefly and move on.\"}, {\"role\": \"user\", \"content\": \"Here is today's data:\\n{{ $json.dataJson }}\"}], \"temperature\": 0.3, \"max_tokens\": 800}",
        "options": {
          "timeout": 60000
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        950,
        0
      ],
      "id": "f2eb23d3-bf07-46d8-8556-2ba6a0185f5a",
      "name": "Synthesize with LLM",
      "continueOnFail": false
    },
    {
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "\nconst response = $input.first().json;\nlet brief = '';\n\nif (response.choices && response.choices[0] && response.choices[0].message) {\n  brief = response.choices[0].message.content;\n} else if (typeof response === 'string') {\n  brief = response;\n} else {\n  brief = 'Error: LLM synthesis failed. Raw data: ' + JSON.stringify(response).substring(0, 500);\n}\n\nconst today = new Date().toISOString().split('T')[0];\nconst yamlFrontmatter = '---\\ncreated: ' + today + '\\ntype: morning-brief\\ntags: [daily, brief]\\n---\\n\\n';\n\nreturn [{\n  json: {\n    brief: brief,\n    briefWithFrontmatter: yamlFrontmatter + '# Morning Brief - ' + today + '\\n\\n' + brief,\n    date: today\n  }\n}];\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1250,
        0
      ],
      "id": "0adac542-7d95-4002-a3e2-080442cfd9e3",
      "name": "Extract Brief"
    },
    {
      "parameters": {
        "chatId": "8367012007",
        "text": "={{ $json.brief }}",
        "additionalFields": {
          "parse_mode": "HTML"
        }
      },
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.2,
      "position": [
        1550,
        -150
      ],
      "id": "8242ada9-20c8-4689-b00c-3cd2787b2eb5",
      "name": "Send Telegram",
      "credentials": {
        "telegramApi": {
          "id": "aox4dyIWVSRdcH5z",
          "name": "Telegram Bot (OpenClaw)"
        }
      },
      "continueOnFail": true
    },
    {
      "parameters": {
        "method": "PUT",
        "url": "=http://172.19.0.1:27123/vault/Notes/{{ $json.date }} Morning Brief.md",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "text/markdown"
            }
          ]
        },
        "sendBody": true,
        "contentType": "raw",
        "rawContentType": "text/markdown",
        "body": "={{ $json.briefWithFrontmatter }}",
        "options": {
          "timeout": 10000
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1550,
        150
      ],
      "id": "0f1fd6a2-86c0-4d3f-a948-32ce701d9f9f",
      "name": "Save to Obsidian",
      "credentials": {
        "httpHeaderAuth": {
          "id": "465Swz2b71O2KRAK",
          "name": "Obsidian Local REST API"
        }
      },
      "continueOnFail": true
    }
  ],
  "connections": {
    "Daily 06:30 PT": {
      "main": [
        [
          {
            "node": "Weather",
            "type": "main",
            "index": 0
          },
          {
            "node": "Swarm Health",
            "type": "main",
            "index": 0
          },
          {
            "node": "n8n Health",
            "type": "main",
            "index": 0
          },
          {
            "node": "LiteLLM Health",
            "type": "main",
            "index": 0
          },
          {
            "node": "Email Highlights",
            "type": "main",
            "index": 0
          },
          {
            "node": "Calendar",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Weather": {
      "main": [
        [
          {
            "node": "Merge Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Swarm Health": {
      "main": [
        [
          {
            "node": "Merge Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "n8n Health": {
      "main": [
        [
          {
            "node": "Merge Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "LiteLLM Health": {
      "main": [
        [
          {
            "node": "Merge Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Email Highlights": {
      "main": [
        [
          {
            "node": "Merge Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Calendar": {
      "main": [
        [
          {
            "node": "Merge Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge Data": {
      "main": [
        [
          {
            "node": "Synthesize with LLM",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Synthesize with LLM": {
      "main": [
        [
          {
            "node": "Extract Brief",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Brief": {
      "main": [
        [
          {
            "node": "Send Telegram",
            "type": "main",
            "index": 0
          },
          {
            "node": "Save to Obsidian",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1",
    "timezone": "America/Los_Angeles",
    "callerPolicy": "workflowsFromSameOwner",
    "availableInMCP": false
  },
  "staticData": {
    "node:Daily 06:30 PT": {
      "recurrenceRules": []
    }
  },
  "meta": null,
  "versionId": "c23946c7-29cf-42dc-985c-c1b818b8d010",
  "activeVersionId": "c23946c7-29cf-42dc-985c-c1b818b8d010",
  "versionCounter": 10,
  "triggerCount": 1,
  "shared": [
    {
      "updatedAt": "2026-05-13T21:41:17.800Z",
      "createdAt": "2026-05-13T21:41:17.800Z",
      "role": "workflow:owner",
      "workflowId": "g3IdGZCK1EtTsv9T",
      "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-14T00:21:08.434Z",
    "createdAt": "2026-05-14T00:21:08.434Z",
    "versionId": "c23946c7-29cf-42dc-985c-c1b818b8d010",
    "workflowId": "g3IdGZCK1EtTsv9T",
    "nodes": [
      {
        "parameters": {
          "rule": {
            "interval": [
              {
                "field": "cronExpression",
                "expression": "30 6 * * *"
              }
            ]
          }
        },
        "type": "n8n-nodes-base.scheduleTrigger",
        "typeVersion": 1.3,
        "position": [
          0,
          0
        ],
        "id": "16110cb5-e50a-4d99-a613-448057221422",
        "name": "Daily 06:30 PT"
      },
      {
        "parameters": {
          "method": "GET",
          "url": "http://wttr.in/Seattle?format=j1",
          "options": {
            "timeout": 10000
          }
        },
        "type": "n8n-nodes-base.httpRequest",
        "typeVersion": 4.2,
        "position": [
          300,
          -400
        ],
        "id": "a119dfe9-46db-43ca-98b2-f0690bc0f6f5",
        "name": "Weather",
        "continueOnFail": true
      },
      {
        "parameters": {
          "method": "GET",
          "url": "http://172.19.0.1:18809/health",
          "options": {
            "timeout": 10000
          }
        },
        "type": "n8n-nodes-base.httpRequest",
        "typeVersion": 4.2,
        "position": [
          300,
          -250
        ],
        "id": "05f60eba-ab11-4fe0-b761-d1ca9ae557d4",
        "name": "Swarm Health",
        "continueOnFail": true
      },
      {
        "parameters": {
          "method": "GET",
          "url": "http://127.0.0.1:5678/healthz",
          "options": {
            "timeout": 10000
          }
        },
        "type": "n8n-nodes-base.httpRequest",
        "typeVersion": 4.2,
        "position": [
          300,
          -100
        ],
        "id": "4b5c3f4c-7f11-4e0c-9c56-3b8596a1d25d",
        "name": "n8n Health",
        "continueOnFail": true
      },
      {
        "parameters": {
          "method": "GET",
          "url": "http://172.19.0.1:18804/health/liveliness",
          "options": {
            "timeout": 10000
          }
        },
        "type": "n8n-nodes-base.httpRequest",
        "typeVersion": 4.2,
        "position": [
          300,
          50
        ],
        "id": "a8e4e45c-60a1-4f90-8ecc-49782d7be900",
        "name": "LiteLLM Health",
        "continueOnFail": true
      },
      {
        "parameters": {
          "method": "GET",
          "url": "http://127.0.0.1:5678/api/v1/executions",
          "sendQuery": true,
          "queryParameters": {
            "parameters": [
              {
                "name": "workflowId",
                "value": "9sFwRyUDz51csAp7"
              },
              {
                "name": "limit",
                "value": "5"
              },
              {
                "name": "status",
                "value": "success"
              }
            ]
          },
          "options": {
            "timeout": 15000
          },
          "authentication": "genericCredentialType",
          "genericAuthType": "httpHeaderAuth"
        },
        "type": "n8n-nodes-base.httpRequest",
        "typeVersion": 4.2,
        "position": [
          300,
          200
        ],
        "id": "c688abdf-9b63-43b4-81da-7c81388b73f8",
        "name": "Email Highlights",
        "continueOnFail": true,
        "credentials": {
          "httpHeaderAuth": {
            "id": "UPAHgUJVRqZQceL4",
            "name": "n8n Public API (Failure Digest)"
          }
        }
      },
      {
        "parameters": {
          "method": "GET",
          "url": "=https://www.googleapis.com/calendar/v3/calendars/primary/events?timeMin={{ $now.format('yyyy-MM-dd') }}T00:00:00-07:00&timeMax={{ $now.plus({days:1}).format('yyyy-MM-dd') }}T23:59:59-07:00&singleEvents=true&orderBy=startTime",
          "authentication": "oAuth2",
          "options": {
            "timeout": 10000
          }
        },
        "type": "n8n-nodes-base.httpRequest",
        "typeVersion": 4.2,
        "position": [
          300,
          350
        ],
        "id": "d3c5a4ce-9f81-4da8-8dc8-7256bd96285b",
        "name": "Calendar",
        "credentials": {
          "oAuth2Api": {
            "id": "458fY4bs1z49OTeZ",
            "name": "Google OAuth"
          }
        },
        "continueOnFail": true
      },
      {
        "parameters": {
          "mode": "runOnceForAllItems",
          "jsCode": "\nfunction getSafe(nodeName) {\n  try {\n    const items = $(nodeName).all();\n    if (items && items.length > 0 && items[0].json) {\n      return items[0].json;\n    }\n  } catch (e) {}\n  return { error: 'Node failed or returned no data' };\n}\n\nconst weather = getSafe('Weather');\nconst swarmHealth = getSafe('Swarm Health');\nconst n8nHealth = getSafe('n8n Health');\nconst litellmHealth = getSafe('LiteLLM Health');\nconst emailData = getSafe('Email Highlights');\nconst calendar = getSafe('Calendar');\n\n// Extract weather summary\nlet weatherSummary = {};\nif (weather.current_condition && weather.current_condition[0]) {\n  const c = weather.current_condition[0];\n  weatherSummary = {\n    temp_F: c.FeelsLikeF || c.temp_F,\n    description: c.weatherDesc ? c.weatherDesc[0].value : 'unknown',\n    humidity: c.humidity,\n    wind_mph: c.windspeedMiles\n  };\n} else {\n  weatherSummary = { error: 'Weather data unavailable' };\n}\n\n// Count healthy/unhealthy containers\nlet infraSummary = { healthy: 0, unhealthy: 0, details: [] };\nif (Array.isArray(swarmHealth)) {\n  for (const c of swarmHealth) {\n    if (c.health === 'healthy' || c.status === 'running') {\n      infraSummary.healthy++;\n    } else {\n      infraSummary.unhealthy++;\n    }\n    infraSummary.details.push({ name: c.name || c.Names, status: c.status, health: c.health });\n  }\n} else if (swarmHealth.containers && Array.isArray(swarmHealth.containers)) {\n  for (const c of swarmHealth.containers) {\n    if (c.health === 'healthy' || c.status === 'running') {\n      infraSummary.healthy++;\n    } else {\n      infraSummary.unhealthy++;\n    }\n    infraSummary.details.push({ name: c.name, status: c.status, health: c.health });\n  }\n} else if (swarmHealth.error) {\n  infraSummary = { error: 'Swarm health endpoint unavailable' };\n}\n\nconst n8nOk = (n8nHealth && !n8nHealth.error);\nconst litellmOk = (litellmHealth && !litellmHealth.error);\n\n// Extract email info from execution data\nlet emailHighlights = [];\nif (emailData && emailData.data && Array.isArray(emailData.data)) {\n  for (const exec of emailData.data.slice(0, 5)) {\n    emailHighlights.push({\n      id: exec.id,\n      finished: exec.stoppedAt || 'unknown'\n    });\n  }\n}\n\n// Calendar events\nlet calendarEvents = [];\nif (calendar && calendar.items && Array.isArray(calendar.items)) {\n  for (const ev of calendar.items.slice(0, 10)) {\n    calendarEvents.push({\n      summary: ev.summary || '(no title)',\n      start: (ev.start && (ev.start.dateTime || ev.start.date)) || 'unknown',\n      end: (ev.end && (ev.end.dateTime || ev.end.date)) || 'unknown'\n    });\n  }\n}\n\nconst dataForLLM = {\n  date: new Date().toISOString().split('T')[0],\n  weather: weatherSummary,\n  infrastructure: {\n    swarm: infraSummary,\n    n8n: n8nOk ? 'healthy' : 'unhealthy',\n    litellm: litellmOk ? 'healthy' : 'unhealthy'\n  },\n  email: emailHighlights.length > 0 ? emailHighlights : [{ info: 'No recent email triage data' }],\n  calendar: calendarEvents.length > 0 ? calendarEvents : [{ info: 'Calendar unavailable or no events today' }]\n};\n\nreturn [{ json: { dataJson: JSON.stringify(dataForLLM, null, 2) } }];\n"
        },
        "type": "n8n-nodes-base.code",
        "typeVersion": 2,
        "position": [
          650,
          0
        ],
        "id": "1d2b39db-3649-4316-8ce9-b5c83c981017",
        "name": "Merge Data"
      },
      {
        "parameters": {
          "method": "POST",
          "url": "http://172.19.0.1:18806/v1/chat/completions",
          "sendBody": true,
          "specifyBody": "json",
          "jsonBody": "={\"model\": \"gemma-4-26B-A4B-it-UD-IQ2_M.gguf\", \"messages\": [{\"role\": \"system\", \"content\": \"You are a personal morning brief assistant. Given raw data about weather, infrastructure, email, and calendar, produce a concise morning brief under 400 words. Use emojis for section headers. Format for Telegram using HTML (use <b> for bold, <code> for code). Keep it scannable and actionable. If any section data is missing or shows errors, note it briefly and move on.\"}, {\"role\": \"user\", \"content\": \"Here is today's data:\\n{{ $json.dataJson }}\"}], \"temperature\": 0.3, \"max_tokens\": 800}",
          "options": {
            "timeout": 60000
          }
        },
        "type": "n8n-nodes-base.httpRequest",
        "typeVersion": 4.2,
        "position": [
          950,
          0
        ],
        "id": "f2eb23d3-bf07-46d8-8556-2ba6a0185f5a",
        "name": "Synthesize with LLM",
        "continueOnFail": false
      },
      {
        "parameters": {
          "mode": "runOnceForAllItems",
          "jsCode": "\nconst response = $input.first().json;\nlet brief = '';\n\nif (response.choices && response.choices[0] && response.choices[0].message) {\n  brief = response.choices[0].message.content;\n} else if (typeof response === 'string') {\n  brief = response;\n} else {\n  brief = 'Error: LLM synthesis failed. Raw data: ' + JSON.stringify(response).substring(0, 500);\n}\n\nconst today = new Date().toISOString().split('T')[0];\nconst yamlFrontmatter = '---\\ncreated: ' + today + '\\ntype: morning-brief\\ntags: [daily, brief]\\n---\\n\\n';\n\nreturn [{\n  json: {\n    brief: brief,\n    briefWithFrontmatter: yamlFrontmatter + '# Morning Brief - ' + today + '\\n\\n' + brief,\n    date: today\n  }\n}];\n"
        },
        "type": "n8n-nodes-base.code",
        "typeVersion": 2,
        "position": [
          1250,
          0
        ],
        "id": "0adac542-7d95-4002-a3e2-080442cfd9e3",
        "name": "Extract Brief"
      },
      {
        "parameters": {
          "chatId": "8367012007",
          "text": "={{ $json.brief }}",
          "additionalFields": {
            "parse_mode": "HTML"
          }
        },
        "type": "n8n-nodes-base.telegram",
        "typeVersion": 1.2,
        "position": [
          1550,
          -150
        ],
        "id": "8242ada9-20c8-4689-b00c-3cd2787b2eb5",
        "name": "Send Telegram",
        "credentials": {
          "telegramApi": {
            "id": "aox4dyIWVSRdcH5z",
            "name": "Telegram Bot (OpenClaw)"
          }
        },
        "continueOnFail": true
      },
      {
        "parameters": {
          "method": "PUT",
          "url": "=http://172.19.0.1:27123/vault/Notes/{{ $json.date }} Morning Brief.md",
          "sendHeaders": true,
          "headerParameters": {
            "parameters": [
              {
                "name": "Content-Type",
                "value": "text/markdown"
              }
            ]
          },
          "sendBody": true,
          "contentType": "raw",
          "rawContentType": "text/markdown",
          "body": "={{ $json.briefWithFrontmatter }}",
          "options": {
            "timeout": 10000
          }
        },
        "type": "n8n-nodes-base.httpRequest",
        "typeVersion": 4.2,
        "position": [
          1550,
          150
        ],
        "id": "0f1fd6a2-86c0-4d3f-a948-32ce701d9f9f",
        "name": "Save to Obsidian",
        "credentials": {
          "httpHeaderAuth": {
            "id": "465Swz2b71O2KRAK",
            "name": "Obsidian Local REST API"
          }
        },
        "continueOnFail": true
      }
    ],
    "connections": {
      "Daily 06:30 PT": {
        "main": [
          [
            {
              "node": "Weather",
              "type": "main",
              "index": 0
            },
            {
              "node": "Swarm Health",
              "type": "main",
              "index": 0
            },
            {
              "node": "n8n Health",
              "type": "main",
              "index": 0
            },
            {
              "node": "LiteLLM Health",
              "type": "main",
              "index": 0
            },
            {
              "node": "Email Highlights",
              "type": "main",
              "index": 0
            },
            {
              "node": "Calendar",
              "type": "main",
              "index": 0
            }
          ]
        ]
      },
      "Weather": {
        "main": [
          [
            {
              "node": "Merge Data",
              "type": "main",
              "index": 0
            }
          ]
        ]
      },
      "Swarm Health": {
        "main": [
          [
            {
              "node": "Merge Data",
              "type": "main",
              "index": 0
            }
          ]
        ]
      },
      "n8n Health": {
        "main": [
          [
            {
              "node": "Merge Data",
              "type": "main",
              "index": 0
            }
          ]
        ]
      },
      "LiteLLM Health": {
        "main": [
          [
            {
              "node": "Merge Data",
              "type": "main",
              "index": 0
            }
          ]
        ]
      },
      "Email Highlights": {
        "main": [
          [
            {
              "node": "Merge Data",
              "type": "main",
              "index": 0
            }
          ]
        ]
      },
      "Calendar": {
        "main": [
          [
            {
              "node": "Merge Data",
              "type": "main",
              "index": 0
            }
          ]
        ]
      },
      "Merge Data": {
        "main": [
          [
            {
              "node": "Synthesize with LLM",
              "type": "main",
              "index": 0
            }
          ]
        ]
      },
      "Synthesize with LLM": {
        "main": [
          [
            {
              "node": "Extract Brief",
              "type": "main",
              "index": 0
            }
          ]
        ]
      },
      "Extract Brief": {
        "main": [
          [
            {
              "node": "Send Telegram",
              "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-14T00:21:08.466Z",
        "id": 1493,
        "workflowId": "g3IdGZCK1EtTsv9T",
        "versionId": "c23946c7-29cf-42dc-985c-c1b818b8d010",
        "event": "activated",
        "userId": "5ad50ead-6e6a-4d12-ab5b-e5db15835bb5"
      }
    ]
  }
}
