Menu

Overview

The verb comes first: n8n-decanter <verb> [workflow…] [flags]. Everything after the verb is an argument, so a workflow named like a verb is just a normal argument (no special rule). Flags may still sit anywhere.

n8n-decanter                        # interactive picker (terminal, inited project)
n8n-decanter --version              # print the installed version and exit (-v; errors if combined with a verb)
n8n-decanter help                   # the command surface (also --help, or a bare run when piped)

# Setup
n8n-decanter init [dir] [--force]   # bootstrap (add --host/--token/--api-key to skip prompts)
n8n-decanter completion zsh|bash

# Sync — over n8n's MCP server, Code-node source only (structure lives in n8n)
n8n-decanter pull [workflow…]       # code + structure snapshot -> workflows/<kebab>/
n8n-decanter push [workflow…] [--force] [--publish] [--no-typecheck]   # to the DRAFT
n8n-decanter watch [workflow]
n8n-decanter publish [workflow…]    # take the draft(s) live
n8n-decanter unpublish [workflow…]  # back to draft-only

# Inspect & test
n8n-decanter preflight [workflow…] [--simulate] [--offline] [--viewer] [--json] [--fail-on=warn] [--fail-fast] [--require=<ids>]
                                    # the gate: grades LOCAL code, scored (read-only) — then push, then test
                                    #   --simulate ADDS a local-engine run (Docker); --offline DROPS the instance reads
n8n-decanter diff [workflow…]       # per-node line diff, local code vs the n8n draft (always exits 0)
n8n-decanter executions [workflow…] [--status=…] [--limit=N]
n8n-decanter executions [workflow…] clean
n8n-decanter data-tables [table…] [--filter='<json>'] [--search=…] [--sort=col:asc|desc] [--limit=N] [--all]
n8n-decanter data-tables [table…] clean
n8n-decanter test <workflow> [--execution <execution-id> | --scenario <slug>] [--trigger <node>] [--json]
                                    # grades the INSTANCE's draft. bare = static check, nothing runs;
                                    # --execution/--scenario = pinned run on the instance
n8n-decanter scenario create <workflow> ["<slug>"] [--execution <id>] [--scaffold]   # committed, gap-fillable pin-data set (offline; --scaffold needs MCP)
n8n-decanter scenario check <workflow> ["<slug>"]                                    # structurally validate a scenario (offline)

# Backup — git-native, redeployable disaster recovery (REST; needs N8N_API_KEY)
n8n-decanter backup create <workflow>                            # capture a full-export backup into backups/
n8n-decanter backup restore <workflow> [<backup>]               # redeploy as a NEW, unpublished workflow
n8n-decanter backup list <workflow>                             # retained backups (offline)

n8n-decanter list [--remote] [--json]

# Node
n8n-decanter node run <node-file> [fixture.json] [--allow-env]  # run a node locally (offline)

# Agent guard — structure/lifecycle acts go through n8n's MCP, guarded
n8n-decanter mcp connect            # stdio MCP guard (spawned from the scaffolded .mcp.json; no secret)
n8n-decanter mcp serve [--port N]   # HTTP variant: localhost guard-proxy for URL-configured agents

Creating, renaming, and archiving workflows — and adding or renaming nodes — are n8n’s acts: do them in the n8n editor or over n8n’s MCP tools (your agent reaches them through the guard, which blocks only Code-node jsCode writes). The next pull reconciles the local mirror: files follow renames, new Code nodes land as files, and the first push seeds a node born empty.

Placeholder vocabulary

TokenMeans
<workflow> / [workflow…]a workflow: id · name · unique name-prefix · folder name
<node-file>a path to a node source file (node run)
<execution-id>an n8n execution id (numeric) — preflight --execution, test --execution, executions <execution-id>
<slug>a scenario name — scenario create/scenario check, preflight --scenario/test --scenario (kebab-cased)
<ids>a comma list of preflight check ids — preflight --require=layout,simulate
<backup>a backup: timestamp (or a prefix, e.g. a bare date) · versionId (short or full)backup restore

Interactive picker

Running bare n8n-decanter (no verb, no arguments) in an inited project on a terminal opens a picker instead of printing usage: type to filter, / to move. Each row leads with a status glyph — for a pulled workflow (green), for a not-yet-pulled remote one (yellow), for a remote workflow not yet available in MCP (red, sorted last) — so the state reads by shape, not color alone, and the ids line up in an aligned column. Enter on a pulled workflow offers preflight / preflight --simulate / diff / pull / push / watch / executions — a row may carry flags, and the --simulate row runs the browsable --viewer form. Enter on an unpulled one pulls it directly; Enter on a row explains where to flip the “Available in MCP” switch in n8n. It stays in the workflow’s verb menu between runs, Esc backs out to the list, Esc again quits. Piped output and dirs without a decanter.config.json keep printing usage — scripts and LLM harnesses never see the picker.

Pulled workflows are listed newest-synced first — the one you last pulled or pushed is under the cursor when the picker opens, so the workflow you are actually working on doesn’t have to be hunted for. Unpulled remote rows keep their place after the local ones. The order comes from each workflow folder’s sync timestamp, which is local activity and not committed history: right after a fresh git clone everything looks equally recent, so the list falls back to alphabetical until your first pull or push. The scripted list output is unaffected — it stays alphabetical.

A drift failure offers a --force retry. If a push from the picker aborts because the code changed in n8n since your last sync, the picker asks retry with --force and overwrite the remote draft? [y/N] instead of just printing the hint and dropping back to the menu. The default is No — a bare Enter (or anything other than y/yes) declines and returns to the menu, and answering y re-runs the same action with --force, which overwrites the n8n draft only. The offer appears only for failures --force can actually fix: a layout-compliance error never prompts, because forcing would not help. Non-interactive runs are unchanged — they never prompt, they print the --force hint and exit non-zero.

No-ref → picker. A ref-taking verb given no workflow, on a terminal, opens the picker to choose one and then runs that verb on it (the verb menu is skipped). The same newest-synced-first ordering applies. For pull the list includes remote workflows too (as in the bare picker), so a fresh setup with nothing pulled still gets a menu to pick from; the other verbs act on already-pulled workflows only. This includes the backup … and scenario … sub-verbs, whose first argument is a workflow ref. Piped/non-TTY runs keep the config-default / error path unchanged, so scripts and LLM harnesses never block. The force-retry confirm belongs to the interactive picker session (bare n8n-decanter), so this single-select path prints the ordinary --force hint instead.

Workflow refs

A <workflow> is its id, its workflow/folder name, or a unique name prefixn8n-decanter push "Order Sync" and n8n-decanter push order both work. Matching is case-insensitive and never prompts: an ambiguous or unknown name errors with the candidate list. pull resolves not-yet-pulled names against the server’s workflow list. Without a workflow argument, all workflows from the config are processed (or the picker opens, on a terminal).

Verb-first grammar. The verb is the first argument; everything after it is an argument. n8n-decanter diff push runs diff on the workflow named push — no “address it by id” caveat. Verb-last (n8n-decanter wf123 push) errors with unknown verb. Flags may still appear in any position.

Offline vs. online

VerbsNetwork
preflight --offline, node run, list, scenario check, completion, executions clean, data-tables cleanFully offline — no credentials needed (list --remote is the exception; preflight --offline --simulate needs Docker but never the n8n instance; scenario create --scaffold is the exception in the scenario namespace — it needs MCP)
diff, list --remote, executions, data-tables, backup create/restoreRead the remote (backup restore also writes a new workflow, never touching the source)
backup listFully offline — reads the local backups/ store
testGrades the workflow’s draft on the instance — run it after a push so the draft holds your code. Bare: a static check (dangling $('…') references), nothing executes, no capture needed. With --execution/--scenario: a pinned run. There is no fallback to the newest capture — executing means saying so. On a terminal, when local differs: a published workflow gets a local-vs-draft prompt; an unpublished one is pushed without asking (a draft nobody runs). Non-interactive runs never write
preflightVerifies your local code as one scored gate — static + instance reads, plus an optional local-engine replay (--simulate); never writes and never runs on the instance, with any flag combination. --offline drops the instance reads entirely. Run it before push; test comes after
pull, push, watch, publish, unpublishRead/write the live instance (pushes land on the draft)
mcp connect / mcp serveLong-running MCP guard (stdio / localhost HTTP) — forwards an agent’s MCP traffic to the instance with decanter’s credentials, blocking Code-node (jsCode) writes; a forwarded structure edit also triggers a background workflow.json refresh (liveMirror, on by default)

Credentials come from .env next to decanter.config.json (searched upward from the current directory) or the environment. N8N_HOST plus MCP credentials (OAuth minted by init into .decanter-auth.json, or an N8N_MCP_TOKEN) power the sync and lifecycle verbs; the public API key (N8N_API_KEY, optional) powers only executions, data-tables, and backup — the surfaces n8n’s MCP server doesn’t cover.

Output and scripting

Output is styled (color, /!/ glyphs, progress) only when writing to a terminal and respects NO_COLOR/FORCE_COLOR; piped or redirected output is plain line-oriented text, safe for scripts and LLM harnesses.

API requests time out after 30 s (set "requestTimeoutMs" in decanter.config.json for slow instances). DEBUG=1 prints full stack traces on errors.

Tab completion for verbs, flags, and workflow names:

eval "$(n8n-decanter completion zsh)"   # or bash — append to your shell rc