# N8n N8nac

> Code-first n8n workflow development with n8nac (n8n-as-code). Workspace bootstrap, GitOps sync protocol, TypeScript decorator syntax, error classification, research protocol, and common mistakes. USE WHEN n8nac, n8n-as-code, code-first workflow, workflow.ts, n8nac init, n8nac push, n8nac pull, n8nac verify, n8nac test, n8nac list, workflow as code, TypeScript workflow, decorator workflow, GitOps n8n, push workflow, pull workflow, verify workflow, test workflow, Class A error, Class B error, n8nac bootstrap, n8nac setup, workflow sync.

- Skill: `mj-deving/n8n-n8nac` (Agent Skill)
- Install (CLI): `npx skillmds@latest add mj-deving/n8n-n8nac`
- Raw SKILL.md: https://api.skillmd.com/api/skills/mj-deving/n8n-n8nac/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Research & Search
- Author: mj-deving (https://skillmd.com/u/mj-deving)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/mj-deving/n8n-n8nac

---


# n8nac — Code-First n8n Workflow Development

n8nac (`@n8n-as-code/cli`) manages n8n workflows as clean, version-controlled TypeScript files using decorators. This skill covers the universal protocol — project-specific config is generated by `n8nac update-ai`.

> Based on n8nac v1.6.x protocol. Run `npx --yes n8nac update-ai` in your project for the latest project-specific AGENTS.md.

> **Drift check:** This skill captures the stable universal protocol. If n8nac has been updated since v1.6.x, run `npx --yes n8nac update-ai` and compare the generated AGENTS.md against this skill. If the protocol changed (new commands, renamed flags, new error classes), update this skill to match.

---

## Workspace Bootstrap (MANDATORY)

Before ANY n8nac command, the workspace must be initialized.

### Check
- Look for `n8nac-config.json` at workspace root
- If missing or incomplete (no `projectId`/`projectName`): not initialized

### Initialize (2-step non-interactive)
```bash
# Step 1: Save credentials
npx --yes n8nac init-auth --host <url> --api-key <key>

# Step 2: Select project
npx --yes n8nac init-project --project-index 1 --sync-folder workflows
```

### 1-command alternative (when project is known)
```bash
npx --yes n8nac init --yes --host <url> --api-key <key> --project-index 1 --sync-folder workflows
```

### Environment variables
If `N8N_HOST` and `N8N_API_KEY` are set in the shell, use them:
```bash
npx --yes n8nac init-auth --host "$N8N_HOST" --api-key "$N8N_API_KEY"
```

### Instance management
```bash
npx --yes n8nac instance list --json          # List saved configs
npx --yes n8nac instance select --instance-name <name>  # Switch
npx --yes n8nac instance delete --instance-name <name> --yes  # Remove
```

**Rules:**
- Never tell the user to run init — the agent runs it
- Never write `n8nac-config.json` by hand
- Never run list/pull/push before init completes
- Don't assume init happened just because workflow files exist

---

## GitOps Sync Protocol (CRITICAL)

n8nac uses a Git-like sync architecture. Local code is source of truth, but the user might have edited in n8n UI.

### The 7-Step Workflow

**1. LIST** — Check status
```bash
npx --yes n8nac list              # All workflows with sync status
npx --yes n8nac list --local      # Local .workflow.ts files only
npx --yes n8nac list --remote     # Remote workflows only
```

**2. PULL** — Download remote changes before editing
```bash
npx --yes n8nac pull <workflowId>
```
Required if remote has newer changes. Skip = OCC rejection on push.

**3. EDIT/CREATE** — Work on local `.workflow.ts`
- Existing: edit the pulled file
- New: create in the `workflowDir` from `n8nac-config.json` (the active instance's canonical path)
- Confirm with `npx --yes n8nac list --local` before pushing

**4. PUSH** — Upload to n8n
```bash
npx --yes n8nac push <path>            # Full or workspace-relative path
npx --yes n8nac push <path> --verify   # Push + verify in one step
```
**Path rules:**
- Always use full path including `.workflow.ts` suffix
- Use absolute or workspace-root-relative path (e.g., `workflows/instance/project/my-workflow.workflow.ts`)
- Never bare filename, never omit extension, never use workflow title

**5. VERIFY** — Validate live workflow
```bash
npx --yes n8nac verify <workflowId>
```
Catches: invalid typeVersion, bad operation values, missing required params, unknown node types.

**6. TEST-PLAN** — Check testability
```bash
npx --yes n8nac test-plan <workflowId>        # Human readable
npx --yes n8nac test-plan <workflowId> --json  # Structured for agents
```

**7. TEST** — Execute webhook/chat/form workflows
```bash
# STANDARD sequence (ALWAYS use this):
npx --yes n8nac workflow activate <workflowId>
npx --yes n8nac test <workflowId> --prod

# With custom payload:
npx --yes n8nac test <workflowId> --prod --data '{"key":"value"}'
```
**Default rule:** ALWAYS activate first, ALWAYS use `--prod`. Bare `test <id>` requires manual arm in n8n editor.

**8. RESOLVE** — Handle conflicts
```bash
npx --yes n8nac resolve <id> --mode keep-current    # Force local
npx --yes n8nac resolve <id> --mode keep-incoming    # Force remote
```

---

## Error Classification

`n8nac test` classifies failures into three buckets:

| Class | Exit Code | Action |
|---|---|---|
| **Class A — Config gap** | 0 | Missing credentials/model/env var. Inform user, do NOT re-edit code |
| **Runtime state** | 0 | Webhook not armed, production webhook not registered. Fix state, NOT code |
| **Class B — Wiring error** | 1 | Bad expression, wrong field. Fix `.workflow.ts`, push, re-test |

**Critical:** A Class A error is NOT a bug. Never push/edit to fix missing credentials.

---

## Research Protocol (MANDATORY before creating/editing nodes)

### Step 0: Pattern Discovery
```bash
npx --yes n8nac skills examples search "telegram chatbot"
```

### Step 1: Search for the node
```bash
npx --yes n8nac skills search "google sheets"
```

### Step 2: Get exact schema
```bash
npx --yes n8nac skills node-info googleSheets    # Complete
npx --yes n8nac skills node-schema googleSheets   # Quick reference
```

### Step 3: Apply schema as absolute truth
- Use EXACT `type` from schema (with full package prefix)
- Use HIGHEST `typeVersion` from schema
- Use exact parameter names

### Step 4: Validate before push
```bash
npx --yes n8nac skills validate workflow.workflow.ts
```

### Step 5: Verify after push
```bash
npx --yes n8nac verify <workflowId>
```

---

## TypeScript Decorator Syntax

### Minimal workflow structure
```typescript
import { workflow, node, links } from '@n8n-as-code/transformer';

@workflow({ name: 'Workflow Name', active: false })
export class MyWorkflow {
  @node({
    name: 'Descriptive Name',
    type: '/* EXACT from search */',
    version: 4,
    position: [250, 300]
  })
  MyNode = { /* parameters from node-info */ };

  @links()
  defineRouting() {
    this.MyNode.out(0).to(this.NextNode.in(0));
  }
}
```

### AI Agent pattern (LangChain nodes)
```typescript
@workflow({ name: 'AI Agent', active: false })
export class AIAgentWorkflow {
  @node({ name: 'Chat Trigger', type: '@n8n/n8n-nodes-langchain.chatTrigger', version: 1.4 })
  ChatTrigger = {};

  @node({ name: 'AI Agent', type: '@n8n/n8n-nodes-langchain.agent', version: 3.1 })
  AiAgent = {
    promptType: 'define',
    text: '={{ $json.chatInput }}',
    hasOutputParser: true,
    options: { systemMessage: 'You are a helpful assistant.' },
  };

  @node({ name: 'Model', type: '@n8n/n8n-nodes-langchain.lmChatOpenAi', version: 1.3,
    credentials: { openAiApi: { id: 'xxx', name: 'OpenAI' } } })
  Model = { model: { mode: 'list', value: 'gpt-4o-mini' }, options: {} };

  @links()
  defineRouting() {
    this.ChatTrigger.out(0).to(this.AiAgent.in(0));

    // AI sub-nodes MUST use .uses(), NEVER .out().to()
    this.AiAgent.uses({
      ai_languageModel: this.Model.output,       // single ref
      ai_tool: [this.SearchTool.output],          // array ref (tools, documents)
    });
  }
}
```

**Key rule:** Regular nodes: `.out(0).to(target.in(0))`. AI sub-nodes (models, memory, tools, parsers): `.uses()` only.

---

## Workflow Map Navigation

Every `.workflow.ts` starts with a `<workflow-map>` comment block — a compact index. Read this FIRST, then search for the specific property name you need. Never load the entire file into context.

---

## 13 Common Mistakes

1. Wrong node type — missing package prefix (`switch` vs `n8n-nodes-base.switch`)
2. Outdated typeVersion — always use highest from schema
3. Non-existent typeVersion — verify against exact array in node-schema
4. Invalid operation value — check exact string in options[].value list
5. Mismatched resource + operation — each resource has different valid operations
6. Guessing parameter structure — always check schema for nested objects
7. Wrong connection names — must match exact node `name` field
8. Inventing non-existent nodes — use `search` to verify
9. Wrong `.uses()` syntax — `ai_tool`/`ai_document` are ALWAYS arrays; all others single refs
10. Connecting AI sub-nodes with `.out().to()` — use `.uses()` for anything flagged `[ai_*]`
11. Guessing fixedCollection values — always run `node-info` first
12. Inverting value1/value2 in Switch/If — value1 = expression, value2 = literal
13. Wrong formFields structure for Wait — use `{ values: [...] }`, not `formFieldsUi.fieldItems`

---

## Additional Tools

```bash
# Execution inspection (debug post-trigger)
npx --yes n8nac execution list --workflow-id <id> --limit 5 --json
npx --yes n8nac execution get <execId> --include-data --json

# Credential management (resolve Class A without UI)
npx --yes n8nac workflow credential-required <id> --json
npx --yes n8nac credential schema <type>
npx --yes n8nac credential list --json
npx --yes n8nac credential create --type <type> --name <name> --file cred.json --json

# Workflow lifecycle
npx --yes n8nac workflow activate <id>
npx --yes n8nac workflow deactivate <id>

# Documentation
npx --yes n8nac skills docs "OpenAI"
npx --yes n8nac skills guides "webhook"
```

> When in doubt: `npx --yes n8nac skills node-info <nodeName>` — the schema is always the source of truth.

