build-stack-v2
Skill18 starsChanged 42 days agoMITView on GitHub
EXPERIMENTAL deterministic builder for a whole n8n workflow STACK (multiple sub-workflows wired via Execute Workflow), JS-orchestrated. Takes a PRP-style end-to-end use case, decomposes it into sub-workflows along known rules, fixes the handover contracts between them, documents the architecture (mermaid) in one central file, then builds each sub-workflow bottom-up via build-workflow-v2. Two modes: GREENFIELD (new stack) and EXTEND (change an existing one). Decomposition rules, build order (topological), and per-sub-WF gates are JS control flow the model cannot skip. Use for multi-workflow use cases; for a single workflow use build-workflow-v2.
In this repository25 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- build-workflowSkill
- build-workflow-v2Skill
- check-mcpsSkill
- data-tablesSkill
- deploySkill
- feedbackSkill
- find-credentialSkill
- find-projectSkill
- init-repoSkill
- inventorySkill
- mirror-syncSkill
- n8nac-cheatsheetSkill
- n8nac-referenceSkill
- n8n-code-javascriptSkill
- n8n-code-pythonSkill
- n8n-modeSkill
- n8n-orchestration-patternsSkill
- n8n-structured-extractionSkill
- plugin-testingSkill
- pull-schemasSkill
- session-envSkill
- stack-intakeSkill
- sync-credentialsSkill
- test-manualSkill
The file
We split this skill into the rules it gives an agent
4 rules. About 0 are common, 0 are distinctive, and 4 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
4
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 46
If ambiguous or empty, ask the user (or point them at /n8n-autopilot:stack-intake).
- Very specific: line 47
Greenfield auto-detect: before decomposing, the script checks docs/*.architecture.md for a stack that already covers the use-case.
- Very specific: line 155
NOT rebuild. Re-run as EXTEND, or pass mode: 'greenfield' to force.
- Very specific: line 190
Do not add a workflow() call inside build/edit.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Build Stack v2 — JS-Orchestrated Stack Builder
One level up from build-workflow-v2: that ships ONE workflow, this
ships a whole stack — an orchestrator plus the sub-workflows it calls via Execute Workflow nodes,
with the handover contracts fixed and the architecture documented. The pipeline is a Claude Code
Workflow JS script (stack.workflow.js); the script body is the control flow, each step a typed
subagent. The per-sub-workflow build reuses build-workflow-v2's build.workflow.js / edit.workflow.js
verbatim (one workflow() hop each), so every sub-workflow gets the same hard gates.
Need a plan to feed this? If the user has only a rough idea, run
/n8n-autopilot:stack-intakefirst — a guided interview that produces the PRP-style description this skill digests.
Why a separate stack builder
A single workflow that does everything is a maintenance trap: untestable in parts, OOM-prone, no reuse.
The decomposition rules (single-responsibility leaves, triggers at the edges, fan-out/fan-in, error +
large-data boundaries — from n8n-orchestration-patterns) say when to split. This skill applies them
structurally: the architect decomposes, the contracts are fixed before any code, and the build runs
bottom-up by topological sort — a parent is only built after its children exist, because its
Execute Workflow node needs the child's real workflowId. A failed child halts its dependents
(no building on a broken foundation) and escalates.
Architecture — roles are extracted
| agentType | Role |
n8n-stack-architect | decompose a PRP into sub-WFs + handover contracts (greenfield) / plan the delta (extend) |
n8n-stack-comprehender | reconstruct the real call-graph from executeWorkflow refs in the local mirror (extend) |
n8n-author | (reused) writes the central architecture doc verbatim |
| build-workflow-v2 agents | (reused, one workflow() hop per sub-WF) research → author → validate → deploy → test |
How to run
- Detect the mode from
$ARGUMENTS:- Starts with
extend/ names an existing stack + a change → EXTEND. - Otherwise (a use-case description) → GREENFIELD.
- If ambiguous or empty, ask the user (or point them at
/n8n-autopilot:stack-intake). - Greenfield auto-detect: before decomposing, the script checks
docs/*.architecture.mdfor a stack that already covers the use-case. On a match it returnsstatus: 'needs-decision'instead of rebuilding — relay thehint(re-run as EXTEND with the change, or passmode: 'greenfield'to force a fresh build). This stops the silent rebuild-over-a-working-stack case. 1b. Refresh the instance cache. A stack decomposition that cannot see the instance will rebuild jobs that already run there:
Writesbash "${CLAUDE_PLUGIN_ROOT}/scripts/build-instance-cache.sh".n8n-autopilot/instance-cache.json+instance-brief.md; the architect reuses existing workflows as callees from it. If it fails, report that before starting — do not plan blind. - Starts with
Resolve the three sub-script paths. They are siblings of this skill inside the plugin install:
buildScript=<plugin>/skills/build-workflow-v2/build.workflow.jseditScript=<plugin>/skills/build-workflow-v2/edit.workflow.jssyncScript=<plugin>/skills/mirror-sync/sync.workflow.js
Resolve
<plugin>as the absolute parent of this skill dir (build-stack-v2). The script has nofs/__dirname, so these MUST be passed in as args — that is by design.Windows / CRLF — do this unconditionally: normalize all three scripts into the scratchpad (
sed 's/\r$//' <src> > <scratchpad>/<name>) and pass the scratchpad paths (including asbuildScript/editScript/syncScript). Installed copies arrive with CRLF despite the LF pin in.gitattributes, andWorkflow({scriptPath})then refuses them with "script contains control characters". It is sporadic —sync.workflow.jswas CRLF in 5.3.0/5.3.1 and LF in 5.3.2 — so a version that happened to work is no reason to skip this. Never hand-edit the plugin cache.Invoke
stack.workflow.jsvia theWorkflowtool (scriptPath= absolute path to it; it runs in the consumer-repo cwd sonpx n8nac workspace statusresolves the pinned project + sync folder):Greenfield:
Workflow({ scriptPath: "<plugin>/skills/build-stack-v2/stack.workflow.js", args: { description: "<full end-to-end use-case / PRP>", buildScript: "<plugin>/skills/build-workflow-v2/build.workflow.js", specPath: "<path to the authoritative spec, if one exists in the repo>", referenceStack: "<folder/glob of a PROVEN twin stack, if one exists>" } })Extend:
Workflow({ scriptPath: "<plugin>/skills/build-stack-v2/stack.workflow.js", args: { mode: "extend", target: "<stack id or name hint>", change: "<what to change>", buildScript: "<plugin>/skills/build-workflow-v2/build.workflow.js", editScript: "<plugin>/skills/build-workflow-v2/edit.workflow.js", syncScript: "<plugin>/skills/mirror-sync/sync.workflow.js", specPath: "<authoritative spec>", referenceStack: "<proven twin>", activate: false } })specPath/referenceStackare not optional garnish — pass them whenever the repo has them. Without the spec the fan-out re-derives requirements from prose (observed: a real requirement argued away because a sibling stack lacked it); without the reference twin every sub-agent re-researches node contracts instead of mirroring a pattern that already runs in production.activate— greenfield defaults totrue(a new stack is useless inactive); extend defaults tofalsebecause an existing stack's active/inactive state is a deliberate operational choice. Passactivate: trueon extend when the change is supposed to go live now.- Render the Completion Report from the returned object. Watch live progress with
/workflows.status: 'success'means built + deployed, not proven: sub-workflows reportproven: falsebecause the stack no longer live-tests each one with synthetic data. Prove the stack ONCE, end to end, against the entry trigger with real input — that single run is the acceptance criterion.
Phases
Preflight (both modes, runs first): resolves and logs the target env + project before anything is
created. A stack run rewires a whole project, so pointing it at the wrong one is the most expensive
mistake available here — and it used to be silent. enforce-env.sh refuses un-pinned instance commands,
but only once a build agent already runs, by which point the abort reads as an unrelated tool error.
The resolved target is logged up front and returned as envContext in every report. A missing
per-session N8NAC_ENVIRONMENT is called out explicitly: the run would otherwise follow the SHARED
global active env, which another session can change mid-run.
Greenfield (stack.workflow.js): Plan (n8n-stack-architect decompose → stackPlan) → Document
(docs/<stack>.architecture.md — contracts + mermaid, composed deterministically in JS) → Build
(topological bottom-up, one build.workflow.js hop per sub-WF with deferActivation, children's real
ids fed to parents) → Activate (deps-first: callees before callers — n8n refuses to activate a
caller whose callee is not published, so per-sub-workflow activation would fail on order alone) →
Report (re-write the doc with real workflowIds).
Extend (stack.workflow.js): Mirror (mirror-sync so the local call-graph is complete) →
Comprehend (n8n-stack-comprehender reconstructs the DAG from executeWorkflow refs) → Plan
(n8n-stack-architect delta) → Build (new sub-WFs bottom-up via build.workflow.js, then changed
sub-WFs / orchestrator rewiring via edit.workflow.js with deferTest) → Activate (only with
activate: true) → Report (update the doc).
A change that is already present is a no-op, not a failure.
edit.workflow.jsreturns{ status: 'success', noop: true }and skips deploy/test when the author finds the change already in the file (comprehend refreshed it to remote base, so local == remote). They appear in the result'snoops[]. Treating those as failures used to HALT the whole stack — four in one observed run.
Local-mirror invariant (EXTEND). The call-graph is reconstructed from code, not memory — so the repo must mirror the instance first.
stack.workflow.jsrunsmirror-syncas phase 0; if a referenced child has no local file, the comprehender reportsmissingLocaland you should re-runmirror-sync.
Result → Completion Report
The script returns one of:
{ status: 'aborted', reason }— missing input (no description / no change / no buildScript).{ status: 'needs-decision', reason: 'existing-stack', stackSlug, entryWorkflowId, detail, hint }— greenfield was requested but a matching stack already exists locally. Relay thehintverbatim; do NOT rebuild. Re-run as EXTEND, or passmode: 'greenfield'to force.{ status: 'needs-decision', reason: 'empty-comprehension', target, envContext, attention }— EXTEND found no existing stack in the active environment's mirror. Do NOT re-run as greenfield to "make it work": the delta planner would have classified every sub-WF as new and rebuilt the whole stack against whatever project the session points at. CheckenvContext, re-runmirror-sync, or choose greenfield deliberately.{ status: 'failed', stage, reason, … }— a structural failure (dependency cycle in the plan).{ status: 'partial', … attention }— some sub-WFs built green, a failure halted the rest. Surfaceattention+ the per-sub-WF list verbatim; offer to fix the failing sub-WF and resume.{ status: 'success', mode, stackSlug, entry, architectureDoc, buildOrder, subWorkflows[], idMap, … }.
Render success:
## Stack {mode === 'extend' ? 'extended' : 'built'} & wired (build-stack-v2)
**Stack:** {stackSlug} **Entry:** {entry}
**Architecture doc:** {architectureDoc}
**Build order:** {buildOrder.join(' → ')}
| sub-workflow | status | workflowId | url |
|---|---|---|---|
{ each subWorkflows/applied row }
{ if any non-success: "⚠ {attention}" }
{ if missingLocal: "⚠ Mirror gap: <list> — re-run /n8n-autopilot:mirror-sync." }Each sub-workflow's own live-test outcome lives in its build.workflow.js result (the stack records
status + id + url; deep test detail is per-sub-WF). Open the architecture doc for the mermaid + contracts.
Limits
- Built on
build-workflow-v2. It inherits v2's boundary: gates enforce that steps run in order, not that the authored TS is semantically perfect. Per-sub-WF correctness rests on the node-verifier fan-out inside each build. workflow()nesting is 1 level.stack → build/edit/syncis fine (those use onlyagent()). Do not add aworkflow()call inside build/edit.- Mid-run human steps (a sub-WF with an mcpTrigger needs a UI Publish; non-HTTP triggers need a manual run) are handed back per sub-WF, not driven inside the stack run.
- Experimental, and test-gated — end-to-end stack runs should only be trusted once
build-workflow-v2(greenfield + edit) is green against the target instance and theskills:pass-through is verified.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

