add_checkpoint
Add checkpoint save/restore capability to n8n workflows, enabling workflow state preservation and recovery at specific nodes.
Instructions
Add a checkpoint save/restore capability to a workflow
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | Path to the workflow file | |
| checkpointName | Yes | Name for the checkpoint | |
| afterNode | No | Node to add checkpoint after (for saving) | |
| addRestore | No | Also add checkpoint restore at workflow start |
Implementation Reference
- src/tools/handler.ts:326-386 (handler)Main handler for 'add_checkpoint' tool: reads workflow, injects checkpoint logic via TrackingInjector, saves modified workflow.case 'add_checkpoint': const checkpointPath = args?.path as string; const checkpointName = args?.checkpointName as string; const afterNode = args?.afterNode as string; const addRestore = args?.addRestore as boolean; // Read workflow const fullCheckpointPath = path.join(this.workflowsPath, checkpointPath); const checkpointWorkflowContent = await fs.readFile(fullCheckpointPath, 'utf-8'); const checkpointWorkflow = JSON.parse(checkpointWorkflowContent); // Use configured storage URL or environment variable const checkpointStorageUrl = this.trackingConfig.storageUrl || process.env.WORKFLOW_STORAGE_URL; if (!checkpointStorageUrl) { return { content: [{ type: 'text', text: '❌ Storage URL not configured. Use configure_tracking to set storageUrl or set WORKFLOW_STORAGE_URL environment variable.' }] }; } // Create injector const checkpointInjector = new TrackingInjector({ enabled: true, storageUrl: checkpointStorageUrl, enableCheckpoints: true }); // Add checkpoint let modifiedCheckpointWorkflow = checkpointWorkflow; if (afterNode) { // Add save checkpoint after specified node modifiedCheckpointWorkflow = await checkpointInjector.injectTracking(checkpointWorkflow, { checkpoints: [{ afterNode, checkpointName }] }); } if (addRestore) { // Add restore checkpoint at workflow start modifiedCheckpointWorkflow = await checkpointInjector.addCheckpointRestore( modifiedCheckpointWorkflow, checkpointName ); } // Save modified workflow await fs.writeFile(fullCheckpointPath, JSON.stringify(modifiedCheckpointWorkflow, null, 2)); return { content: [{ type: 'text', text: `✅ Added checkpoint "${checkpointName}" to workflow\\n\\n` + (afterNode ? `Save checkpoint after: ${afterNode}\\n` : '') + (addRestore ? `Restore checkpoint at workflow start\\n` : '') + `Storage URL: ${checkpointStorageUrl}` }] };
- src/tools/registry.ts:490-515 (registration)Tool registration including name, description, and input schema for 'add_checkpoint' in getToolDefinitions().{ name: 'add_checkpoint', description: 'Add a checkpoint save/restore capability to a workflow', inputSchema: { type: 'object', properties: { path: { type: 'string', description: 'Path to the workflow file', }, checkpointName: { type: 'string', description: 'Name for the checkpoint', }, afterNode: { type: 'string', description: 'Node to add checkpoint after (for saving)', }, addRestore: { type: 'boolean', description: 'Also add checkpoint restore at workflow start', }, }, required: ['path', 'checkpointName'], }, },
- Helper method addCheckpointRestore in TrackingInjector: adds restore node and IF node for checkpoint restoration at workflow start.async addCheckpointRestore(workflow: any, checkpointName: string): Promise<any> { const modifiedWorkflow = JSON.parse(JSON.stringify(workflow)); // Create checkpoint restore node const restoreNode = this.tracker.createCheckpointRestoreNode( checkpointName, { x: 100, y: 200 } ); // Create IF node to check if checkpoint exists const ifNode = { parameters: { conditions: { boolean: [ { value1: '={{$json.checkpointData}}', operation: 'isNotEmpty' } ] } }, id: 'if_checkpoint_' + Date.now(), name: `Check ${checkpointName} Exists`, type: 'n8n-nodes-base.if', typeVersion: 2, position: [350, 200] }; // Add nodes modifiedWorkflow.nodes.push(restoreNode); modifiedWorkflow.nodes.push(ifNode); // Connect restore to IF modifiedWorkflow.connections[restoreNode.name] = { main: [[{ node: ifNode.name, type: 'main', index: 0 }]] }; // IF node will have two outputs: true (has checkpoint) and false (no checkpoint) // These need to be connected to appropriate workflow paths return modifiedWorkflow; }
- Private helper addCheckpoints: inserts checkpoint save nodes after specified target nodes in the workflow, rewiring connections.private addCheckpoints(workflow: any, checkpoints: Array<{ afterNode: string; checkpointName: string }>) { for (const checkpoint of checkpoints) { const targetNode = workflow.nodes.find((n: any) => n.name === checkpoint.afterNode); if (!targetNode) continue; // Create checkpoint node const checkpointNode = this.tracker.createCheckpointNode( checkpoint.checkpointName, { x: targetNode.position[0] + 250, y: targetNode.position[1] + 50 } ); // Add to workflow workflow.nodes.push(checkpointNode.node); // Insert checkpoint between target and its connections const existingConnections = workflow.connections[checkpoint.afterNode]?.main?.[0] || []; // Connect checkpoint to target's destinations if (existingConnections.length > 0) { workflow.connections[checkpointNode.node.name] = { main: [existingConnections] }; } // Connect target to checkpoint workflow.connections[checkpoint.afterNode] = { main: [[{ node: checkpointNode.node.name, type: 'main', index: 0 }]] }; } }
- src/tools/registry.ts:493-513 (schema)Input schema definition for the 'add_checkpoint' tool validation.inputSchema: { type: 'object', properties: { path: { type: 'string', description: 'Path to the workflow file', }, checkpointName: { type: 'string', description: 'Name for the checkpoint', }, afterNode: { type: 'string', description: 'Node to add checkpoint after (for saving)', }, addRestore: { type: 'boolean', description: 'Also add checkpoint restore at workflow start', }, }, required: ['path', 'checkpointName'],