The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"id": "ghiath-vault-watch",
"name": "Ghiath Vault Watch",
"nodes": [
{
"parameters": {
"rule": {
"interval": [
{
"field": "seconds",
"secondsInterval": 30
}
]
}
},
"id": "vw-schedule",
"name": "Every 30s",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.2,
"position": [
260,
300
]
},
{
"parameters": {
"jsCode": "// Poll the vault every interval and trigger the agent that owns any folder where\n// a new \"open\" note appeared. Replaces the old localFileTrigger approach, which\n// depended on the Local File Trigger node (unavailable in this n8n image, shows\n// as \"?\") and on inotify seeing subfolders. This uses only fs + a schedule, the\n// same proven pattern as the reminder scheduler.\n//\n// Dedup: workflow static data remembers, per note, the content hash we last\n// fired on. We fire once per distinct content. When the agent flips status to\n// \"doing\"/\"done\" the content changes AND it is no longer \"open\", so it is never\n// re-triggered; and an unchanged still-\"open\" note is not spammed every poll.\nconst fs = require('fs');\nconst path = require('path');\nconst crypto = require('crypto');\n\nconst ROOT = '/data/vault';\nconst DEFAULT_ROUTES = {\n assistant: { port: 8642, model: 'deepseek/deepseek-v2-flash', folder: 'scratchpads' },\n engineer: { port: 8643, model: 'anthropic/claude-opus-4-8', folder: 'projects' },\n researcher: { port: 8644, model: 'z-ai/glm-4.6', folder: 'memory' },\n};\nlet routes = DEFAULT_ROUTES;\ntry { if ($env.GHIATH_ROUTES) routes = JSON.parse($env.GHIATH_ROUTES); } catch (e) {}\n\nconst agentByFolder = {};\nfor (const [name, cfg] of Object.entries(routes)) { if (cfg.folder) agentByFolder[cfg.folder] = name; }\nconst folders = Object.keys(agentByFolder);\nif (!folders.length) return [];\n\nconst store = $getWorkflowStaticData('global');\nconst fired = store.fired || (store.fired = {});\n\nconst out = [];\nconst seen = new Set();\n\nfor (const folder of folders) {\n const dir = path.join(ROOT, folder);\n let files = [];\n try { files = fs.readdirSync(dir).filter((f) => f.endsWith('.md')); } catch (e) { continue; }\n\n for (const f of files) {\n const key = folder + '/' + f;\n seen.add(key);\n const fp = path.join(dir, f);\n let raw;\n try { raw = fs.readFileSync(fp, 'utf8'); } catch (e) { continue; }\n\n let status = 'open'; // notes without front-matter are human-created open tasks\n const fm = raw.match(/^---\\n([\\s\\S]*?)\\n---/);\n if (fm) {\n const s = fm[1].match(/^status:\\s*(\\S+)/m);\n if (s) status = s[1].toLowerCase();\n }\n if (status !== 'open') continue;\n\n const hash = crypto.createHash('sha256').update(raw).digest('hex');\n if (fired[key] === hash) continue; // already fired for this exact content\n fired[key] = hash;\n\n const agent = agentByFolder[folder];\n const r = routes[agent];\n const url = 'http://host.docker.internal:' + r.port + '/v1/chat/completions';\n const hostPath = key;\n const prompt =\n 'An open note was placed in your folder: ' + hostPath +\n '\\nRead it, set its status to \"doing\", act on it, then set its status to \"done\". ' +\n 'Record your result as a note with type \"result\", status \"done\", owner yourself. ' +\n 'If the task should move to another agent, drop an \"open\" note in that agent\\'s folder with owner set to them.';\n\n out.push({ json: { agent, folder, url, model: r.model, prompt, note: hostPath } });\n }\n}\n\n// Forget notes that no longer exist so the map cannot grow forever.\nfor (const k of Object.keys(fired)) { if (!seen.has(k)) delete fired[k]; }\n\nreturn out;\n"
},
"id": "vw-scan",
"name": "Scan Open Handoffs",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
520,
300
]
},
{
"parameters": {
"method": "POST",
"url": "={{ $json.url }}",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ JSON.stringify({ model: $json.model, messages: [ { role: 'user', content: $json.prompt } ] }) }}",
"options": {
"timeout": 300000
}
},
"id": "call-hermes",
"name": "Trigger Owning Agent",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
780,
300
],
"onError": "continueRegularOutput"
}
],
"connections": {
"Every 30s": {
"main": [
[
{
"node": "Scan Open Handoffs",
"type": "main",
"index": 0
}
]
]
},
"Scan Open Handoffs": {
"main": [
[
{
"node": "Trigger Owning Agent",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
},
"active": false
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Ghiath Vault Watch. Uses httpRequest. Scheduled trigger; 3 nodes.
Source: https://github.com/isfaaghyth/ghiath/blob/b47799947d74f824dc41303fdd291270701edc6e/n8n-workflows/vault-watch.json — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
Proactively alert to service endpoint changes and pod/container issues (Pending, Not Ready, Restart spikes) using Prometheus metrics, formatted and sent to Slack.
Tired of being let down by the Google Drive Trigger? Rather not exhaust system resources by polling every minute? Then this workflow is for you!
Triggers at a regular interval or via a webhook request. Solves AWS WAF challenge then makes a request to fetch the product page. Extracts product data from the retrieved HTML page. Compares the curre
🔄 Monitor Container Images from Docker Hub or GHCR.
Automatically monitor billable Kimai projects every weekday morning and receive a formatted HTML email when a project deadline is approaching or its hour budget is running low. If nothing requires att