{
  "name": "OpenClaw Drift Detector",
  "nodes": [
    {
      "parameters": {
        "rule": {"interval": [{"field": "cronExpression", "expression": "45 6 * * *"}]},
        "timezone": "Australia/Perth"
      },
      "id": "cron",
      "name": "Daily 06:45 AWST",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [220, 320]
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {"name": "repoOwner", "type": "string", "value": "Anthony"},
            {"name": "repoName", "type": "string", "value": "openclaw-backups"},
            {"name": "branch", "type": "string", "value": "main"}
          ]
        }
      },
      "id": "set",
      "name": "Set Repo Context",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [440, 320]
    },
    {
      "parameters": {
        "url": "=http://gitea.kangaroo-eel.ts.net:3000/api/v1/repos/{{$json.repoOwner}}/{{$json.repoName}}/commits?sha={{$json.branch}}&limit=2",
        "options": {"timeout": 10000}
      },
      "id": "commits",
      "name": "Get Last 2 Commits",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [680, 320],
      "retryOnFail": true,
      "maxTries": 3,
      "waitBetweenTries": 1500
    },
    {
      "parameters": {
        "jsCode": "const commits = Array.isArray($json) ? $json : ($json.data || []);\nif (commits.length < 2) {\n  return [{json:{status:'insufficient_history', message:'Not enough commits to compare'}}];\n}\nreturn [{json:{status:'ok', head: commits[0].sha, base: commits[1].sha, headMsg: commits[0].commit?.message || '', baseMsg: commits[1].commit?.message || ''}}];"
      },
      "id": "prep",
      "name": "Prepare Compare SHAs",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [920, 320]
    },
    {
      "parameters": {
        "conditions": {"string": [{"value1": "={{$json.status}}", "operation": "equals", "value2": "ok"}]}
      },
      "id": "if-ready",
      "name": "Ready to Compare?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [1140, 320]
    },
    {
      "parameters": {
        "url": "=http://gitea.kangaroo-eel.ts.net:3000/api/v1/repos/Anthony/openclaw-backups/compare/{{$json.base}}...{{$json.head}}",
        "options": {"timeout": 10000}
      },
      "id": "compare",
      "name": "Compare Commits",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [1360, 260],
      "retryOnFail": true,
      "maxTries": 3,
      "waitBetweenTries": 1500
    },
    {
      "parameters": {
        "jsCode": "const files = $json.files || [];\nconst watch = [\n  'state-backup/openclaw.json',\n  'state-backup/cron/jobs.json',\n  'state-backup/devices/paired.json',\n  'AGENTS.md','SOUL.md','USER.md','TOOLS.md','MEMORY.md','HEARTBEAT.md'\n];\nconst changed = files.map(f => f.filename).filter(f => watch.some(w => f===w));\nconst critical = changed.filter(f => f.startsWith('state-backup/'));\nreturn [{json:{drift: changed.length>0, changed, critical, changedCount: changed.length, criticalCount: critical.length}}];"
      },
      "id": "analyze",
      "name": "Analyze Drift",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [1580, 260]
    },
    {
      "parameters": {
        "conditions": {"boolean": [{"value1": "={{$json.drift}}", "operation": "true"}]}
      },
      "id": "if-drift",
      "name": "Drift Detected?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [1800, 260]
    },
    {
      "parameters": {
        "url": "http://runtipi.kangaroo-eel.ts.net:8129/message?token=AGKnHafW3FGzBlt",
        "sendBody": true,
        "contentType": "json",
        "bodyParameters": {"parameters": [
          {"name": "title", "value": "🦀 OpenClaw Drift Detected"},
          {"name": "message", "value": "={{`Changed files: ${$json.changed.join(', ')}${$json.criticalCount>0 ? '\nCritical state changed.' : ''}`}}"},
          {"name": "priority", "value": "={{$json.criticalCount>0 ? 9 : 6}}"}
        ]}
      },
      "id": "gotify",
      "name": "Gotify Drift Alert",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [2020, 220]
    },
    {
      "parameters": {
        "chatId": "1793951355",
        "text": "={{`🦀 OpenClaw drift detected\nChanged: ${$json.changed.join(', ')}${$json.criticalCount>0 ? '\n⚠️ Critical state changed' : ''}`}}"
      },
      "id": "tg",
      "name": "Telegram Drift Alert",
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.2,
      "position": [2240, 220],
      "credentials": {"telegramApi": {"name": "Telegram account"}}
    }
  ],
  "connections": {
    "Daily 06:45 AWST": {"main": [[{"node": "Set Repo Context", "type": "main", "index": 0}]]},
    "Set Repo Context": {"main": [[{"node": "Get Last 2 Commits", "type": "main", "index": 0}]]},
    "Get Last 2 Commits": {"main": [[{"node": "Prepare Compare SHAs", "type": "main", "index": 0}]]},
    "Prepare Compare SHAs": {"main": [[{"node": "Ready to Compare?", "type": "main", "index": 0}]]},
    "Ready to Compare?": {"main": [[{"node": "Compare Commits", "type": "main", "index": 0}], []]},
    "Compare Commits": {"main": [[{"node": "Analyze Drift", "type": "main", "index": 0}]]},
    "Analyze Drift": {"main": [[{"node": "Drift Detected?", "type": "main", "index": 0}]]},
    "Drift Detected?": {"main": [[{"node": "Gotify Drift Alert", "type": "main", "index": 0}], []]},
    "Gotify Drift Alert": {"main": [[{"node": "Telegram Drift Alert", "type": "main", "index": 0}]]}
  },
  "settings": {"executionOrder": "v1"},
  "active": false
}
