@n8n-as-code/skills 1.10.1-next.7 β 2.0.0-next.57
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/agent-skills/n8n-architect/SKILL.md +379 -0
- package/dist/agent-skills/n8n-manager/SKILL.md +116 -0
- package/dist/assets/n8n-credentials-ontology.json +24962 -0
- package/dist/assets/n8n-docs-complete.json +1 -1
- package/dist/assets/n8n-knowledge-index.json +1 -1
- package/dist/assets/n8n-nodes-index.json +7711 -5
- package/dist/assets/n8n-nodes-technical.json +15417 -5
- package/dist/assets/workflows-index.json +1 -1
- package/dist/commands/skills-commander.d.ts.map +1 -1
- package/dist/commands/skills-commander.js +32 -5
- package/dist/commands/skills-commander.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/services/ai-context-generator.d.ts +7 -31
- package/dist/services/ai-context-generator.d.ts.map +1 -1
- package/dist/services/ai-context-generator.js +80 -885
- package/dist/services/ai-context-generator.js.map +1 -1
- package/dist/services/cli-command-resolver.d.ts +14 -0
- package/dist/services/cli-command-resolver.d.ts.map +1 -0
- package/dist/services/cli-command-resolver.js +52 -0
- package/dist/services/cli-command-resolver.js.map +1 -0
- package/package.json +6 -5
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { fileURLToPath } from 'url';
|
|
4
|
+
import { resolveN8nacCommandRefs } from './cli-command-resolver.js';
|
|
4
5
|
// Helper to get __dirname in ESM
|
|
5
6
|
const _filename = typeof __filename !== 'undefined'
|
|
6
7
|
? __filename
|
|
@@ -9,271 +10,57 @@ const _dirname = typeof __dirname !== 'undefined'
|
|
|
9
10
|
? __dirname
|
|
10
11
|
: (_filename ? path.dirname(_filename) : '');
|
|
11
12
|
export class AiContextGenerator {
|
|
12
|
-
nodesIndex = null;
|
|
13
13
|
constructor() { }
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const
|
|
14
|
+
getCommandRefs(distTag, cliCommandOverride, projectRoot) {
|
|
15
|
+
return resolveN8nacCommandRefs({
|
|
16
|
+
projectRoot,
|
|
17
|
+
distTag,
|
|
18
|
+
override: cliCommandOverride,
|
|
19
|
+
env: projectRoot ? process.env : {},
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
getAgentSkillContent(skillName, distTag, options = {}, projectRoot) {
|
|
23
|
+
const { cliCmd, skillsCmd } = this.getCommandRefs(distTag, options.cliCommandOverride, projectRoot);
|
|
24
|
+
const managerCmd = options.managerCommandOverride || (projectRoot ? process.env.N8N_MANAGER_COMMAND : undefined) || 'n8n-manager';
|
|
25
|
+
const contextRootHint = projectRoot
|
|
26
|
+
? `Generated context root hint: \`${path.resolve(projectRoot)}\`. If this path exists, run workspace commands from there.`
|
|
27
|
+
: 'Generated context root hint: not embedded. Use the shell launch directory or the workspace path explicitly given by the user.';
|
|
28
|
+
return this.readCanonicalAgentSkill(skillName)
|
|
29
|
+
.replaceAll('{{N8NAC_CMD}}', cliCmd)
|
|
30
|
+
.replaceAll('{{N8NAC_SKILLS_CMD}}', skillsCmd)
|
|
31
|
+
.replaceAll('{{N8N_MANAGER_CMD}}', managerCmd)
|
|
32
|
+
.replaceAll('{{N8NAC_CONTEXT_ROOT_HINT}}', contextRootHint);
|
|
33
|
+
}
|
|
34
|
+
readCanonicalAgentSkill(skillName) {
|
|
25
35
|
const candidates = [
|
|
26
|
-
|
|
27
|
-
path.resolve(_dirname, '
|
|
28
|
-
path.resolve(_dirname, '
|
|
36
|
+
path.resolve(_dirname, '../../src/agent-skills', skillName, 'SKILL.md'),
|
|
37
|
+
path.resolve(_dirname, 'agent-skills', skillName, 'SKILL.md'),
|
|
38
|
+
path.resolve(_dirname, '../agent-skills', skillName, 'SKILL.md'),
|
|
39
|
+
path.resolve(_dirname, '../../agent-skills', skillName, 'SKILL.md'),
|
|
29
40
|
];
|
|
30
|
-
for (const
|
|
31
|
-
if (fs.existsSync(
|
|
32
|
-
|
|
33
|
-
this.nodesIndex = JSON.parse(fs.readFileSync(p, 'utf-8')).nodes ?? {};
|
|
34
|
-
return this.nodesIndex;
|
|
35
|
-
}
|
|
36
|
-
catch { /* ignore parse errors */ }
|
|
41
|
+
for (const candidate of candidates) {
|
|
42
|
+
if (fs.existsSync(candidate)) {
|
|
43
|
+
return fs.readFileSync(candidate, 'utf8');
|
|
37
44
|
}
|
|
38
45
|
}
|
|
39
|
-
|
|
40
|
-
return this.nodesIndex;
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* Returns the highest typeVersion for a node looked up by its short name
|
|
44
|
-
* (the key in n8n-nodes-technical.json, e.g. 'lmChatOpenAi').
|
|
45
|
-
* Falls back to the given fallback when the node is not found.
|
|
46
|
-
*/
|
|
47
|
-
latestVersion(nodeShortName, fallback) {
|
|
48
|
-
const nodes = this.loadNodesIndex();
|
|
49
|
-
const node = nodes[nodeShortName];
|
|
50
|
-
if (!node)
|
|
51
|
-
return fallback;
|
|
52
|
-
const versions = Array.isArray(node.version) ? node.version : [node.version];
|
|
53
|
-
return Math.max(...versions.map((v) => Number(v)));
|
|
54
|
-
}
|
|
55
|
-
getCommandRefs(distTag, cliCommandOverride) {
|
|
56
|
-
if (cliCommandOverride) {
|
|
57
|
-
return {
|
|
58
|
-
skillsCmd: `${cliCommandOverride} skills`,
|
|
59
|
-
cliCmd: cliCommandOverride,
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
return {
|
|
63
|
-
skillsCmd: distTag ? `npx --yes n8nac@${distTag} skills` : 'npx --yes n8nac skills',
|
|
64
|
-
cliCmd: distTag ? `npx --yes n8nac@${distTag}` : 'npx --yes n8nac',
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Returns the canonical AI Agent workflow example TypeScript code.
|
|
69
|
-
* Shared between AGENTS.md and the skill prompt to keep both in sync.
|
|
70
|
-
* Node versions are resolved dynamically from n8n-nodes-technical.json
|
|
71
|
-
* so the example never goes stale.
|
|
72
|
-
*/
|
|
73
|
-
getAiAgentWorkflowExampleCode() {
|
|
74
|
-
// Resolve latest typeVersion for each node used in the example
|
|
75
|
-
const vChatTrigger = this.latestVersion('chatTrigger', 1.1);
|
|
76
|
-
const vAgent = this.latestVersion('agent', 3);
|
|
77
|
-
const vLmChatOpenAi = this.latestVersion('lmChatOpenAi', 1.3);
|
|
78
|
-
const vMemoryBufferWindow = this.latestVersion('memoryBufferWindow', 1.3);
|
|
79
|
-
const vHttpRequestTool = this.latestVersion('httpRequestTool', 1.1);
|
|
80
|
-
const vOutputParser = this.latestVersion('outputParserStructured', 1.3);
|
|
81
|
-
return [
|
|
82
|
-
`import { workflow, node, links } from '@n8n-as-code/transformer';`,
|
|
83
|
-
``,
|
|
84
|
-
`// <workflow-map>`,
|
|
85
|
-
`// Workflow : AI Agent`,
|
|
86
|
-
`// Nodes : 6 | Connections: 1`,
|
|
87
|
-
`//`,
|
|
88
|
-
`// NODE INDEX`,
|
|
89
|
-
`// ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ`,
|
|
90
|
-
`// Property name Node type (short) Flags`,
|
|
91
|
-
`// ChatTrigger chatTrigger`,
|
|
92
|
-
`// AiAgent agent [AI]`,
|
|
93
|
-
`// OpenaiModel lmChatOpenAi [creds] [ai_languageModel]`,
|
|
94
|
-
`// Memory memoryBufferWindow [ai_memory]`,
|
|
95
|
-
`// SearchTool httpRequestTool [ai_tool]`,
|
|
96
|
-
`// OutputParser outputParserStructured [ai_outputParser]`,
|
|
97
|
-
`//`,
|
|
98
|
-
`// ROUTING MAP`,
|
|
99
|
-
`// ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ`,
|
|
100
|
-
`// ChatTrigger`,
|
|
101
|
-
`// β AiAgent`,
|
|
102
|
-
`//`,
|
|
103
|
-
`// AI CONNECTIONS`,
|
|
104
|
-
`// AiAgent.uses({ ai_languageModel: OpenaiModel, ai_memory: Memory, ai_outputParser: OutputParser, ai_tool: [SearchTool] })`,
|
|
105
|
-
`// </workflow-map>`,
|
|
106
|
-
``,
|
|
107
|
-
`@workflow({ name: 'AI Agent', active: false })`,
|
|
108
|
-
`export class AIAgentWorkflow {`,
|
|
109
|
-
` @node({ name: 'Chat Trigger', type: '@n8n/n8n-nodes-langchain.chatTrigger', version: ${vChatTrigger}, position: [0, 0] })`,
|
|
110
|
-
` ChatTrigger = {};`,
|
|
111
|
-
``,
|
|
112
|
-
` @node({ name: 'AI Agent', type: '@n8n/n8n-nodes-langchain.agent', version: ${vAgent}, position: [200, 0] })`,
|
|
113
|
-
` AiAgent = {`,
|
|
114
|
-
` promptType: 'define',`,
|
|
115
|
-
` text: '={{ $json.chatInput }}',`,
|
|
116
|
-
` hasOutputParser: true, // REQUIRED when an output parser sub-node is connected`,
|
|
117
|
-
` options: { systemMessage: 'You are a helpful assistant.' },`,
|
|
118
|
-
` };`,
|
|
119
|
-
``,
|
|
120
|
-
` @node({ name: 'OpenAI Model', type: '@n8n/n8n-nodes-langchain.lmChatOpenAi', version: ${vLmChatOpenAi}, position: [200, 200],`,
|
|
121
|
-
` credentials: { openAiApi: { id: 'xxx', name: 'OpenAI' } } })`,
|
|
122
|
-
` OpenaiModel = { model: { mode: 'list', value: 'gpt-4o-mini' }, options: {} };`,
|
|
123
|
-
``,
|
|
124
|
-
` @node({ name: 'Memory', type: '@n8n/n8n-nodes-langchain.memoryBufferWindow', version: ${vMemoryBufferWindow}, position: [300, 200] })`,
|
|
125
|
-
` Memory = { sessionIdType: 'customKey', sessionKey: '={{ $execution.id }}', contextWindowLength: 10 };`,
|
|
126
|
-
``,
|
|
127
|
-
` @node({ name: 'Search Tool', type: 'n8n-nodes-base.httpRequestTool', version: ${vHttpRequestTool}, position: [400, 200] })`,
|
|
128
|
-
` SearchTool = { url: 'https://api.example.com/search', toolDescription: 'Search for information' };`,
|
|
129
|
-
``,
|
|
130
|
-
` @node({ name: 'Output Parser', type: '@n8n/n8n-nodes-langchain.outputParserStructured', version: ${vOutputParser}, position: [500, 200] })`,
|
|
131
|
-
` OutputParser = { schemaType: 'manual', inputSchema: '{ "type": "object", "properties": { "answer": { "type": "string" } } }' };`,
|
|
132
|
-
``,
|
|
133
|
-
` @links()`,
|
|
134
|
-
` defineRouting() {`,
|
|
135
|
-
` // Regular data flow: use .out(0).to(target.in(0))`,
|
|
136
|
-
` this.ChatTrigger.out(0).to(this.AiAgent.in(0));`,
|
|
137
|
-
``,
|
|
138
|
-
` // AI sub-node connections: ALWAYS use .uses(), NEVER .out().to() for these`,
|
|
139
|
-
` this.AiAgent.uses({`,
|
|
140
|
-
` ai_languageModel: this.OpenaiModel.output, // single ref β this.Node.output`,
|
|
141
|
-
` ai_memory: this.Memory.output, // single ref`,
|
|
142
|
-
` ai_outputParser: this.OutputParser.output, // single ref`,
|
|
143
|
-
` ai_tool: [this.SearchTool.output], // array ref β [this.Node.output, ...]`,
|
|
144
|
-
` });`,
|
|
145
|
-
` }`,
|
|
146
|
-
`}`,
|
|
147
|
-
].join('\n');
|
|
148
|
-
}
|
|
149
|
-
getWorkspaceBootstrapLines(cliCmd) {
|
|
150
|
-
return [
|
|
151
|
-
`## π Workspace Bootstrap (MANDATORY)`,
|
|
152
|
-
``,
|
|
153
|
-
`Before using any \`n8nac\` workflow command, check whether the workspace is initialized.`,
|
|
154
|
-
``,
|
|
155
|
-
`### Initialization Check`,
|
|
156
|
-
`- Look for \`n8nac-config.json\` at the root of the target n8n-as-code workspace. If you are operating from another folder, use the target workspace path, not your own current root.`,
|
|
157
|
-
`- If \`n8nac-config.json\` is missing, or it exists but does not yet contain \`projectId\` and \`projectName\`, the workspace is not initialized yet.`,
|
|
158
|
-
`- **NEVER tell the user to run \`${cliCmd} init\` themselves.** You are the agent β it is YOUR job to run the command.`,
|
|
159
|
-
`- For autonomous agents, the default non-interactive initialization flow is the explicit 2-step sequence: \`${cliCmd} init-auth --host <url> --api-key <key> [--sync-folder <path>]\`, then \`${cliCmd} init-project --project-id <id>|--project-name <name>|--project-index <n> [--sync-folder <path>]\`. Use this when the project is not known yet and you need to discover or inspect projects before choosing one.`,
|
|
160
|
-
`- A 1-command non-interactive flow also exists when the host, API key, and project selector are already known: \`${cliCmd} instance add --yes --host <url> --api-key <key> --project-id <id>|--project-name <name>|--project-index <n> [--sync-folder <path>]\`. \`${cliCmd} init\` is the ergonomic alias.`,
|
|
161
|
-
`- If the workspace already has saved instance configs, inspect them with \`${cliCmd} instance list --json\` before deciding whether to add a new one or switch the active config.`,
|
|
162
|
-
`- Use \`${cliCmd} instance select --instance-id <id>\` or \`${cliCmd} instance select --instance-name <name>\` to switch saved configs non-interactively.`,
|
|
163
|
-
`- Use \`${cliCmd} instance delete --instance-id <id> --yes\` or \`${cliCmd} instance delete --instance-name <name> --yes\` to remove stale saved configs non-interactively.`,
|
|
164
|
-
`- If the user has already provided the n8n host and API key, prefer the 2-step flow when you still need to inspect projects first. Use the 1-command flow only when the target project is already known.`,
|
|
165
|
-
`- If host or API key are missing, ask the user for them with a single clear question: "To initialize the workspace I need your n8n host URL and API key β what are they?" Then, once you have both values, run the appropriate command yourself.`,
|
|
166
|
-
`- Do not run \`n8nac list\`, \`pull\`, \`push\`, or edit workflow files until initialization is complete.`,
|
|
167
|
-
`- Never write \`n8nac-config.json\` by hand. Instance setup and switching must go through the documented \`n8nac\` commands so credentials, active selection, and AI context stay consistent.`,
|
|
168
|
-
`- Do not assume initialization has already happened just because the repository contains workflow files or plugin files.`,
|
|
169
|
-
``,
|
|
170
|
-
`### Preferred Agent Commands`,
|
|
171
|
-
`- Default 2-step non-interactive auth: \`${cliCmd} init-auth --host <url> --api-key <key> [--sync-folder <path>]\``,
|
|
172
|
-
`- Default 2-step non-interactive project selection: \`${cliCmd} init-project --project-id <id>|--project-name <name>|--project-index <n> [--sync-folder <path>]\``,
|
|
173
|
-
`- Optional 1-command non-interactive setup when the project is already known: \`${cliCmd} instance add --yes --host <url> --api-key <key> --project-id <id>|--project-name <name>|--project-index <n> [--sync-folder <path>]\``,
|
|
174
|
-
`- Optional 1-command alias: \`${cliCmd} init --yes --host <url> --api-key <key> --project-id <id>|--project-name <name>|--project-index <n> [--sync-folder <path>]\``,
|
|
175
|
-
`- Saved config management: \`${cliCmd} instance list --json\`, \`${cliCmd} instance select --instance-id <id>|--instance-name <name>\`, \`${cliCmd} instance delete --instance-id <id>|--instance-name <name> --yes\``,
|
|
176
|
-
`- \`${cliCmd} init-project\` can run interactively after \`${cliCmd} init-auth\`, or non-interactively when the project selector is known.`,
|
|
177
|
-
``,
|
|
178
|
-
`### Required Order`,
|
|
179
|
-
`1. Check for \`n8nac-config.json\`.`,
|
|
180
|
-
`2. If saved configs already exist: inspect them with \`${cliCmd} instance list --json\`. Reuse them with \`${cliCmd} instance select\` instead of creating duplicates whenever that satisfies the user request.`,
|
|
181
|
-
`3. If initialization is missing and \`N8N_HOST\` / \`N8N_API_KEY\` are available: default to \`${cliCmd} init-auth --host <url> --api-key <key> [--sync-folder <path>]\` to discover projects. Only use \`${cliCmd} instance add --yes --host <url> --api-key <key> --project-id <id>|--project-name <name>|--project-index <n> [--sync-folder <path>]\` when the project is already known.`,
|
|
182
|
-
`4. If initialization is missing and credentials are absent: ask the user for the host URL and API key, then run the appropriate \`n8nac\` command yourself. **Do not ask the user to run the command.**`,
|
|
183
|
-
`5. After credentials are saved, inspect the listed projects. If only one project exists, run \`${cliCmd} init-project --project-index 1 --sync-folder workflows\`. If multiple projects exist, ask the user which one to use, then run \`${cliCmd} init-project --project-id <id> [--sync-folder <path>]\`.`,
|
|
184
|
-
`6. Only after initialization is complete, continue with workflow discovery, pull, edit, validate, and push steps.`,
|
|
185
|
-
``,
|
|
186
|
-
`---`,
|
|
187
|
-
``,
|
|
188
|
-
];
|
|
189
|
-
}
|
|
190
|
-
getWorkflowMapGuidanceLines() {
|
|
191
|
-
return [
|
|
192
|
-
`## πΊοΈ Reading Workflow Files Efficiently`,
|
|
193
|
-
``,
|
|
194
|
-
`Every \`.workflow.ts\` file starts with a \`<workflow-map>\` block β a compact index generated automatically at each sync. Always read this block first before opening the rest of the file.`,
|
|
195
|
-
``,
|
|
196
|
-
`\`\`\``,
|
|
197
|
-
`// <workflow-map>`,
|
|
198
|
-
`// Workflow : My Workflow`,
|
|
199
|
-
`// Nodes : 12 | Connections: 14`,
|
|
200
|
-
`//`,
|
|
201
|
-
`// NODE INDEX`,
|
|
202
|
-
`// ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ`,
|
|
203
|
-
`// Property name Node type (short) Flags`,
|
|
204
|
-
`// ScheduleTrigger scheduleTrigger`,
|
|
205
|
-
`// AgentGenerateApplication agent [AI] [creds]`,
|
|
206
|
-
`// OpenaiChatModel lmChatOpenAi [creds] [ai_languageModel]`,
|
|
207
|
-
`// Memory memoryBufferWindow [ai_memory]`,
|
|
208
|
-
`// GithubCheckBranchRef httpRequest [onErrorβout(1)]`,
|
|
209
|
-
`//`,
|
|
210
|
-
`// ROUTING MAP`,
|
|
211
|
-
`// ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ`,
|
|
212
|
-
`// β οΈ Nodes flagged [ai_*] are NOT in the β routing β they connect via .uses()`,
|
|
213
|
-
`// ScheduleTrigger`,
|
|
214
|
-
`// β Configuration1`,
|
|
215
|
-
`// β BuildProfileSources β LoopOverProfileSources`,
|
|
216
|
-
`// .out(1) β JinaReadProfileSource β LoopOverProfileSources (β© loop)`,
|
|
217
|
-
`//`,
|
|
218
|
-
`// AI CONNECTIONS`,
|
|
219
|
-
`// AgentGenerateApplication.uses({ ai_languageModel: OpenaiChatModel, ai_memory: Memory })`,
|
|
220
|
-
`// </workflow-map>`,
|
|
221
|
-
`\`\`\``,
|
|
222
|
-
``,
|
|
223
|
-
`### How to navigate a workflow as an agent`,
|
|
224
|
-
``,
|
|
225
|
-
`1. Read \`<workflow-map>\` only β locate the property name you need.`,
|
|
226
|
-
`2. Search for that property name in the file (for example \`AgentGenerateApplication =\`).`,
|
|
227
|
-
`3. Read only that section β do not load the entire file into context.`,
|
|
228
|
-
``,
|
|
229
|
-
`This avoids loading 1500+ lines when you only need to patch 10.`,
|
|
230
|
-
``,
|
|
231
|
-
];
|
|
232
|
-
}
|
|
233
|
-
getSharedToolGuidanceLines(skillsCmd) {
|
|
234
|
-
return [
|
|
235
|
-
`### AI Tool Nodes`,
|
|
236
|
-
``,
|
|
237
|
-
`When an AI agent uses tool nodes:`,
|
|
238
|
-
``,
|
|
239
|
-
`- β
Search for the exact tool node first.`,
|
|
240
|
-
`- β
Run \`${skillsCmd} node-info <nodeName>\` before writing parameters.`,
|
|
241
|
-
`- β
Connect tool nodes as arrays: \`this.Agent.uses({ ai_tool: [this.Tool.output] })\`.`,
|
|
242
|
-
`- β Do not assume tool parameter names or reuse stale node-specific guidance.`,
|
|
243
|
-
``,
|
|
244
|
-
];
|
|
245
|
-
}
|
|
246
|
-
getSharedResponseFormatLines(cliCmd) {
|
|
247
|
-
return [
|
|
248
|
-
`## π Response Format`,
|
|
249
|
-
``,
|
|
250
|
-
`When helping users:`,
|
|
251
|
-
``,
|
|
252
|
-
`1. Acknowledge what they want to achieve.`,
|
|
253
|
-
`2. Check initialization by verifying whether \`n8nac-config.json\` exists in the workspace root.`,
|
|
254
|
-
`3. If not initialized, ask the user for the host URL and API key if needed, then run \`${cliCmd} init-auth\` and \`${cliCmd} init-project\` yourself.`,
|
|
255
|
-
`4. Pull the workflow before any modification and show the command.`,
|
|
256
|
-
`5. For a new workflow, read \`workflowDir\` from the active instance in \`n8nac-config.json\` to find the correct directory. In the common case it is workspace-relative, but it can also be absolute if \`syncFolder\` is absolute. Create the file there and confirm it appears in \`${cliCmd} list --local\` before pushing.`,
|
|
257
|
-
`6. Search for the relevant nodes and show the command you are running.`,
|
|
258
|
-
`7. Retrieve the exact schema.`,
|
|
259
|
-
`8. Generate the TypeScript configuration using the schema.`,
|
|
260
|
-
`9. Explain the key parameters and any credentials needed.`,
|
|
261
|
-
`10. Push the workflow after modification and show the command.`,
|
|
262
|
-
`11. For webhook/chat/form workflows: run \`${cliCmd} test-plan <id>\` after pushing to inspect trigger, endpoints, and suggested payload.`,
|
|
263
|
-
` - Then run \`${cliCmd} test <id>\` with the inferred payload when runtime validation is needed.`,
|
|
264
|
-
` - If **Class A** (config gap): report what the user needs to configure β do NOT re-edit the code.`,
|
|
265
|
-
` - If **runtime-state issue** (webhook test URL not armed, production webhook not registered): do NOT re-edit the code. Resolve the state/arming issue first.`,
|
|
266
|
-
` - If **Class B** (wiring error): fix the issue, push again, and re-test.`,
|
|
267
|
-
``,
|
|
268
|
-
`---`,
|
|
269
|
-
``,
|
|
270
|
-
`Remember: Check initialization first. Pull before you modify. Push after you modify. Inspect then test webhook/chat/form workflows after push. Never guess parameters β always verify against the schema.`,
|
|
271
|
-
];
|
|
46
|
+
throw new Error(`Canonical agent skill not found: ${skillName}`);
|
|
272
47
|
}
|
|
273
48
|
async generate(projectRoot, n8nVersion = "Unknown", distTag, options = {}) {
|
|
274
|
-
const agentsContent = this.getAgentsContent(n8nVersion, distTag, options);
|
|
275
|
-
// 1. AGENTS.md (
|
|
49
|
+
const agentsContent = this.getAgentsContent(n8nVersion, distTag, options, projectRoot);
|
|
50
|
+
// 1. AGENTS.md (lightweight context-root bootstrap)
|
|
276
51
|
this.injectOrUpdate(path.join(projectRoot, 'AGENTS.md'), agentsContent, true);
|
|
52
|
+
// 2. Local portable skills for agents that only see the context root.
|
|
53
|
+
this.materializeAgentSkills(projectRoot, distTag, options);
|
|
54
|
+
}
|
|
55
|
+
materializeAgentSkills(projectRoot, distTag, options = {}) {
|
|
56
|
+
const skillsRoot = path.join(projectRoot, '.agents', 'skills');
|
|
57
|
+
const skillNames = ['n8n-manager', 'n8n-architect'];
|
|
58
|
+
for (const skillName of skillNames) {
|
|
59
|
+
const content = this.getAgentSkillContent(skillName, distTag, options, projectRoot);
|
|
60
|
+
const skillDir = path.join(skillsRoot, skillName);
|
|
61
|
+
fs.mkdirSync(skillDir, { recursive: true });
|
|
62
|
+
fs.writeFileSync(path.join(skillDir, 'SKILL.md'), content);
|
|
63
|
+
}
|
|
277
64
|
}
|
|
278
65
|
injectOrUpdate(filePath, content, isMarkdownFile = false) {
|
|
279
66
|
const startMarker = isMarkdownFile ? '<!-- n8n-as-code-start -->' : '### π€ n8n-as-code-start';
|
|
@@ -299,665 +86,73 @@ export class AiContextGenerator {
|
|
|
299
86
|
fs.writeFileSync(filePath, existing.trim() + '\n' + block);
|
|
300
87
|
}
|
|
301
88
|
}
|
|
302
|
-
getAgentsContent(n8nVersion, distTag, options = {}) {
|
|
303
|
-
const { cliCmd, skillsCmd
|
|
89
|
+
getAgentsContent(n8nVersion, distTag, options = {}, projectRoot) {
|
|
90
|
+
const { cliCmd, skillsCmd } = this.getCommandRefs(distTag, options.cliCommandOverride, projectRoot);
|
|
91
|
+
const managerCmd = options.managerCommandOverride || process.env.N8N_MANAGER_COMMAND || 'n8n-manager';
|
|
304
92
|
const versionStamp = options.cliVersion ? [`<!-- n8nac-version: ${options.cliVersion} -->`, ``] : [];
|
|
93
|
+
const contextRoot = projectRoot ? path.resolve(projectRoot) : process.cwd();
|
|
305
94
|
return [
|
|
306
95
|
...versionStamp,
|
|
307
|
-
`##
|
|
308
|
-
``,
|
|
309
|
-
`You are a specialized AI agent for creating and editing n8n workflows.`,
|
|
310
|
-
`You manage n8n workflows as **clean, version-controlled TypeScript files** using decorators.`,
|
|
311
|
-
``,
|
|
312
|
-
`### π Context`,
|
|
313
|
-
`- **n8n Version**: ${n8nVersion}`,
|
|
314
|
-
`- **Source of Truth**: \`${cmd}\` tools (Deep Search + Technical Schemas)`,
|
|
315
|
-
``,
|
|
316
|
-
`---`,
|
|
317
|
-
``,
|
|
318
|
-
...this.getWorkspaceBootstrapLines(cliCmd),
|
|
319
|
-
`## π GitOps & Synchronization Protocol (CRITICAL)`,
|
|
320
|
-
``,
|
|
321
|
-
`n8n-as-code uses a **Git-like sync architecture**. The local code is the source of truth, but the user might have modified the workflow in the n8n UI.`,
|
|
322
|
-
``,
|
|
323
|
-
`**β οΈ CRITICAL RULE**: Before modifying ANY existing \`.workflow.ts\` file, you MUST follow the git-like workflow:`,
|
|
324
|
-
``,
|
|
325
|
-
`### Git-like Sync Workflow`,
|
|
326
|
-
``,
|
|
327
|
-
`1. **LIST FIRST**: Check status with \`${cliCmd} list\``,
|
|
328
|
-
` - \`${cliCmd} list\`: List all non-archived workflows with their sync status (lightweight β only reads metadata).`,
|
|
329
|
-
` - \`${cliCmd} list --include-archived\`: List all workflows including archived ones.`,
|
|
330
|
-
` - \`${cliCmd} list --only-archived\`: List only archived workflows.`,
|
|
331
|
-
` - \`${cliCmd} list --local\`: List only local \`.workflow.ts\` files.`,
|
|
332
|
-
` - \`${cliCmd} list --remote\`: List only remote workflows.`,
|
|
333
|
-
` - Identify workflow IDs, filenames, and sync status. Archived workflows are shown with an \`[archived]\` badge.`,
|
|
334
|
-
` - β οΈ **ARCHIVED WORKFLOWS ARE READ-ONLY**: Archived workflows cannot be pushed or modified via the API.`,
|
|
335
|
-
` - Read \`n8nac-config.json\` to understand the active sync context. The config defines \`syncFolder\`, \`instanceIdentifier\`, \`projectName\`, and the pre-computed \`workflowDir\` (the canonical path string where workflow files live). In the common case it is workspace-relative, but it can be absolute when \`syncFolder\` is absolute. You never need to reconstruct it manually.`,
|
|
336
|
-
` - Always run \`${cliCmd}\` from the workspace root. Never construct sync paths manually.`,
|
|
337
|
-
``,
|
|
338
|
-
`2. **PULL IF NEEDED**: Download remote changes before editing`,
|
|
339
|
-
` - \`${cliCmd} pull <id>\`: Download workflow from n8n to local.`,
|
|
340
|
-
` - Required if workflow exists remotely but not locally, or if remote has newer changes.`,
|
|
341
|
-
``,
|
|
342
|
-
`3. **EDIT / CREATE LOCALLY**: Work on the local \`.workflow.ts\` file inside the active workflow directory.`,
|
|
343
|
-
` - For an existing workflow: edit the pulled local file.`,
|
|
344
|
-
` - For a brand-new workflow: read \`workflowDir\` from the **active instance** in \`n8nac-config.json\` β that is the instance whose \`id\` matches \`activeInstanceId\`. That path string is the canonical location for all workflow files. In the common case it is workspace-relative, but it can be absolute. Create the file there; never in the workspace root.`,
|
|
345
|
-
` - \`workflowDir\` is recomputed and persisted automatically on every \`instance add\` / \`instance select\` / \`init\`. It is always the authoritative source β do not reconstruct it from \`syncFolder\` + \`instanceIdentifier\` + \`projectName\` manually.`,
|
|
346
|
-
` - After writing a new file, confirm it appears in \`${cliCmd} list --local\` before running \`${cliCmd} push <path>\` with either the absolute path or the workspace-root-relative path, such as \`workflows/127_0_0_1_5678_yagr_l/personal/slack-notification.workflow.ts\`.`,
|
|
347
|
-
``,
|
|
348
|
-
`4. **PUSH**: Upload your changes explicitly`,
|
|
349
|
-
` - \`${cliCmd} push <path>\`: Upload the local workflow file to n8n. This is the only public push form.`,
|
|
350
|
-
` - \`${cliCmd} push <path> --verify\`: Push and immediately verify the live workflow against the local schema.`,
|
|
351
|
-
``,
|
|
352
|
-
` > β οΈ **CRITICAL β what \`path\` means**:`,
|
|
353
|
-
` > - Always use the full workflow file path including the \`.workflow.ts\` suffix.`,
|
|
354
|
-
` > - Use either the absolute path from \`workflowDir\` or the workspace-root-relative path that starts with \`workflowDir\`, for example \`workflows/127_0_0_1_5678_yagr_l/personal/slack-notification.workflow.ts\`.`,
|
|
355
|
-
` > - Do **not** pass a bare filename such as \`slack-notification.workflow.ts\` β there is no automatic scope prefix and the push will fail.`,
|
|
356
|
-
` > - Do **not** omit the extension or pass a bare workflow name such as \`slack-notification\`.`,
|
|
357
|
-
` > - Do **not** use the workflow title from n8n as a CLI argument.`,
|
|
358
|
-
` > - The remote source of truth remains the workflow ID; \`push\` resolves the file from the path you provide.`,
|
|
359
|
-
``,
|
|
360
|
-
`5. **VERIFY (strongly recommended)**: After any push, validate the live workflow`,
|
|
361
|
-
` - \`${cliCmd} verify <id>\`: Fetches the workflow from n8n and checks all nodes against the schema.`,
|
|
362
|
-
` - Detects: invalid \`typeVersion\` (e.g. 1.6 when schema only has 2.2), invalid \`operation\` values (e.g. 'post' vs 'create'), missing required params, unknown node types.`,
|
|
363
|
-
` - This catches the same errors n8n would display as "Could not find workflow" or "Could not find property option" **before** the user opens the workflow.`,
|
|
364
|
-
``,
|
|
365
|
-
`6. **INSPECT TEST PLAN (recommended for webhook/chat/form workflows)**: Determine whether and how the workflow can be tested`,
|
|
366
|
-
` - \`${cliCmd} test-plan <id>\`: Detects the trigger type, decides whether the workflow is HTTP-testable, and returns suggested endpoints plus an inferred payload.`,
|
|
367
|
-
` - Use \`--json\` when an agent needs structured output.`,
|
|
368
|
-
` - The payload is heuristic: treat it as a starting point, not as a guaranteed contract.`,
|
|
369
|
-
` - Skip this step for Schedule or generic polling triggers when the command reports them as non-testable.`,
|
|
370
|
-
``,
|
|
371
|
-
`7. **TEST (recommended for webhook/chat/form workflows)**: Execute the workflow`,
|
|
372
|
-
` - **β οΈ DEFAULT: ALWAYS activate then test with \`--prod\`.** This is the only flow that works without manual intervention in the n8n editor.`,
|
|
373
|
-
` - \`${cliCmd} workflow activate <id>\` then \`${cliCmd} test <id> --prod\`: **This is the standard sequence.** Activate the workflow first, then call the production webhook URL. Works immediately, no manual arm needed.`,
|
|
374
|
-
` - \`${cliCmd} test <id>\` (bare, no \`--prod\`): Only for workflows that are NOT activated AND the test URL has been manually armed in the n8n editor ("Listen for test event"). **Do NOT use this as the default path β it will fail silently without the manual arm step.**`,
|
|
375
|
-
` - **β οΈ MANDATORY RULE: By default, ALWAYS run \`workflow activate <id>\` before testing and ALWAYS pass \`--prod\`. Only use bare \`test <id>\` when the workflow is intentionally left inactive AND the test URL has been manually armed in the n8n editor; never use bare \`test <id>\` as the default path.**`,
|
|
376
|
-
` - Works for workflows whose first trigger is a **Webhook**, **Chat Trigger**, or **Form Trigger**.`,
|
|
377
|
-
` - Does NOT work for Schedule or generic polling triggers (those cannot be called via HTTP).`,
|
|
378
|
-
``,
|
|
379
|
-
` ### β οΈ Critical: Error Classification`,
|
|
380
|
-
``,
|
|
381
|
-
` \`n8nac test\` classifies failures into three buckets:`,
|
|
382
|
-
``,
|
|
383
|
-
` **Class A β Configuration gap** (exit 0, do NOT iterate):`,
|
|
384
|
-
` - Missing credentials, unset LLM model, missing environment variable.`,
|
|
385
|
-
` - These are NOT bugs in the workflow code β they are setup tasks the user must complete in the n8n UI.`,
|
|
386
|
-
` - When you see \`β Configuration gap detected (Class A)\`, stop and inform the user what to configure.`,
|
|
387
|
-
` - **Do NOT re-push or re-edit the workflow** to try to fix a Class A error β you cannot fix credentials in code.`,
|
|
388
|
-
``,
|
|
389
|
-
` **Runtime-state issue** (exit 0, do NOT edit code blindly):`,
|
|
390
|
-
` - Typical examples: the webhook test URL is not armed yet, or the production webhook is not registered even though the workflow was just activated.`,
|
|
391
|
-
` - For classic Webhook/Form triggers, \`/webhook-test/...\` usually requires a manual arm step in the n8n editor: click \`Execute workflow\` or \`Listen for test event\`, then retry the same request once.`,
|
|
392
|
-
` - There is no documented public n8n API in this project for arming test webhooks on your behalf, so treat this step as manual.`,
|
|
393
|
-
` - If \`n8nac test --prod\` still reports "webhook is not registered" after \`${cliCmd} workflow activate <id>\`, do not keep editing the workflow. Treat it as a publish/runtime-state issue and verify the workflow state in n8n.`,
|
|
96
|
+
`## n8n-as-code Context Root`,
|
|
394
97
|
``,
|
|
395
|
-
`
|
|
396
|
-
` - Bad expression, wrong field name, HTTP error caused by the workflow logic.`,
|
|
397
|
-
` - These ARE fixable by editing the \`.workflow.ts\` file.`,
|
|
398
|
-
` - When you see \`β Workflow execution failed (Class B)\`, fix the wiring, push, and \`n8nac test\` again.`,
|
|
98
|
+
`This file is generated by \`${cliCmd} update-ai\`. It is bootstrap context only, not a configuration source of truth.`,
|
|
399
99
|
``,
|
|
400
|
-
|
|
401
|
-
|
|
100
|
+
`- Context root: \`${contextRoot}\``,
|
|
101
|
+
`- n8n version at generation time: ${n8nVersion}`,
|
|
102
|
+
`- n8nac command: \`${cliCmd}\``,
|
|
103
|
+
`- n8n-manager command: \`${managerCmd}\``,
|
|
104
|
+
`- n8n knowledge command: \`${skillsCmd}\``,
|
|
402
105
|
``,
|
|
403
|
-
`
|
|
404
|
-
` - \`${cliCmd} resolve <id> --mode keep-current\`: Force-push local version.`,
|
|
405
|
-
` - \`${cliCmd} resolve <id> --mode keep-incoming\`: Force-pull remote version.`,
|
|
406
|
-
``,
|
|
407
|
-
`### Key Principles`,
|
|
408
|
-
`- **Explicit over automatic**: All operations are user-triggered or ai-agent-triggered.`,
|
|
409
|
-
`- **Point-in-time status**: \`list\` is lightweight and covers all workflows at once.`,
|
|
410
|
-
`- **Pull before edit**: Always ensure you have latest version before modifying.`,
|
|
411
|
-
`- **new workflows must be created in the active local workflow directory**: Read \`workflowDir\` from the active instance in \`n8nac-config.json\` (the instance whose \`id\` === \`activeInstanceId\`) β this is always correct regardless of \`--instance\` overrides or prior \`instance select\` calls. In the common case it is workspace-relative, but it can be absolute if \`syncFolder\` is absolute. Do not write workflows in the repo root or an ad-hoc folder.`,
|
|
412
|
-
`- **push requires the full workflow file path**: Always use either the absolute path from \`workflowDir\` or the workspace-root-relative equivalent, such as \`workflowDir/<filename>.workflow.ts\` in the common relative case. Never use a bare filename. A bare name has no implicit scope prefix and will be rejected with a clear error showing the expected path.`,
|
|
413
|
-
`- **inspect then test after push for webhook/chat/form workflows**: Run \`${cliCmd} test-plan <id>\` first, then activate and test with \`--prod\`. **ALWAYS activate the workflow first (\`workflow activate <id>\`), then test with \`${cliCmd} test <id> --prod\`. Never use bare \`test <id>\` β it requires a manual arm step in the n8n editor and will fail without it.** A Class A error is not a bug β tell the user. A runtime-state issue is also not a code bug β fix the state/arming problem, not the workflow code. A Class B error is fixable β iterate.`,
|
|
414
|
-
``,
|
|
415
|
-
`> \`pull\` and \`resolve\` always operate on **a single workflow ID**. \`push\` always starts from **the full path of the local workflow file** β either absolute or workspace-root-relative (e.g. \`workflows/127_0_0_1_5678_yagr_l/personal/my-workflow.workflow.ts\`). \`list\` is the only command that covers all workflows at once.`,
|
|
416
|
-
``,
|
|
417
|
-
`If you skip the Pull step, your Push will be REJECTED by the Optimistic Concurrency Control (OCC) if the user modified the UI in the meantime.`,
|
|
106
|
+
`Run workspace commands from this context root. Do not \`cd\` into the n8n-as-code source repository, n8n-manager source repository, plugin directory, or package directory to run \`${cliCmd} workspace ...\`, \`${cliCmd} list\`, \`${cliCmd} pull\`, \`${cliCmd} push\`, or \`${cliCmd} update-ai\`.`,
|
|
418
107
|
``,
|
|
419
108
|
`---`,
|
|
420
109
|
``,
|
|
421
|
-
`##
|
|
110
|
+
`## Required Local Skills`,
|
|
422
111
|
``,
|
|
423
|
-
|
|
424
|
-
``,
|
|
425
|
-
`### Step 0: Pattern Discovery (Intelligence Gathering)`,
|
|
426
|
-
`\`\`\`bash`,
|
|
427
|
-
`${cmd} examples search "telegram chatbot"`,
|
|
428
|
-
`\`\`\``,
|
|
429
|
-
`- **GOAL**: Don't reinvent the wheel. See how experts build it.`,
|
|
430
|
-
`- **ACTION**: If a relevant workflow exists, DOWNLOAD it to study the node configurations and connections.`,
|
|
431
|
-
`- **LEARNING**: extracting patterns > guessing parameters.`,
|
|
112
|
+
`Read these local skill files before doing n8n work:`,
|
|
432
113
|
``,
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
`${cmd} search "google sheets"`,
|
|
436
|
-
`\`\`\``,
|
|
437
|
-
`- Find the **exact node name** (camelCase: e.g., \`googleSheets\`)`,
|
|
438
|
-
`- Verify the node exists in current n8n version`,
|
|
114
|
+
`- \`.agents/skills/n8n-manager/SKILL.md\``,
|
|
115
|
+
`- \`.agents/skills/n8n-architect/SKILL.md\``,
|
|
439
116
|
``,
|
|
440
|
-
|
|
441
|
-
`\`\`\`bash`,
|
|
442
|
-
`${cmd} node-info googleSheets`,
|
|
443
|
-
`\`\`\``,
|
|
444
|
-
`- Get **EXACT parameter names** (e.g., \`spreadsheetId\`, not \`spreadsheet_id\`)`,
|
|
445
|
-
`- Get **EXACT parameter types** (string, number, options, etc.)`,
|
|
446
|
-
`- Get **available operations/resources**`,
|
|
447
|
-
`- Get **required vs optional parameters**`,
|
|
448
|
-
``,
|
|
449
|
-
`### Step 3: Apply Schema as Absolute Truth`,
|
|
450
|
-
`- **CRITICAL (TYPE)**: The \`type\` field MUST EXACTLY match the \`type\` from schema`,
|
|
451
|
-
`- **CRITICAL (VERSION)**: Use HIGHEST \`typeVersion\` from schema`,
|
|
452
|
-
`- **PARAMETER NAMES**: Use exact names (e.g., \`spreadsheetId\` vs \`spreadsheet_id\`)`,
|
|
453
|
-
`- **NO HALLUCINATIONS**: Do not invent parameter names`,
|
|
454
|
-
``,
|
|
455
|
-
`### Step 4: Validate Before Finishing`,
|
|
456
|
-
`\`\`\`bash`,
|
|
457
|
-
`${cmd} validate workflow.workflow.ts`,
|
|
458
|
-
`\`\`\``,
|
|
459
|
-
``,
|
|
460
|
-
`### Step 5: Verify After Push`,
|
|
461
|
-
`\`\`\`bash`,
|
|
462
|
-
`${cliCmd} verify <workflowId>`,
|
|
463
|
-
`\`\`\``,
|
|
464
|
-
`- **Catches runtime errors** that local validate misses: non-existent typeVersion, invalid operation values, missing required params.`,
|
|
465
|
-
`- Tip: use \`${cliCmd} push <workflowDir>/my-workflow.workflow.ts --verify\` to do both in one command.`,
|
|
466
|
-
``,
|
|
467
|
-
`### Step 6: Inspect Webhook/Chat/Form Testability After Push`,
|
|
468
|
-
`\`\`\`bash`,
|
|
469
|
-
`${cliCmd} test-plan <workflowId>`,
|
|
470
|
-
`${cliCmd} test-plan <workflowId> --json`,
|
|
471
|
-
`\`\`\``,
|
|
472
|
-
`- Determines whether the workflow is HTTP-testable.`,
|
|
473
|
-
`- Returns the trigger type, endpoints, and a suggested payload inferred from expressions.`,
|
|
474
|
-
`- The suggested payload is heuristic. Review it before relying on it.`,
|
|
475
|
-
`- For classic Webhook/Form triggers, the test URL often requires a manual arm step in the n8n editor before it will accept a request.`,
|
|
476
|
-
``,
|
|
477
|
-
`### Step 7: Test Webhook/Chat/Form Workflows After Push`,
|
|
478
|
-
`\`\`\`bash`,
|
|
479
|
-
`# STANDARD sequence β ALWAYS activate first, then test with --prod:`,
|
|
480
|
-
`${cliCmd} workflow activate <workflowId>`,
|
|
481
|
-
`${cliCmd} test <workflowId> --prod`,
|
|
482
|
-
``,
|
|
483
|
-
`# Without activation β ONLY if the test URL was manually armed in n8n editor. Do NOT use as default.`,
|
|
484
|
-
`${cliCmd} test <workflowId>`,
|
|
485
|
-
`\`\`\``,
|
|
486
|
-
`- **β οΈ DEFAULT RULE: ALWAYS activate the workflow first and prefer \`test <id> --prod\`. Use bare \`test <id>\` only when the workflow is intentionally left inactive _and_ you have manually armed the test URL in the n8n editor.**`,
|
|
487
|
-
`- **Closes the dev cycle** for HTTP-triggered workflows.`,
|
|
488
|
-
`- **Class A exit 0** β config gap (credentials, model, env var): inform user, do NOT re-edit code.`,
|
|
489
|
-
`- **Runtime-state exit 0** β webhook test URL not armed / production webhook not registered: resolve the state issue, do NOT re-edit code.`,
|
|
490
|
-
`- **Class B exit 1** β wiring error (bad expression, wrong field): fix, push, re-test.`,
|
|
491
|
-
`- Skip this step for Schedule/polling triggers β they cannot be called via HTTP.`,
|
|
117
|
+
`If your agent runtime supports skills, load those skills. If it does not, treat the files as mandatory instructions.`,
|
|
492
118
|
``,
|
|
493
119
|
`---`,
|
|
494
120
|
``,
|
|
495
|
-
|
|
496
|
-
`---`,
|
|
497
|
-
``,
|
|
498
|
-
`## π Minimal Workflow Structure`,
|
|
499
|
-
``,
|
|
500
|
-
`\`\`\`typescript`,
|
|
501
|
-
`import { workflow, node, links } from '@n8n-as-code/transformer';`,
|
|
502
|
-
``,
|
|
503
|
-
`@workflow({`,
|
|
504
|
-
` name: 'Workflow Name',`,
|
|
505
|
-
` active: false`,
|
|
506
|
-
`})`,
|
|
507
|
-
`export class MyWorkflow {`,
|
|
508
|
-
` @node({`,
|
|
509
|
-
` name: 'Descriptive Name',`,
|
|
510
|
-
` type: '/* EXACT from search */',`,
|
|
511
|
-
` version: 4,`,
|
|
512
|
-
` position: [250, 300]`,
|
|
513
|
-
` })`,
|
|
514
|
-
` MyNode = {`,
|
|
515
|
-
` /* parameters from ${cmd} node-info */`,
|
|
516
|
-
` };`,
|
|
121
|
+
`## Source Of Truth`,
|
|
517
122
|
``,
|
|
518
|
-
`
|
|
519
|
-
` name: 'Next Node',`,
|
|
520
|
-
` type: '/* EXACT from search */',`,
|
|
521
|
-
` version: 3`,
|
|
522
|
-
` })`,
|
|
523
|
-
` NextNode = { /* parameters */ };`,
|
|
123
|
+
`Do not infer configuration from this file. It intentionally avoids storing the effective instance, project, sync folder, or workflow directory.`,
|
|
524
124
|
``,
|
|
525
|
-
`
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
`}`,
|
|
530
|
-
`\`\`\``,
|
|
531
|
-
``,
|
|
532
|
-
`### AI Agent Workflow Example (CRITICAL β follow this pattern for LangChain nodes)`,
|
|
125
|
+
`n8n-manager plus n8nac backend resolution remains the only source of effective state.`,
|
|
126
|
+
`- Global n8n state and secrets live in \`n8n-manager\`.`,
|
|
127
|
+
`- Context-root overrides live in \`n8nac-config.json\`.`,
|
|
128
|
+
`- The effective context is resolved by the backend.`,
|
|
533
129
|
``,
|
|
534
|
-
|
|
535
|
-
...this.getAiAgentWorkflowExampleCode().split('\n'),
|
|
536
|
-
`\`\`\``,
|
|
130
|
+
`Before any n8n workflow command, run:`,
|
|
537
131
|
``,
|
|
538
|
-
`> **Key rule**: Regular nodes connect with \`source.out(0).to(target.in(0))\`. AI sub-nodes (models, memory, tools, parsers, embeddings, vector stores, retrievers) MUST connect with \`.uses()\`. Using \`.out().to()\` for AI sub-nodes will produce broken connections.`,
|
|
539
|
-
``,
|
|
540
|
-
`---`,
|
|
541
|
-
``,
|
|
542
|
-
`## π« Common Mistakes to AVOID`,
|
|
543
|
-
``,
|
|
544
|
-
`1. β **Wrong node type** - Missing package prefix causes "?" icon. Always use the EXACT \`type\` from \`node-schema\` (with full package prefix: \`n8n-nodes-base.switch\`, not \`switch\`).`,
|
|
545
|
-
`2. β **Outdated typeVersion** - Use highest version from schema`,
|
|
546
|
-
`3. β **Non-existent typeVersion** - e.g. \`typeVersion: 1.6\` when schema only has \`[1, 1.1, 2, 2.2]\`. Causes "Could not find workflow" in n8n. Always pick a value **from the exact array in \`node-schema\`**.`,
|
|
547
|
-
`4. β **Invalid operation/resource value** - e.g. \`operation: 'post'\` on Slack node when the valid string for that resource is \`'create'\`. n8n will show "Could not find property option". Always verify the exact string appears in the \`options[].value\` list returned by \`${cmd} node-schema <node>\`.`,
|
|
548
|
-
`5. β **Mismatched resource + operation** - Each \`resource\` value enables a different set of valid \`operation\` values. Combining an operation from the wrong resource causes "Could not find property option" in n8n.`,
|
|
549
|
-
`6. β **Guessing parameter structure** - Check if nested objects required`,
|
|
550
|
-
`7. β **Wrong connection names** - Must match EXACT node \`name\` field`,
|
|
551
|
-
`8. β **Inventing non-existent nodes** - Use \`search\` to verify`,
|
|
552
|
-
`9. β **Wrong \`.uses()\` syntax for tools** - \`ai_tool\` and \`ai_document\` are ALWAYS arrays: \`ai_tool: [this.Tool.output]\`. All other AI connection types (\`ai_languageModel\`, \`ai_memory\`, etc.) are single refs: \`ai_languageModel: this.Model.output\`. Never wrap single refs in an array.`,
|
|
553
|
-
`10. β **Connecting AI sub-nodes with \`.out().to()\`** β any node flagged \`[ai_*]\` in the NODE INDEX MUST use \`.uses()\`, never \`.out().to()\`. Doing so produces invisible/broken connections in n8n.`,
|
|
554
|
-
`11. β **Guessing fixedCollection values without checking** β Fields like \`rules\` (Switch/If) or \`formFields\` (Wait) expand into nested structures with specific valid option values. Always run \`node-info <node>\` first β the schema now shows the full internal structure and all valid values. Never invent operation names like \`'contained'\`.`,
|
|
555
|
-
`12. β **Inverting \`value1\`/\`value2\` in Switch/If rules** β \`value1\` is ALWAYS the expression being evaluated (e.g. \`={{ $json.myField }}\`). \`value2\` is ALWAYS the literal comparison value (e.g. \`'auto_send_ok'\`). Swapping them causes rules to never match.`,
|
|
556
|
-
`13. β **Wrong \`formFields\` structure for Wait (form) nodes** β \`formFields\` must use \`{ values: [...] }\` (flat array). Do NOT use \`formFieldsUi.fieldItems\` β that legacy structure causes "Could not find property option" in n8n.`,
|
|
557
|
-
``,
|
|
558
|
-
`---`,
|
|
559
|
-
``,
|
|
560
|
-
`## β
Best Practices`,
|
|
561
|
-
``,
|
|
562
|
-
`### Node Parameters`,
|
|
563
|
-
`- β
Always check schema before writing`,
|
|
564
|
-
`- β
Use exact parameter names from schema`,
|
|
565
|
-
`- β Never guess parameter names`,
|
|
566
|
-
``,
|
|
567
|
-
`### Expressions (Modern Syntax)`,
|
|
568
|
-
`- β
Use: \`{{ $json.fieldName }}\` (modern)`,
|
|
569
|
-
`- β
Use: \`{{ $('NodeName').item.json.field }}\` (specific nodes)`,
|
|
570
|
-
`- β Avoid: \`{{ $node["Name"].json.field }}\` (legacy)`,
|
|
571
|
-
``,
|
|
572
|
-
`### Node Naming`,
|
|
573
|
-
`- β
"Action Resource" pattern (e.g., "Get Customers", "Send Email")`,
|
|
574
|
-
`- β Avoid generic names like "Node1", "HTTP Request"`,
|
|
575
|
-
``,
|
|
576
|
-
...this.getSharedToolGuidanceLines(cmd),
|
|
577
|
-
`---`,
|
|
578
|
-
``,
|
|
579
|
-
`## π Available Tools`,
|
|
580
|
-
``,
|
|
581
|
-
``,
|
|
582
|
-
`### π Unified Search (PRIMARY TOOL)`,
|
|
583
|
-
`\`\`\`bash`,
|
|
584
|
-
`${cmd} search "google sheets"`,
|
|
585
|
-
`${cmd} search "how to use RAG"`,
|
|
586
|
-
`\`\`\``,
|
|
587
|
-
`**ALWAYS START HERE.** Deep search across nodes, docs, and tutorials.`,
|
|
588
|
-
``,
|
|
589
|
-
`### π οΈ Get Node Schema`,
|
|
590
|
-
`\`\`\`bash`,
|
|
591
|
-
`${cmd} node-info googleSheets # Complete info`,
|
|
592
|
-
`${cmd} node-schema googleSheets # Quick reference`,
|
|
593
|
-
`\`\`\``,
|
|
594
|
-
``,
|
|
595
|
-
`### π Community Workflows`,
|
|
596
|
-
`\`\`\`bash`,
|
|
597
|
-
`${cmd} examples search "slack notification"`,
|
|
598
|
-
`${cmd} examples info 916`,
|
|
599
|
-
`${cmd} examples download 4365`,
|
|
600
|
-
`\`\`\``,
|
|
601
|
-
``,
|
|
602
|
-
`### π Documentation`,
|
|
603
132
|
`\`\`\`bash`,
|
|
604
|
-
|
|
605
|
-
`${
|
|
133
|
+
`cd ${contextRoot}`,
|
|
134
|
+
`${cliCmd} workspace status --json`,
|
|
606
135
|
`\`\`\``,
|
|
607
136
|
``,
|
|
608
|
-
|
|
609
|
-
`\`\`\`bash`,
|
|
610
|
-
`${cmd} validate workflow.workflow.ts`,
|
|
611
|
-
`\`\`\``,
|
|
612
|
-
``,
|
|
613
|
-
`### π Verify Live Workflow (post-push)`,
|
|
614
|
-
`\`\`\`bash`,
|
|
615
|
-
`${cliCmd} verify <workflowId> # Fetch from n8n + validate against schema`,
|
|
616
|
-
`${cliCmd} push <workflowDir>/my-workflow.workflow.ts --verify # Push then verify in one step`,
|
|
617
|
-
`\`\`\``,
|
|
618
|
-
`Catches runtime errors (invalid typeVersion, bad operation values, missing required params) **before** the user notices them in the UI.`,
|
|
619
|
-
``,
|
|
620
|
-
`### π§ Inspect Webhook/Chat/Form Test Plan (post-push)`,
|
|
621
|
-
`\`\`\`bash`,
|
|
622
|
-
`${cliCmd} test-plan <workflowId> # Detect trigger + testability + suggested payload`,
|
|
623
|
-
`${cliCmd} test-plan <workflowId> --json # Structured output for agents`,
|
|
624
|
-
`\`\`\``,
|
|
625
|
-
`Use this first when an agent needs to know whether a workflow can be tested and what payload to try.`,
|
|
626
|
-
``,
|
|
627
|
-
`### π§ͺ Test Webhook/Chat/Form Workflows (post-push)`,
|
|
628
|
-
`\`\`\`bash`,
|
|
629
|
-
`${cliCmd} test <workflowId> # Trigger test-mode URL, show result`,
|
|
630
|
-
`${cliCmd} test <workflowId> --data '{"key":"value"}' # Pass request body`,
|
|
631
|
-
`${cliCmd} test <workflowId> --query '{"key":"value"}' # Explicit query params for GET/HEAD webhooks`,
|
|
632
|
-
`${cliCmd} test <workflowId> --prod # Use production URL instead`,
|
|
633
|
-
`\`\`\``,
|
|
634
|
-
`Closes the dev cycle for webhook/chat/form workflows. Exits 0 on success, Class A (config gap β inform user), or runtime-state issues such as an unarmed test webhook. Exits 1 only on Class B (wiring error β fix and re-test). Prefer \`${cliCmd} test-plan\` first when the payload is unclear. For GET/HEAD webhooks, prefer \`${cliCmd} test --query <json>\`; \`--data\` also maps to query params for backward compatibility.`,
|
|
635
|
-
`If \`${cliCmd} test\` says the webhook is not registered, do not blindly rewrite the workflow. First decide whether the test URL needs manual arming in the editor or whether the production webhook is still unpublished.`,
|
|
137
|
+
`Use the returned \`workflowDir\` exactly as provided. Do not reconstruct paths from raw config files.`,
|
|
636
138
|
``,
|
|
637
|
-
|
|
638
|
-
`\`\`\`bash`,
|
|
639
|
-
`${cliCmd} execution list --workflow-id <id> --limit 5 --json # Recent executions for one workflow`,
|
|
640
|
-
`${cliCmd} execution get <executionId> --include-data --json # Full execution detail and run data`,
|
|
641
|
-
`\`\`\``,
|
|
642
|
-
`Use this immediately after a webhook returns 2xx but the workflow still appears broken. A successful HTTP trigger only means n8n accepted the request; the execution can still fail later inside the workflow.`,
|
|
139
|
+
`---`,
|
|
643
140
|
``,
|
|
644
|
-
|
|
645
|
-
`\`\`\`bash`,
|
|
646
|
-
`${cliCmd} workflow credential-required <id> --json # List missing credentials (exit 1 if any missing)`,
|
|
647
|
-
`${cliCmd} credential schema <type> # Discover required fields for a type`,
|
|
648
|
-
`${cliCmd} credential list --json # List existing credentials as JSON`,
|
|
649
|
-
`${cliCmd} credential create --type <type> --name <name> --file cred.json --json # Create from file and return metadata`,
|
|
650
|
-
`${cliCmd} credential delete <id> # Delete a credential`,
|
|
651
|
-
`${cliCmd} workflow activate <id> # Activate workflow after credentials provisioned`,
|
|
652
|
-
`\`\`\``,
|
|
653
|
-
`**Full autonomous loop:** push workflow β \`workflow credential-required <id> --json\` (exit 1 = missing, act) β \`credential schema <type>\` β ask user for secret values β \`credential create --file\` β \`workflow activate <id>\` β \`test <id>\`. Workflow blocked by a Class A error? Use \`credential schema <type>\` to discover required fields, write them to a JSON file, then run \`credential create\` to provision the credential programmatically. If testing a classic Webhook/Form trigger via the test URL, expect a manual arm step in the n8n editor before the request will succeed. **Never pass secrets inline via --data** β use --file instead (keeps secrets out of shell history).`,
|
|
654
|
-
`If \`credential create\` fails, read the returned validation message and change the payload before retrying. Never rerun the same failing command unchanged. If a subcommand is unfamiliar, run \`${cliCmd} <subcommand> --help\` instead of inventing flags.`,
|
|
141
|
+
`## Safe Commands`,
|
|
655
142
|
``,
|
|
656
|
-
|
|
143
|
+
`- Instance/runtime/auth/project work: \`${managerCmd} ...\``,
|
|
144
|
+
`- Context-root overrides: \`${cliCmd} workspace ...\``,
|
|
145
|
+
`- Workflow sync and validation: \`${cliCmd} ...\``,
|
|
146
|
+
`- Node knowledge and schema lookup: \`${skillsCmd} ...\``,
|
|
657
147
|
``,
|
|
658
|
-
|
|
148
|
+
`Never write \`n8nac-config.json\` or n8n-manager secret files by hand.`,
|
|
659
149
|
].join('\n');
|
|
660
150
|
}
|
|
661
151
|
getSkillContent() {
|
|
662
|
-
|
|
663
|
-
return `---
|
|
664
|
-
name: n8n-architect
|
|
665
|
-
description: Expert assistant for n8n workflow development. Use when the user asks about n8n workflows, nodes, automation, or needs help creating/editing n8n JSON configurations. Provides access to complete n8n node documentation and prevents parameter hallucination.
|
|
666
|
-
---
|
|
667
|
-
|
|
668
|
-
# n8n Architect
|
|
669
|
-
|
|
670
|
-
You are an expert n8n workflow engineer. Your role is to help users create, edit, and understand n8n workflows using clean, version-controlled TypeScript files.
|
|
671
|
-
|
|
672
|
-
## π Context
|
|
673
|
-
|
|
674
|
-
- **Workflow Format**: TypeScript files using \`@workflow\`, \`@node\`, \`@links\` decorators
|
|
675
|
-
- **Tool Access**: You have access to the complete n8n node documentation via CLI commands
|
|
676
|
-
|
|
677
|
-
${this.getWorkspaceBootstrapLines(cliCmd).join('\n')}
|
|
678
|
-
|
|
679
|
-
## π Root Agent Context
|
|
680
|
-
|
|
681
|
-
- After initialization is complete, read \`AGENTS.md\` from the workspace root.
|
|
682
|
-
- \`init\` or the completed \`init-project\` flow automatically bootstraps \`AGENTS.md\` via \`n8nac update-ai\`.
|
|
683
|
-
- Treat \`AGENTS.md\` as shared workspace context that complements this skill. Use it after initialization, not before.
|
|
684
|
-
|
|
685
|
-
## π Sync Discipline (MANDATORY)
|
|
686
|
-
|
|
687
|
-
This project uses a **Git-like explicit sync model**. You are responsible for pulling before reading and pushing after writing.
|
|
688
|
-
|
|
689
|
-
### Before modifying a workflow
|
|
690
|
-
|
|
691
|
-
Always pull the latest version from the n8n instance first:
|
|
692
|
-
|
|
693
|
-
\`\`\`
|
|
694
|
-
n8n.pullWorkflow β right-click the workflow in the sidebar, or run the "Pull Workflow" command
|
|
695
|
-
\`\`\`
|
|
696
|
-
|
|
697
|
-
This ensures your local file matches the remote state before you make any changes. Skipping this step risks overwriting someone else's changes or triggering an OCC conflict.
|
|
698
|
-
|
|
699
|
-
### After modifying a workflow
|
|
700
|
-
|
|
701
|
-
Always push your changes back to the n8n instance:
|
|
702
|
-
|
|
703
|
-
\`\`\`
|
|
704
|
-
n8n.pushWorkflow β right-click the workflow in the sidebar, or run the "Push Workflow" command
|
|
705
|
-
\`\`\`
|
|
706
|
-
|
|
707
|
-
If the push fails with an OCC conflict (the remote was modified since your last pull), you will be offered:
|
|
708
|
-
- **Show Diff** β inspect what changed remotely
|
|
709
|
-
- **Force Push** β overwrite the remote with your version
|
|
710
|
-
- **Pull** β discard your changes and take the remote version
|
|
711
|
-
|
|
712
|
-
### Rules
|
|
713
|
-
|
|
714
|
-
1. **Pull before you read or modify** β never assume local files are up to date
|
|
715
|
-
2. **Push after every modification** β never leave local changes unpushed
|
|
716
|
-
3. **Never modify \`.workflow.ts\` files without a preceding pull** β treat it like \`git pull\` before editing
|
|
717
|
-
4. **One workflow at a time** β pull/push operates on the currently open workflow file
|
|
718
|
-
|
|
719
|
-
## π¬ Research Protocol (MANDATORY)
|
|
720
|
-
|
|
721
|
-
**NEVER hallucinate or guess node parameters.** Always follow this protocol:
|
|
722
|
-
|
|
723
|
-
### Step 1: Search for the Node
|
|
724
|
-
|
|
725
|
-
When a user mentions a node type (e.g., "HTTP Request", "Google Sheets", "Code"), first search for it:
|
|
726
|
-
|
|
727
|
-
\`\`\`bash
|
|
728
|
-
npx --yes n8nac skills search "<search term>"
|
|
729
|
-
\`\`\`
|
|
730
|
-
|
|
731
|
-
**Examples:**
|
|
732
|
-
- \`npx --yes n8nac skills search "http request"\`
|
|
733
|
-
- \`npx --yes n8nac skills search "google sheets"\`
|
|
734
|
-
- \`npx --yes n8nac skills search "webhook"\`
|
|
735
|
-
|
|
736
|
-
This returns a list of matching nodes with their exact technical names.
|
|
737
|
-
|
|
738
|
-
### Step 2: Get the Node Schema
|
|
739
|
-
|
|
740
|
-
Once you have the exact node name, retrieve its complete schema:
|
|
741
|
-
|
|
742
|
-
\`\`\`bash
|
|
743
|
-
npx --yes n8nac skills node-info "<nodeName>"
|
|
744
|
-
\`\`\`
|
|
745
|
-
|
|
746
|
-
**Examples:**
|
|
747
|
-
- \`npx --yes n8nac skills node-info "httpRequest"\`
|
|
748
|
-
- \`npx --yes n8nac skills node-info "googleSheets"\`
|
|
749
|
-
- \`npx --yes n8nac skills node-info "code"\`
|
|
750
|
-
|
|
751
|
-
This returns the full JSON schema including all parameters, types, defaults, valid options, and input/output structure.
|
|
752
|
-
|
|
753
|
-
### Step 3: Apply the Knowledge
|
|
754
|
-
|
|
755
|
-
Use the retrieved schema as the **absolute source of truth** when generating or modifying workflow TypeScript. Never add parameters that aren't in the schema.
|
|
756
|
-
|
|
757
|
-
${this.getWorkflowMapGuidanceLines().join('\n')}
|
|
758
|
-
|
|
759
|
-
## π Coding Standards
|
|
760
|
-
|
|
761
|
-
### TypeScript Decorator Format
|
|
762
|
-
|
|
763
|
-
\`\`\`typescript
|
|
764
|
-
import { workflow, node, links } from '@n8n-as-code/transformer';
|
|
765
|
-
|
|
766
|
-
@workflow({
|
|
767
|
-
name: 'Workflow Name',
|
|
768
|
-
active: false
|
|
769
|
-
})
|
|
770
|
-
export class MyWorkflow {
|
|
771
|
-
@node({
|
|
772
|
-
name: 'Descriptive Name',
|
|
773
|
-
type: '/* EXACT from search */',
|
|
774
|
-
version: 4,
|
|
775
|
-
position: [250, 300]
|
|
776
|
-
})
|
|
777
|
-
MyNode = {
|
|
778
|
-
/* parameters from npx --yes n8nac skills node-info */
|
|
779
|
-
};
|
|
780
|
-
|
|
781
|
-
@links()
|
|
782
|
-
defineRouting() {
|
|
783
|
-
this.MyNode.out(0).to(this.NextNode.in(0));
|
|
784
|
-
}
|
|
785
|
-
}
|
|
786
|
-
\`\`\`
|
|
787
|
-
|
|
788
|
-
### AI Agent Workflow Example
|
|
789
|
-
|
|
790
|
-
\`\`\`typescript
|
|
791
|
-
${this.getAiAgentWorkflowExampleCode()}
|
|
792
|
-
\`\`\`
|
|
793
|
-
|
|
794
|
-
> **Key rule**: Regular nodes connect with \`source.out(0).to(target.in(0))\`. AI sub-nodes (models, memory, tools, parsers, embeddings, vector stores, retrievers) MUST connect with \`.uses()\`. Using \`.out().to()\` for AI sub-nodes will produce broken connections.
|
|
795
|
-
|
|
796
|
-
### Expression Syntax
|
|
797
|
-
|
|
798
|
-
**Modern (Preferred):**
|
|
799
|
-
\`\`\`javascript
|
|
800
|
-
{{ $json.fieldName }}
|
|
801
|
-
{{ $json.nested.field }}
|
|
802
|
-
{{ $now }}
|
|
803
|
-
{{ $workflow.id }}
|
|
804
|
-
\`\`\`
|
|
805
|
-
|
|
806
|
-
### Credentials
|
|
807
|
-
|
|
808
|
-
**NEVER hardcode API keys or secrets.** Always reference credentials by name.
|
|
809
|
-
|
|
810
|
-
### Connections
|
|
811
|
-
|
|
812
|
-
- β
Regular: \`this.NodeA.out(0).to(this.NodeB.in(0))\`
|
|
813
|
-
- β
AI sub-nodes: \`this.Agent.uses({ ai_languageModel: this.Model.output })\`
|
|
814
|
-
- β Never use \`.out().to()\` for AI sub-node connections
|
|
815
|
-
|
|
816
|
-
### Connection-Dependent Boolean Flags
|
|
817
|
-
|
|
818
|
-
Some boolean parameters gate other parameters or AI connection attachment points. These flags are **conditional** β only set them to \`true\` when you need the gated params or declared connection.
|
|
819
|
-
|
|
820
|
-
The exact flags for each node are shown in the \`node-info\` output under \`Conditional boolean flags\`. **Always check the node-info output** when declaring \`.uses()\` connections to confirm which flags are required.
|
|
821
|
-
|
|
822
|
-
**After writing any AI workflow, verify**: for each \`.uses()\` call, inspect the node's \`node-info\` output and set any listed conditional boolean flag that corresponds to the declared connection type.
|
|
823
|
-
|
|
824
|
-
${this.getSharedToolGuidanceLines(skillsCmd).join('\n')}
|
|
825
|
-
|
|
826
|
-
## π Best Practices
|
|
827
|
-
|
|
828
|
-
1. **Always verify node schemas** before generating configuration
|
|
829
|
-
2. **Use descriptive node names** for clarity ("Get Customers", not "HTTP Request")
|
|
830
|
-
3. **Add comments in Code nodes** to explain logic
|
|
831
|
-
4. **Validate node parameters** using \`npx --yes n8nac skills node-info <nodeName>\`
|
|
832
|
-
5. **Reference credentials** by name, never hardcode
|
|
833
|
-
6. **Use error handling** nodes for production workflows
|
|
834
|
-
|
|
835
|
-
## π Troubleshooting
|
|
836
|
-
|
|
837
|
-
If you're unsure about any node:
|
|
838
|
-
|
|
839
|
-
1. **List all available nodes:**
|
|
840
|
-
\`\`\`bash
|
|
841
|
-
npx --yes n8nac skills list
|
|
842
|
-
\`\`\`
|
|
843
|
-
|
|
844
|
-
2. **Search for similar nodes:**
|
|
845
|
-
\`\`\`bash
|
|
846
|
-
npx --yes n8nac skills search "keyword"
|
|
847
|
-
\`\`\`
|
|
848
|
-
|
|
849
|
-
3. **Get detailed documentation:**
|
|
850
|
-
\`\`\`bash
|
|
851
|
-
npx --yes n8nac skills node-info "nodeName"
|
|
852
|
-
\`\`\`
|
|
853
|
-
|
|
854
|
-
## π Credential Management
|
|
855
|
-
|
|
856
|
-
When a workflow is blocked because a credential is missing, resolve it without opening the n8n UI:
|
|
857
|
-
|
|
858
|
-
**Full autonomous loop:**
|
|
859
|
-
|
|
860
|
-
1. **Detect missing credentials for a workflow (exit 1 = act, exit 0 = all present):**
|
|
861
|
-
\`\`\`bash
|
|
862
|
-
npx --yes n8nac workflow credential-required <workflowId> --json
|
|
863
|
-
\`\`\`
|
|
864
|
-
Output: \`[{ nodeName, credentialType, credentialName, exists }]\`
|
|
865
|
-
Run this immediately after pushing. Exit code 1 means at least one credential is missing.
|
|
866
|
-
|
|
867
|
-
2. **Discover required fields for a credential type:**
|
|
868
|
-
\`\`\`bash
|
|
869
|
-
npx --yes n8nac credential schema <type>
|
|
870
|
-
\`\`\`
|
|
871
|
-
Example: \`npx --yes n8nac credential schema notionApi\`
|
|
872
|
-
Use the output to build the credential data file. Ask the user for secret values β never guess.
|
|
873
|
-
|
|
874
|
-
3. **Create the credential from a file (preferred β keeps secrets out of shell history):**
|
|
875
|
-
\`\`\`bash
|
|
876
|
-
npx --yes n8nac credential create --type <type> --name "My Credential" --file cred.json --json
|
|
877
|
-
\`\`\`
|
|
878
|
-
|
|
879
|
-
4. **Activate the workflow after credentials are provisioned:**
|
|
880
|
-
\`\`\`bash
|
|
881
|
-
npx --yes n8nac workflow activate <workflowId>
|
|
882
|
-
\`\`\`
|
|
883
|
-
|
|
884
|
-
5. **Run the test:**
|
|
885
|
-
\`\`\`bash
|
|
886
|
-
npx --yes n8nac test <workflowId>
|
|
887
|
-
\`\`\`
|
|
888
|
-
A Class A error that was blocking the test should now be resolved.
|
|
889
|
-
If the workflow uses a classic Webhook or Form trigger and the test URL says the webhook is not registered, this is usually a manual arm/listen issue in the n8n editor rather than a code bug.
|
|
890
|
-
Click \`Execute workflow\` or \`Listen for test event\` in the editor, then retry the same test request once.
|
|
891
|
-
If the trigger uses GET or HEAD and the workflow reads from \`$json.query\`, prefer:
|
|
892
|
-
\`\`\`bash
|
|
893
|
-
npx --yes n8nac test <workflowId> --query '{"chatInput":"hello"}'
|
|
894
|
-
\`\`\`
|
|
895
|
-
|
|
896
|
-
6. **If the webhook call succeeds but the workflow still misbehaves, inspect executions:**
|
|
897
|
-
\`\`\`bash
|
|
898
|
-
npx --yes n8nac execution list --workflow-id <workflowId> --limit 5 --json
|
|
899
|
-
npx --yes n8nac execution get <executionId> --include-data --json
|
|
900
|
-
\`\`\`
|
|
901
|
-
Use this to debug server-side execution failures without opening the n8n UI.
|
|
902
|
-
|
|
903
|
-
**Other credential commands:**
|
|
904
|
-
\`\`\`bash
|
|
905
|
-
npx --yes n8nac credential list --json # List all existing credentials as JSON
|
|
906
|
-
npx --yes n8nac workflow deactivate <workflowId> # Deactivate a workflow
|
|
907
|
-
\`\`\`
|
|
908
|
-
|
|
909
|
-
If \`credential create\` fails, read the returned validation message and change the payload before retrying. Never rerun the same failing command unchanged. If a subcommand is unfamiliar, run \`npx --yes n8nac <subcommand> --help\` instead of inventing flags.
|
|
910
|
-
|
|
911
|
-
${this.getSharedResponseFormatLines(cliCmd).join('\n')}
|
|
912
|
-
`;
|
|
152
|
+
return this.getAgentSkillContent('n8n-architect');
|
|
913
153
|
}
|
|
914
|
-
/**
|
|
915
|
-
* Builds the OpenClaw-specific n8n skill prompt.
|
|
916
|
-
* Unlike getSkillContent(), this variant emphasizes the native `n8nac` tool
|
|
917
|
-
* and the lighter OpenClaw prompt/skill handoff to workspace AGENTS.md.
|
|
918
|
-
*/
|
|
919
154
|
getOpenClawSkillContent() {
|
|
920
|
-
|
|
921
|
-
const workflowMapLines = this.getWorkflowMapGuidanceLines()
|
|
922
|
-
.map((line) => line === '## πΊοΈ Reading Workflow Files Efficiently'
|
|
923
|
-
? '## Reading workflow files efficiently'
|
|
924
|
-
: line);
|
|
925
|
-
const toolGuidanceLines = this.getSharedToolGuidanceLines(skillsCmd)
|
|
926
|
-
.map((line) => line === '### AI Tool Nodes'
|
|
927
|
-
? '### AI tool nodes'
|
|
928
|
-
: line);
|
|
929
|
-
return `---
|
|
930
|
-
name: n8n-architect
|
|
931
|
-
description: Use when the user explicitly wants to create, edit, validate, sync, or troubleshoot n8n workflows, asks about n8n nodes or automation, or wants to use the n8nac tool.
|
|
932
|
-
---
|
|
933
|
-
|
|
934
|
-
# n8n Architect
|
|
935
|
-
|
|
936
|
-
Use this skill only for explicit n8n workflow work.
|
|
937
|
-
|
|
938
|
-
## First steps
|
|
939
|
-
|
|
940
|
-
1. Check whether \`n8nac-config.json\` exists in the workspace root.
|
|
941
|
-
2. If the workspace is initialized, read \`AGENTS.md\` from the workspace root before making workflow changes. It is the detailed, workspace-specific source of truth generated by \`n8nac update-ai\`.
|
|
942
|
-
3. If \`AGENTS.md\` is missing or unreadable, regenerate it with \`npx --yes n8nac update-ai\` or run the \`openclaw n8nac:setup\` command before attempting workflow authoring.
|
|
943
|
-
4. If the workspace is not initialized, ask the user for the n8n host URL and API key, then use the \`n8nac\` tool with \`action: "init_auth"\` and \`action: "init_project"\` to complete setup yourself. If you need to add a second saved instance later, call \`action: "init_auth"\` with \`newInstance: true\` first.
|
|
944
|
-
|
|
945
|
-
## Using the n8nac tool
|
|
946
|
-
|
|
947
|
-
- Use the \`n8nac\` tool for setup checks, saved instance config management, workflow list/pull/push/verify, validation, and \`skills\` lookups.
|
|
948
|
-
- Use \`action: "instance_list"\` to inspect saved configs, \`action: "instance_select"\` to switch the active config, and \`action: "instance_delete"\` to remove a stale saved config.
|
|
949
|
-
- Use \`action: "skills"\` whenever you need node search or schema details.
|
|
950
|
-
- Never guess node parameters. The schema lookup is the source of truth.
|
|
951
|
-
- Treat \`AGENTS.md\` as the authoritative workflow-engineering protocol once this skill is active.
|
|
952
|
-
- When a workflow fails due to missing credentials (Class A), identify the missing credentials clearly and use the documented \`n8nac\` CLI commands from \`AGENTS.md\` (for example \`npx --yes n8nac workflow credential-required <workflowId> --json\`, \`npx --yes n8nac credential schema <type>\`, \`npx --yes n8nac credential create --type <type> --name "<name>" --file cred.json --json\`, and \`npx --yes n8nac workflow activate <workflowId>\`). Do not invent unsupported \`n8nac\` tool actions or CLI flags; use \`--help\` if you are unsure.
|
|
953
|
-
- When \`n8nac test\` reports that a webhook is not registered, treat that as a runtime-state issue first, not as a workflow-code bug. For classic Webhook/Form triggers, the test URL usually requires a manual arm step in the n8n editor (\`Execute workflow\` or \`Listen for test event\`). There is no documented public API here to arm test webhooks automatically.
|
|
954
|
-
- When a webhook call succeeds but the workflow still seems broken, inspect the resulting execution with the documented CLI commands from \`AGENTS.md\` (for example \`npx --yes n8nac execution list --workflow-id <workflowId> --limit 5 --json\` then \`npx --yes n8nac execution get <executionId> --include-data --json\`).
|
|
955
|
-
- For GET/HEAD webhooks, prefer \`n8nac test --query <json>\` when the workflow reads from \`$json.query\`. Do not invent flags like \`--query\` unless they are documented in the current \`--help\`.
|
|
956
|
-
|
|
957
|
-
${workflowMapLines.join('\n')}
|
|
958
|
-
|
|
959
|
-
${toolGuidanceLines.join('\n')}
|
|
960
|
-
`;
|
|
155
|
+
return this.getAgentSkillContent('n8n-architect');
|
|
961
156
|
}
|
|
962
157
|
}
|
|
963
158
|
//# sourceMappingURL=ai-context-generator.js.map
|