n8n Setup and Configuration #
This document explains how n8n is configured to orchestrate the Tofie workflow automation.
Overview #
n8n serves as the central automation hub, receiving webhooks from Linear and executing Tofie scripts on the Coder instance via SSH.
Environment: bonsai.app.n8n.cloud (cloud-hosted)
Workflow Structure #
Main Tofie Workflow #
Webhook URL: https://bonsai.app.n8n.cloud/webhook/tofie-event
Method: POST
Authentication: Webhook signature validation
Nodes:
-
Webhook Trigger
- Receives Linear webhook events
- Returns immediate 200 OK response
-
Parse Linear Event
- Extracts event type (Comment.created, Issue.updated, etc.)
- Parses comment body for Tofie mentions
-
Command Router (Switch node)
- Routes to appropriate workflow based on command:
plan→ Planning workflowimplement→ Implementation workflowreview→ Review workflowpr→ PR submission workflow
- Routes to appropriate workflow based on command:
-
Extract Issue Context
- Pulls full issue details from Linear API
- Gets all comments on the issue
- Extracts project information
-
Update Linear Status (HTTP Request)
- Changes issue status (e.g., Todo → Planning)
- Adds comment confirming work started
-
Build Script Input (Function node)
const branchName = `${user}/${issueKey}-${slugify(issueTitle)}`; return { branchName, issueIdentifier: items[0].json.issue.identifier, agentSessionId: $execution.id, project: items[0].json.issue.project, issue: items[0].json.issue }; -
SSH Execute (SSH node)
- Connects to Coder instance
- Executes appropriate Tofie script
- Pipes JSON input via stdin
- Captures stdout/stderr
-
Parse Script Output (Function node)
const result = JSON.parse(items[0].json.stdout); if (!result.success) { throw new Error(result.error || 'Script execution failed'); } return result; -
Update Linear with Result (HTTP Request)
- Posts plan/implementation summary as comment
- Updates issue status (e.g., Planning → Planned)
- Adds PR link if created
-
Error Handler (Error Workflow)
- Catches any failures
- Posts error message to Linear
- Logs to n8n error log
Configuration #
Credentials #
Linear API:
- Type: HTTP Header Auth
- Header Name:
Authorization - Value:
Bearer <LINEAR_API_KEY>
SSH Connection:
- Type: SSH
- Host:
coder-instance.internal - Port:
22 - Username:
coder - Private Key:
<SSH_PRIVATE_KEY>
GitHub (for PR operations):
- Stored in Doppler on Coder instance
- Retrieved by scripts via
doppler secrets get GITHUB_TOKEN
Environment Variables #
Set in n8n workflow settings:
LINEAR_WORKSPACE_ID=<workspace-id>
LINEAR_WEBHOOK_SECRET=<webhook-secret>
CODER_HOST=coder-instance.internal
TOFIE_SCRIPTS_PATH=/home/coder/bonsai/tools/local/scripts/tofie
Webhook Signature Validation #
Purpose: Verify webhooks are from Linear, not malicious actors
Implementation:
const crypto = require('crypto');
const signature = $node["Webhook"].json.headers['linear-signature'];
const payload = JSON.stringify($node["Webhook"].json.body);
const secret = $env.LINEAR_WEBHOOK_SECRET;
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
if (signature !== expectedSignature) {
throw new Error('Invalid webhook signature');
}
return items;
Command Parsing #
Function node logic:
const comment = items[0].json.data.body.toLowerCase();
// Check for Tofie mention
if (!comment.includes('@tofie')) {
return []; // Skip, not a Tofie command
}
// Extract command
let command = 'unknown';
if (comment.includes('plan')) command = 'plan';
else if (comment.includes('implement')) command = 'implement';
else if (comment.includes('review')) command = 'review';
else if (comment.includes('pr')) command = 'pr';
// Check thoroughness for planning
let thoroughness = 'medium';
if (comment.includes('thorough') || comment.includes('deep')) {
thoroughness = 'very thorough';
}
return [{
json: {
command,
thoroughness,
...items[0].json
}
}];
Script Execution #
SSH Command Template:
cd {{$env.TOFIE_SCRIPTS_PATH}} && \
./{{$node["Command Router"].json.command}}.sh
stdin: JSON from “Build Script Input” node stdout: Captured and parsed as JSON stderr: Logged for debugging
Timeout: 30 minutes (configurable per command)
Error Handling #
Retry Logic #
Configured retries:
- Webhook processing: No retry (immediate response required)
- SSH execution: 3 retries with exponential backoff
- Retry 1: After 30 seconds
- Retry 2: After 2 minutes
- Retry 3: After 5 minutes
- Linear API calls: 5 retries with backoff
Error Workflow #
Separate workflow triggered on any error:
-
Catch Error
- Receives error details and context
-
Format Error Message
❌ Tofie Error **Command**: {{$json.command}} **Error**: {{$json.error}} Please check logs or contact DevOps if this persists. -
Post to Linear
- Adds error comment to issue
- Optionally reverts status change
-
Log to Monitoring
- Send to logging service (if configured)
- Track error metrics
Status Transitions #
Configured transitions:
| Command | Initial Status | During Execution | Success Status | Error Status |
|---|---|---|---|---|
| plan | Todo, Backlog | Planning | Planned | Todo |
| implement | Planned | In Progress | In Review | Planned |
| review | In Review | Under Review | Reviewed | In Review |
| pr | In Review, Reviewed | PR Creating | PR Created | In Review |
Linear API Integration #
GraphQL Queries #
Get Issue Details:
query GetIssue($id: String!) {
issue(id: $id) {
id
identifier
title
description
state { id name }
project { id name key }
comments { nodes { id body createdAt user { name } } }
labels { nodes { id name } }
}
}
Update Issue Status:
mutation UpdateIssue($id: String!, $stateId: String!) {
issueUpdate(id: $id, input: { stateId: $stateId }) {
success
issue { id state { name } }
}
}
Create Comment:
mutation CreateComment($issueId: String!, $body: String!) {
commentCreate(input: { issueId: $issueId, body: $body }) {
success
comment { id }
}
}
Monitoring #
Workflow Execution Tracking #
n8n automatically tracks:
- Execution count
- Success/failure rate
- Average execution time
- Active executions
Access: n8n UI → Executions tab
Custom Metrics #
Tracked via function nodes:
- Command type distribution
- Planning vs subagent usage
- PR creation success rate
- Average time by workflow stage
Debugging #
Execution Logs #
View in n8n UI:
- Go to Executions tab
- Click on execution ID
- View node-by-node execution data
Each node shows:
- Input data
- Output data
- Execution time
- Error details (if any)
Test Webhooks #
Manual testing:
- Go to Webhook node in workflow
- Click “Listen for Test Event”
- Trigger event from Linear (or use curl)
- View test execution results
curl example:
curl -X POST https://bonsai.app.n8n.cloud/webhook/tofie-event \
-H "Content-Type: application/json" \
-H "linear-signature: <signature>" \
-d '{ "action": "create", "type": "Comment", ... }'
SSH Debugging #
Test SSH connection:
ssh -i ~/.ssh/tofie_key coder@coder-instance.internal \
"echo 'SSH connection successful'"
Test script execution:
echo '{"branchName": "test", ...}' | \
ssh coder@coder-instance.internal \
"cd /home/coder/bonsai/tools/local/scripts/tofie && ./planning.sh"
Maintenance #
Regular Tasks #
Weekly:
- Review failed executions
- Check error rate trends
- Validate webhook signature
Monthly:
- Update credentials if rotated
- Review and optimize workflows
- Clean up old execution logs
Workflow Updates #
Best practices:
- Test changes in n8n’s “Test” environment first
- Export workflow before making changes (backup)
- Use version control for workflow JSON
- Document changes in workflow description
Export workflow:
# In n8n UI: Workflow → Settings → Download
# Or use n8n API:
curl -X GET https://bonsai.app.n8n.cloud/api/v1/workflows/123 \
-H "X-N8N-API-KEY: <api-key>"
Security #
Webhook Security #
- ✅ Signature validation enabled
- ✅ HTTPS only
- ✅ No sensitive data in webhooks (IDs only, fetch full data via API)
SSH Security #
- ✅ Key-based authentication (no passwords)
- ✅ Limited user permissions on Coder instance
- ✅ Keys rotated every 90 days
- ✅ Connection from n8n cloud IP only (firewall rule)
Credential Management #
- ✅ n8n credential vault (encrypted at rest)
- ✅ Doppler for GitHub tokens
- ✅ No credentials in workflow JSON
- ✅ Principle of least privilege
Troubleshooting #
See Troubleshooting Guide for common issues and solutions.
Related Documentation #
- Architecture - System architecture overview
- Linear Integration - Linear webhook and API details
- Workflows - Individual workflow documentation