{
  "updatedAt": "2026-05-01T20:02:33.035Z",
  "createdAt": "2026-03-27T23:10:47.862Z",
  "id": "75JCevkdgkyCr2qH",
  "name": "Nightly Obsidian Vault Sync",
  "description": null,
  "active": false,
  "isArchived": false,
  "nodes": [
    {
      "id": "schedule-node",
      "name": "Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        240,
        300
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "45 23 * * *"
            }
          ]
        }
      }
    },
    {
      "id": "nightly-sync",
      "name": "Generate Nightly Vault Sync",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        520,
        300
      ],
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "\nconst http = this.helpers.httpRequest;\nconst OBS_BASE = 'http://192.168.153.130:27123';\nconst OBS_KEY = '698cfc8b00b93c41480e7e1cb84d77b75176be87507256a5fae9a5b53b5a20cb';\nconst MODEL = 'gemma-4-26B-A4B-it-UD-IQ2_M.gguf';\nconst TZ = 'America/Los_Angeles';\n\nconst enc = (p) => encodeURIComponent(p).replace(/%2F/g, '/');\nconst getDate = () => new Intl.DateTimeFormat('en-CA', { timeZone: TZ, year: 'numeric', month: '2-digit', day: '2-digit' }).format(new Date()).replaceAll('/', '-');\n\nconst notePaths = [\n  'Infrastructure/Architecture.md',\n  'Infrastructure/Automation/n8n Workflows.md',\n  'Infrastructure/Automation/Cron Jobs.md',\n  'Infrastructure/Services/Docker Services.md'\n];\n\nconst obsHeaders = {\n  'Authorization': `Bearer ${OBS_KEY}`,\n  'User-Agent': 'n8n-nightly-vault-sync'\n};\n\nconst notes = {};\nfor (const p of notePaths) {\n  notes[p] = await http({\n    method: 'GET',\n    url: `${OBS_BASE}/vault/${enc(p)}`,\n    headers: obsHeaders,\n    timeout: 15000,\n  });\n}\n\nconst n8nHealth = await http({\n  method: 'GET',\n  url: 'http://192.168.153.130:18808/healthz',\n  json: true,\n  timeout: 10000,\n});\n\nconst modelInfo = await http({\n  method: 'GET',\n  url: 'http://192.168.153.130:18806/v1/models',\n  json: true,\n  timeout: 10000,\n});\n\nconst prompt = [\n  'Write a concise nightly operational sync note for an Obsidian shared vault.',\n  'Return markdown body only. No code fences.',\n  'Start with heading: # Nightly Vault Sync',\n  'Then sections: ## Summary, ## Current State, ## Follow-ups',\n  'Keep it factual, low-noise, and under 250 words.',\n  'Mention that this is an automated nightly note generated by n8n using the local LLM.',\n  '',\n  'Live health:',\n  `- n8n health: ${JSON.stringify(n8nHealth)}`,\n  `- local model ids: ${JSON.stringify((modelInfo.data || []).map(m => m.id))}`,\n  '',\n  'Source note contents:',\n  ...notePaths.flatMap(p => [`\\n--- ${p} ---`, String(notes[p]).slice(0, 1800)])\n].join('\\n');\n\nconst llm = await http({\n  method: 'POST',\n  url: 'http://192.168.153.130:18806/v1/chat/completions',\n  headers: { 'Content-Type': 'application/json' },\n  body: {\n    model: MODEL,\n    temperature: 0.2,\n    max_tokens: 260,\n    messages: [\n      {\n        role: 'system',\n        content: 'You create concise nightly operations notes for an Obsidian vault. Prefer concrete facts from the provided sources. If there are unresolved drifts or follow-ups, mention them briefly. Do not invent incidents.'\n      },\n      { role: 'user', content: prompt }\n    ]\n  },\n  json: true,\n  timeout: 60000,\n});\n\nlet body = (((llm || {}).choices || [])[0] || {}).message?.content || '';\nbody = body.replace(/^```(?:markdown)?\\s*/i, '').replace(/```\\s*$/i, '').trim();\nif (!body) {\n  body = '# Nightly Vault Sync\\n\\n## Summary\\n\\nAutomated nightly note ran, but the local LLM returned an empty response.\\n\\n## Current State\\n\\n- n8n health: ok\\n- local model endpoint reachable\\n\\n## Follow-ups\\n\\n- Check the local LLM response path if this repeats.';\n}\n\nconst date = getDate();\nconst notePath = `Notes/${date} Nightly Vault Sync.md`;\nconst full = `---\\ntitle: Nightly Vault Sync\\narea: infrastructure\\ntags: [infrastructure, obsidian, automation, nightly, assistant]\\ncreated: ${date}\\nupdated: ${date}\\nstatus: active\\nrelated: [[Infrastructure/Architecture]], [[Infrastructure/Automation/n8n Workflows]], [[Infrastructure/Automation/Cron Jobs]], [[Infrastructure/Services/Docker Services]]\\n---\\n\\n${body}\\n`;\n\nawait http({\n  method: 'PUT',\n  url: `${OBS_BASE}/vault/${enc(notePath)}`,\n  headers: { ...obsHeaders, 'Content-Type': 'text/markdown' },\n  body: full,\n  timeout: 20000,\n});\n\nreturn [{ json: { notePath, model: MODEL, sourceNotes: notePaths, n8nHealth, modelCount: (modelInfo.data || []).length } }];\n"
      }
    }
  ],
  "connections": {
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "Generate Nightly Vault Sync",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1",
    "callerPolicy": "workflowsFromSameOwner",
    "availableInMCP": false
  },
  "staticData": {
    "node:Schedule Trigger": {
      "recurrenceRules": []
    }
  },
  "meta": null,
  "pinData": null,
  "versionId": "9585256a-29c2-444a-aa55-0eaf259f032d",
  "activeVersionId": null,
  "versionCounter": 66,
  "triggerCount": 1,
  "shared": [
    {
      "updatedAt": "2026-03-27T23:10:47.871Z",
      "createdAt": "2026-03-27T23:10:47.871Z",
      "role": "workflow:owner",
      "workflowId": "75JCevkdgkyCr2qH",
      "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": null
}