By Dr. FIRAS — LinkedIn
Build complete n8n workflows from natural language, validate them, and deploy them to your n8n instance — all in one step. No placeholders, no TODOs, no manual assembly required.
ALWAYS:
connections objectN8N_API_KEY is configuredNEVER:
url, path, or jsCode fields emptyTwo environment variables are needed:
VariableWhere to find itN8N_API_KEYn8n UI → Settings → API → Create API KeyN8N_BASE_URLYour instance URL, e.g. https://n8n.example.com
Set them via OpenClaw settings ( ~/.config/openclaw/settings.json):
json
{
"skills": {
"n8n-autopilot": {
"env": {
"N8N_API_KEY": "your-key",
"N8N_BASE_URL": "https://your-n8n.example.com"
}
}
}
}
Verify connectivity:
bash
python3 scripts/n8n_deploy.py ping
Follow these steps for every workflow request:
Determine four things before writing JSON:
If the request is clear, skip to generation. Do not over-ask.
Map the flow mentally:
text
Trigger → [Ingest] → [Transform] → [Branch?] → [Act] → [Respond/Store]
Use the WorkflowForge builder (see scripts/workflow_forge.py) or write
raw JSON. Output a single valid JSON object ready for n8n's "Import from JSON".
Run through the validation checklist below. Fix every issue before showing the user. You can also call:
bash
python3 scripts/workflow_inspector.py check --file workflow.json
bash
python3 scripts/n8n_deploy.py push --file workflow.json
python3 scripts/n8n_deploy.py push --file workflow.json --activate
Provide a brief node-by-node table and import/credential instructions.
json
{
"name": "Descriptive Workflow Name",
"nodes": [],
"connections": {},
"active": false,
"settings": { "executionOrder": "v1" }
}
json
{
"id": "unique-uuid-v4",
"name": "Human Readable Name",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [500, 300],
"parameters": { ... },
"credentials": { "httpHeaderAuth": { "id": "1", "name": "My Auth" } }
}
json
{
"connections": {
"Source Node Name": {
"main": [
[{ "node": "Target Node Name", "type": "main", "index": 0 }]
]
}
}
}
main = array of arrays (outer = output index, inner = targets)TypeVerPurposen8n-nodes-base.manualTrigger1Testing / manual runsn8n-nodes-base.webhook2HTTP webhook receivern8n-nodes-base.scheduleTrigger1Cron / interval
TypeVerPurposen8n-nodes-base.code2JavaScript / Pythonn8n-nodes-base.set3Map / rename / add fieldsn8n-nodes-base.if2Conditional branchn8n-nodes-base.switch3Multi-way routingn8n-nodes-base.merge3Combine streamsn8n-nodes-base.splitInBatches3Loop / batchn8n-nodes-base.noOp1No-op terminus
TypeVerPurposen8n-nodes-base.httpRequest4Any REST calln8n-nodes-base.respondToWebhook1Webhook reply
TypeVerPurposen8n-nodes-base.slack2Slack messagesn8n-nodes-base.gmail2Gmailn8n-nodes-base.googleSheets4Google Sheetsn8n-nodes-base.notion2Notionn8n-nodes-base.postgres2PostgreSQLn8n-nodes-base.telegram2Telegram
TypeVerPurpose@n8n/n8n-nodes-langchain.openAi1OpenAI completions@n8n/n8n-nodes-langchain.lmChatOpenAi1OpenAI chat model
For full credential mapping, see references/node-catalog.md.
PatternMeaning={{ $json.field }}Current item field={{ $json["field-name"] }}Hyphenated field={{ $node["Name"].json.field }}Upstream node field={{ $input.all() }}All items (Code node)={{ $input.first().json.f }}First item field={{ $now.toISO() }}Current ISO timestamp={{ $vars.MY_VAR }}Environment variable
Before outputting any workflow, verify:
Structure:
nodes array exists and is non-emptyconnections covers every non-terminal nodeid, name, type, typeVersion, position, parametersIntegrity:
url, path, jsCode)Graph:
Credentials:
credentials blockExpressions:
={{ ... }} references point to fields that upstream nodes producen8n_deploy.py)#bash
# Connectivity check
python3 scripts/n8n_deploy.py ping
# List workflows
python3 scripts/n8n_deploy.py ls [--active]
# Push (create) a workflow
python3 scripts/n8n_deploy.py push --file workflow.json [--activate]
# Inspect a deployed workflow
python3 scripts/n8n_deploy.py inspect --id <wf-id>
# Activate / deactivate
python3 scripts/n8n_deploy.py on --id <wf-id>
python3 scripts/n8n_deploy.py off --id <wf-id>
# Trigger manual execution
python3 scripts/n8n_deploy.py run --id <wf-id> [--payload '{"key":"val"}']
# View recent executions
python3 scripts/n8n_deploy.py history --id <wf-id> [--limit 10]
# Execution details
python3 scripts/n8n_deploy.py exec-detail --id <exec-id>
# Execution statistics
python3 scripts/n8n_deploy.py stats --id <wf-id> [--days 7]
# Delete workflow
python3 scripts/n8n_deploy.py rm --id <wf-id>
workflow_inspector.py)#bash
# Validate a local file
python3 scripts/workflow_inspector.py check --file workflow.json
# Validate a deployed workflow
python3 scripts/workflow_inspector.py check --id <wf-id>
# Full diagnostic report (structure + performance)
python3 scripts/workflow_inspector.py diagnose --id <wf-id> [--days 14]
# Optimization suggestions only
python3 scripts/workflow_inspector.py optimize --id <wf-id>
workflow_forge.py)#bash
# Build from a recipe YAML and deploy
python3 scripts/workflow_forge.py build --recipe recipe.yaml --deploy
# Export as JSON
python3 scripts/workflow_forge.py build --recipe recipe.yaml --output wf.json
Apply when generating workflows:
splitInBatches instead of Code-node loops.executionTimeout in settings for long-running flows.Every workflow response must include:
#NodeTypeWhat it does1Webhook TriggerwebhookReceives POST requests2Parse InputsetExtracts email and name
text
Webhook → Set (extract) → Code (transform) → Respond to Webhook
text
Schedule → HTTP Request (fetch) → Code (process) → Google Sheets (append)
text
Webhook → IF → true: Slack notify → NoOp
false: Email alert → NoOp
text
Schedule → HTTP Request → IF (ok?) → true: Process → Store
false: Slack error alert
text
n8n-autopilot/
├── SKILL.md # This file
├── README.md # Project overview
├── scripts/
│ ├── n8n_deploy.py # API client + deployment CLI
│ ├── workflow_forge.py # Programmatic workflow builder
│ └── workflow_inspector.py # Validation + diagnostics
└── references/
└── node-catalog.md # Node types & credential mapping
SymptomFixN8N_API_KEY not setExport the variable or add to OpenClaw settingsHTTP 401 UnauthorizedRegenerate API key in n8n Settings → APIConnection refusedCheck N8N_BASE_URL — include protocol and portValidation: cycle detectedBreak circular connections; use sub-workflowsExecution timeoutAdd executionTimeout in settings; optimize slow nodesRate limit (429)Insert Wait nodes; use batch processing