Build Stack V2
ASecurityEXPERIMENTAL 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 (t...
- 18 stars
- 0 votes
- 0 copies
- 3 views
- Added August 31, 2026
Works with
Security analysis
100/100Pro scans all 2 files and shows the line behind each finding
npx -y skills add neurawork-git/n8n-autopilot --skill build-stack-v2 --agent claude-codeAre you the author of Build Stack V2?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/neurawork-git-build-stack-v2)---
name: build-stack-v2
description: "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."
argument-hint: '"<end-to-end use-case / PRP>" OR extend "<stack id-or-name>" "<change>"'
user-invocable: true
allowed-tools: Read, Write, Edit, Grep, Glob, Bash(npx:*), Workflow
---
# Build Stack v2 — JS-Orchestrated Stack Builder
One level up from [`build-workflow-v2`](../build-workflow-v2/SKILL.md): 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-intake`](../stack-intake/SKILL.md) first — 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
1. **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.md` for a
stack that already covers the use-case. On a match it returns `status: 'needs-decision'` instead
of rebuilding — relay the `hint` (re-run as EXTEND with the change, or pass `mode: '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:
```bash
bash "${CLAUDE_PLUGIN_ROOT}/scripts/build-instance-cache.sh"
```
Writes `.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.
2. **Resolve the three sub-script paths.** They are siblings of this skill inside the plugin install:
- `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`
Resolve `<plugin>` as the absolute parent of *this* skill dir (`build-stack-v2`). The script has no
`fs`/`__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 as
> `buildScript` / `editScript` / `syncScript`). Installed copies arrive with CRLF despite the LF pin
> in `.gitattributes`, and `Workflow({scriptPath})` then refuses them with "script contains control
> characters". It is *sporadic* — `sync.workflow.js` was 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.
3. **Invoke `stack.workflow.js` via the `Workflow` tool** (`scriptPath` = absolute path to it; it runs in
the consumer-repo cwd so `npx n8nac workspace status` resolves 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` / `referenceStack` are 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 to `true` (a new stack is useless inactive); extend defaults to
`false` because an existing stack's active/inactive state is a deliberate operational choice. Pass
`activate: true` on extend when the change is supposed to go live now.
4. Render the **Completion Report** from the returned object. Watch live progress with `/workflows`.
`status: 'success'` means **built + deployed**, not proven: sub-workflows report `proven: false`
because 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 `workflowId`s).
**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.js` returns
> `{ 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's
> `noops[]`. 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.js` runs `mirror-sync` as phase 0; if a referenced
> child has no local file, the comprehender reports `missingLocal` and you should re-run `mirror-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 the `hint` verbatim; do
NOT rebuild. Re-run as EXTEND, or pass `mode: '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. Check `envContext`, re-run `mirror-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. Surface
`attention` + 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/sync` is fine (those use only `agent()`).
Do not add a `workflow()` 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 the `skills:`
pass-through is verified.
Files in this skill
- SKILL.md
- stack.workflow.js
Attribution
Comments
Loading comments…
Newsletter
Get the weekly list of safe new skills, and the ones we pulled.