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 →
{
"name": "TaskManager Tool: complete_task",
"nodes": [
{
"parameters": {},
"id": "c4a0b004-0001-4000-8000-000000000001",
"name": "Execute Workflow Trigger",
"type": "n8n-nodes-base.executeWorkflowTrigger",
"typeVersion": 1.1,
"position": [
200,
400
]
},
{
"parameters": {
"mode": "runOnceForAllItems",
"jsCode": "// ============================================================\n// INPUT VALIDATION \u2014 Verify task_id is valid integer\n// ============================================================\n\nconst input = $input.first().json;\nconst taskId = parseInt(input.task_id);\n\nif (isNaN(taskId) || taskId <= 0) {\n return [{\n json: {\n success: false,\n error: 'INVARIANT_VIOLATION: task_id must be a positive integer, got: ' + input.task_id,\n timestamp: new Date().toISOString()\n }\n }];\n}\n\nreturn [{ json: { task_id: taskId, validated: true } }];"
},
"id": "c4a0b004-0001-4000-8000-000000000002",
"name": "Validate Input",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
420,
400
]
},
{
"parameters": {
"operation": "read",
"tableId": "DATA_TABLE_ID_TASKS",
"returnAll": true,
"options": {}
},
"id": "c4a0b004-0001-4000-8000-000000000003",
"name": "Data Table: Read All Tasks",
"type": "n8n-nodes-base.dataTable",
"typeVersion": 1,
"position": [
640,
400
]
},
{
"parameters": {
"mode": "runOnceForAllItems",
"jsCode": "// ============================================================\n// TASK LOOKUP + STATUS CHECK\n// Find target task, verify it exists and isn't already done.\n// ============================================================\n\nconst taskId = $('Validate Input').first().json.task_id;\nconst allTasks = $input.all().map(item => item.json);\n\n// Find target task\nconst targetTask = allTasks.find(t => parseInt(t.id) === taskId);\n\nif (!targetTask) {\n return [{\n json: {\n success: false,\n error: 'NOT_FOUND: Task #' + taskId + ' does not exist in the database.',\n available_tasks: allTasks\n .filter(t => t.status !== 'done')\n .map(t => ({ id: t.id, title: t.title, status: t.status }))\n .slice(0, 10),\n timestamp: new Date().toISOString()\n }\n }];\n}\n\nif (targetTask.status === 'done') {\n return [{\n json: {\n success: false,\n error: 'IDEMPOTENCY_CHECK: Task #' + taskId + ' (\"' + targetTask.title + '\") is already marked as done (completed at ' + targetTask.completed_at + '). No action taken.',\n task: targetTask,\n timestamp: new Date().toISOString()\n }\n }];\n}\n\n// Task is valid and not yet complete\nreturn [{\n json: {\n success: true,\n target_task: targetTask,\n all_tasks: allTasks,\n proceed: true\n }\n}];"
},
"id": "c4a0b004-0001-4000-8000-000000000004",
"name": "Lookup & Status Check",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
860,
400
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"id": "proceed-check",
"leftValue": "={{ $json.proceed }}",
"rightValue": true,
"operator": {
"type": "boolean",
"operation": "equals",
"singleValue": true
}
}
],
"combinator": "and"
},
"options": {}
},
"id": "c4a0b004-0001-4000-8000-000000000005",
"name": "Proceed Gate",
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
1080,
400
]
},
{
"parameters": {
"mode": "raw",
"jsonOutput": "={\n \"id\": {{ $json.target_task.id }},\n \"status\": \"done\",\n \"completed_at\": \"{{ new Date().toISOString() }}\"\n}",
"options": {}
},
"id": "c4a0b004-0001-4000-8000-000000000006",
"name": "Prepare Update",
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
1300,
300
]
},
{
"parameters": {
"operation": "update",
"tableId": "DATA_TABLE_ID_TASKS",
"columns": {
"mappingMode": "autoMapInputData"
},
"options": {}
},
"id": "c4a0b004-0001-4000-8000-000000000007",
"name": "Data Table: Mark Done",
"type": "n8n-nodes-base.dataTable",
"typeVersion": 1,
"position": [
1520,
300
]
},
{
"parameters": {
"mode": "runOnceForAllItems",
"jsCode": "// ============================================================\n// DAG TRAVERSAL ENGINE\n// After completing a task, traverse the dependency graph\n// to find tasks that are now unblocked.\n// ============================================================\n\nconst lookupData = $('Lookup & Status Check').first().json;\nconst completedTask = lookupData.target_task;\nconst completedId = String(completedTask.id);\nconst allTasks = lookupData.all_tasks;\nconst now = new Date();\n\n// --- Find newly unblocked tasks ---\nconst unblockedTasks = [];\n\nfor (const task of allTasks) {\n if (task.status === 'done' || task.status === 'cancelled') continue;\n if (!task.depends_on || task.depends_on === '') continue;\n\n const depIds = task.depends_on.split(',').map(d => d.trim());\n \n // Only check tasks that depend on the completed task\n if (!depIds.includes(completedId)) continue;\n\n // Check if ALL dependencies are now satisfied\n const allDepsSatisfied = depIds.every(depId => {\n if (depId === completedId) return true; // just completed\n const depTask = allTasks.find(t => String(t.id) === depId);\n return depTask && depTask.status === 'done';\n });\n\n if (allDepsSatisfied) {\n unblockedTasks.push({\n id: task.id,\n title: task.title,\n priority: task.priority,\n category: task.category\n });\n }\n}\n\n// --- Compute completion metrics ---\nconst createdAt = new Date(completedTask.created_at);\nconst completedAt = now;\nconst elapsedMs = completedAt - createdAt;\nconst elapsedHours = Math.round(elapsedMs / (1000 * 60 * 60) * 10) / 10;\nconst elapsedDays = Math.round(elapsedMs / (1000 * 60 * 60 * 24) * 10) / 10;\n\nlet elapsedHuman;\nif (elapsedDays >= 1) {\n elapsedHuman = elapsedDays + ' days';\n} else {\n elapsedHuman = elapsedHours + ' hours';\n}\n\n// --- Count completed tasks for productivity metric ---\nconst doneTasks = allTasks.filter(t => t.status === 'done').length + 1; // +1 for this one\nconst totalTasks = allTasks.length;\n\n// --- Check recurrence ---\nlet recurrenceNote = null;\nif (completedTask.recurrence_rule && completedTask.recurrence_rule !== 'none') {\n recurrenceNote = 'This is a recurring task (' + completedTask.recurrence_rule + '). A new instance should be created.';\n}\n\n// --- Build response ---\nconst response = {\n success: true,\n operation: 'task_completed',\n completed_task: {\n id: completedTask.id,\n title: completedTask.title,\n category: completedTask.category,\n priority_was: completedTask.priority,\n eisenhower_was: completedTask.eisenhower_quadrant,\n created_at: completedTask.created_at,\n completed_at: completedAt.toISOString()\n },\n metrics: {\n elapsed_human: elapsedHuman,\n elapsed_hours: elapsedHours,\n tasks_done_total: doneTasks,\n tasks_remaining: totalTasks - doneTasks,\n completion_rate: Math.round((doneTasks / totalTasks) * 100) + '%'\n },\n dependency_graph: {\n unblocked_tasks: unblockedTasks,\n unblocked_count: unblockedTasks.length\n },\n recurrence: recurrenceNote,\n timestamp: completedAt.toISOString()\n};\n\nreturn [{ json: response }];"
},
"id": "c4a0b004-0001-4000-8000-000000000008",
"name": "DAG Traversal & Response",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1740,
300
]
}
],
"connections": {
"Execute Workflow Trigger": {
"main": [
[
{
"node": "Validate Input",
"type": "main",
"index": 0
}
]
]
},
"Validate Input": {
"main": [
[
{
"node": "Data Table: Read All Tasks",
"type": "main",
"index": 0
}
]
]
},
"Data Table: Read All Tasks": {
"main": [
[
{
"node": "Lookup & Status Check",
"type": "main",
"index": 0
}
]
]
},
"Lookup & Status Check": {
"main": [
[
{
"node": "Proceed Gate",
"type": "main",
"index": 0
}
]
]
},
"Proceed Gate": {
"main": [
[
{
"node": "Prepare Update",
"type": "main",
"index": 0
}
],
[]
]
},
"Prepare Update": {
"main": [
[
{
"node": "Data Table: Mark Done",
"type": "main",
"index": 0
}
]
]
},
"Data Table: Mark Done": {
"main": [
[
{
"node": "DAG Traversal & Response",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
},
"staticData": null,
"tags": [
{
"name": "Tool",
"id": "4"
},
{
"name": "Task Manager",
"id": "2"
}
]
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
TaskManager Tool: complete_task. Uses executeWorkflowTrigger, dataTable. Event-driven trigger; 8 nodes.
Source: https://github.com/neuron7xLab/ai-automation-portfolio/blob/main/agent-patterns/task-manager/wf4-tool-complete-task.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.
Reagendamiento. Uses executeWorkflowTrigger, redis, n8n-nodes-evolution-api, dataTable. Event-driven trigger; 73 nodes.
Agendamiento. Uses n8n-nodes-evolution-api, redis, dataTable, executeWorkflowTrigger. Event-driven trigger; 60 nodes.
This workflow provides a reusable error handling, audit logging, and observability pattern for n8n workflows using two n8n custom Data Tables: and .
If you're in need of a quick and dirty cache that doesn't need anything other than the current version of N8N, boy do I have a dodgy script for you to try!
TaskManager Tool: add_task. Uses executeWorkflowTrigger, dataTable. Event-driven trigger; 6 nodes.