{
 "name": "Quiet watchdog — tell me when a workflow stops running",
 "nodes": [
  {
   "id": "trigger",
   "name": "Every 30 minutes",
   "type": "n8n-nodes-base.scheduleTrigger",
   "typeVersion": 1.3,
   "position": [
    0,
    340
   ],
   "parameters": {
    "rule": {
     "interval": [
      {
       "field": "minutes",
       "minutesInterval": 30
      }
     ]
    }
   }
  },
  {
   "id": "settings",
   "name": "Settings",
   "type": "n8n-nodes-base.set",
   "typeVersion": 3.4,
   "position": [
    220,
    340
   ],
   "parameters": {
    "assignments": {
     "assignments": [
      {
       "id": "quiet",
       "name": "quietAfterHours",
       "value": 6,
       "type": "number"
      },
      {
       "id": "ignore",
       "name": "ignoreNamesContaining",
       "value": "watchdog",
       "type": "string"
      }
     ]
    },
    "options": {}
   }
  },
  {
   "id": "workflows",
   "name": "Active workflows",
   "type": "n8n-nodes-base.n8n",
   "typeVersion": 1,
   "position": [
    440,
    240
   ],
   "parameters": {
    "resource": "workflow",
    "operation": "getAll",
    "returnAll": true,
    "filters": {
     "activeWorkflows": true
    },
    "requestOptions": {}
   }
  },
  {
   "id": "executions",
   "name": "Recent executions",
   "type": "n8n-nodes-base.n8n",
   "typeVersion": 1,
   "position": [
    440,
    440
   ],
   "parameters": {
    "resource": "execution",
    "operation": "getAll",
    "returnAll": false,
    "limit": 250,
    "filters": {},
    "requestOptions": {}
   }
  },
  {
   "id": "merge",
   "name": "Both lists",
   "type": "n8n-nodes-base.merge",
   "typeVersion": 3,
   "position": [
    660,
    340
   ],
   "parameters": {
    "mode": "combine",
    "combineBy": "combineByPosition",
    "options": {
     "includeUnpaired": true
    }
   }
  },
  {
   "id": "compare",
   "name": "Who went quiet?",
   "type": "n8n-nodes-base.code",
   "typeVersion": 2,
   "position": [
    880,
    340
   ],
   "parameters": {
    "jsCode": "// One item per workflow that is ON but has not run for longer than its threshold.\nconst settings = $('Settings').first().json;\nconst defaultHours = Number(settings.quietAfterHours || 6);\nconst ignore = String(settings.ignoreNamesContaining || '').toLowerCase();\nconst workflows = $('Active workflows').all().map(i => i.json);\nconst executions = $('Recent executions').all().map(i => i.json);\nconst now = Date.now();\nconst lastRun = {};\nfor (const e of executions) {\n  if (e.mode === 'manual') continue;             // someone pressing Test is not the rhythm\n  const t = Date.parse(e.startedAt || e.stoppedAt || 0);\n  if (!t) continue;\n  const id = String(e.workflowId);\n  if (!lastRun[id] || t > lastRun[id]) lastRun[id] = t;\n}\nconst out = [];\nfor (const w of workflows) {\n  const name = String(w.name || '');\n  if (ignore && name.toLowerCase().includes(ignore)) continue;\n  const m = name.match(/\\[quiet:(\\d+)h\\]/i);\n  const hours = m ? Number(m[1]) : defaultHours;\n  const last = lastRun[String(w.id)];\n  if (!last) continue;                            // never ran in the window we can see: nothing to compare with\n  const ageH = (now - last) / 36e5;\n  if (ageH > hours) out.push({ json: { id: w.id, name, lastRun: new Date(last).toISOString(), hoursQuiet: Math.round(ageH * 10) / 10, threshold: hours } });\n}\nreturn out;"
   }
  },
  {
   "id": "any",
   "name": "Any quiet?",
   "type": "n8n-nodes-base.if",
   "typeVersion": 2.2,
   "position": [
    1100,
    340
   ],
   "parameters": {
    "conditions": {
     "options": {
      "caseSensitive": true,
      "leftValue": "",
      "typeValidation": "loose",
      "version": 2
     },
     "conditions": [
      {
       "id": "has",
       "leftValue": "={{ $json.name }}",
       "rightValue": "",
       "operator": {
        "type": "string",
        "operation": "notEmpty",
        "singleValue": true
       }
      }
     ],
     "combinator": "and"
    },
    "options": {}
   }
  },
  {
   "id": "summarize",
   "name": "One message",
   "type": "n8n-nodes-base.code",
   "typeVersion": 2,
   "position": [
    1320,
    340
   ],
   "parameters": {
    "jsCode": "const rows = $input.all().map(i => i.json);\nconst lines = rows.map(r => `• ${r.name} — nothing for ${r.hoursQuiet} h (threshold ${r.threshold} h), last run ${r.lastRun}`);\nreturn [{ json: { count: rows.length, text: `${rows.length} workflow(s) went quiet:\\n${lines.join('\\n')}\\n\\nIf events should be coming in, check the trigger's credential first (expired OAuth is the usual cause).` } }];"
   }
  },
  {
   "id": "send",
   "name": "Send alert",
   "type": "n8n-nodes-base.gmail",
   "typeVersion": 2.1,
   "position": [
    1540,
    340
   ],
   "parameters": {
    "resource": "message",
    "operation": "send",
    "sendTo": "",
    "subject": "=n8n: {{ $json.count }} workflow(s) went quiet",
    "emailType": "text",
    "message": "={{ $json.text }}",
    "options": {}
   },
   "notes": "Put your own address in sendTo. Or replace this node with Slack / Telegram 'send message' and map {{ $json.text }}."
  },
  {
   "id": "sticky-how",
   "name": "How this works",
   "type": "n8n-nodes-base.stickyNote",
   "typeVersion": 1,
   "position": [
    0,
    0
   ],
   "parameters": {
    "height": 300,
    "width": 420,
    "content": "## Quiet watchdog\nEvery 30 minutes: list the active workflows, list recent executions, and compare.\nA workflow that is ON but has not run for longer than its threshold is reported once.\n\n**You fill in:**\n1. `n8n` nodes → an n8n API credential (Settings → n8n API → Create; read-only scope is enough).\n2. `Settings` → `quietAfterHours` (default 6). A workflow name containing `[quiet:24h]` overrides it for that workflow.\n3. `Send alert` → your Gmail (or swap it for Slack / Telegram).\n\nIt reports only workflows that have run at least once before, so brand-new ones stay silent.\nFree, from usebridgecore.com/guard — the hosted version also learns each workflow's own rhythm and checks that steps ask before sending or paying."
   }
  }
 ],
 "connections": {
  "Every 30 minutes": {
   "main": [
    [
     {
      "node": "Settings",
      "type": "main",
      "index": 0
     }
    ]
   ]
  },
  "Settings": {
   "main": [
    [
     {
      "node": "Active workflows",
      "type": "main",
      "index": 0
     },
     {
      "node": "Recent executions",
      "type": "main",
      "index": 0
     }
    ]
   ]
  },
  "Active workflows": {
   "main": [
    [
     {
      "node": "Both lists",
      "type": "main",
      "index": 0
     }
    ]
   ]
  },
  "Recent executions": {
   "main": [
    [
     {
      "node": "Both lists",
      "type": "main",
      "index": 1
     }
    ]
   ]
  },
  "Both lists": {
   "main": [
    [
     {
      "node": "Who went quiet?",
      "type": "main",
      "index": 0
     }
    ]
   ]
  },
  "Who went quiet?": {
   "main": [
    [
     {
      "node": "Any quiet?",
      "type": "main",
      "index": 0
     }
    ]
   ]
  },
  "Any quiet?": {
   "main": [
    [
     {
      "node": "One message",
      "type": "main",
      "index": 0
     }
    ],
    []
   ]
  },
  "One message": {
   "main": [
    [
     {
      "node": "Send alert",
      "type": "main",
      "index": 0
     }
    ]
   ]
  }
 },
 "settings": {
  "executionOrder": "v1"
 },
 "pinData": {}
}