---
name: fluent-cli-reference
description: Complete Fluent Commerce CLI v2 command reference. Every command, every flag, every output format. The single source of truth for all CLI operations. Triggers on "fluent cli help", "cli reference", "cli commands", "how to use fluent cli", "fluent command".
user-invocable: true
allowed-tools: Bash, Read, Write, Edit, Glob, Grep
argument-hint: [command] [subcommand]
cursor-tier: manual
---

# Fluent Commerce CLI v2 — Complete Reference

Single source of truth for every `fluent` CLI command, flag, and output format. Use this skill when you need the exact syntax for any CLI operation.

## CLI Path & Version

```bash
# Check version (all OS)
fluent --version
```

Common locations:
- Windows (nvm4w): `C:/nvm4w/nodejs/fluent`
- macOS/Linux: use `which fluent` to resolve the active binary in PATH

**Required:** Node.js 20+

## Global Options (all commands)

| Flag | Description |
|------|-------------|
| `-v, --version` | Print CLI version |
| `-d, --debug` | Enable verbose debug logging |
| `-q, --quiet` | Suppress non-essential output |
| `-h, --help` | Show command help |

---

## 1. `fluent profile` — Connection Management

Profiles store account credentials in `~/.fluentcommerce/<profile-name>/` (Windows resolves `~` to `C:/Users/<user>`).

### `profile create <profile-name>`

Create a new profile for a Fluent account.

```bash
fluent profile create <profile-name> \
  --id <account-id> \
  --base-url <base-url> \
  --username <username> \
  --password <password> \
  --client-secret <client-secret>
```

| Flag | Required | Description |
|------|----------|-------------|
| `--id` | Yes | Fluent account ID (same as client_id in OAuth) |
| `--base-url` | Yes | API base URL (e.g., `https://acme.sandbox.api.fluentretail.com`) |
| `--username` | Yes | Admin username |
| `--password` | Yes | Admin password |
| `--client-secret` | Yes | OAuth client secret |

**Files created:**
```
~/.fluentcommerce/<profile-name>/
  profile.json          # Account ID, base URL
  user.<username>.json  # Encrypted credentials
```

### `profile list`

List all local profiles.

```bash
fluent profile list
```

### `profile active`

Show the currently active profile and retailer.

```bash
fluent profile active
```

### `profile use <profile-name>`

Set the active profile (and optionally retailer).

```bash
fluent profile use <profile-name>
fluent profile use <profile-name> --retailer <retailer-ref>
```

| Flag | Required | Description |
|------|----------|-------------|
| `-r, --retailer` | No | Set active retailer context |

### `profile update <profile-name>`

Update profile, user, or retailer credentials.

```bash
# Update default user reference
fluent profile update <profile> --user <user-ref>

# Add/update user credentials
fluent profile update <profile> --user <user-ref> --username <username> --password <password>

# Add/update retailer (IMPORTANT: this is how you register a retailer locally)
fluent profile update <profile> --retailer <retailer-ref> --id <retailer-id>

# Add retailer with credentials
fluent profile update <profile> --retailer <retailer-ref> --id <retailer-id> \
  --username <username> --password <password>

# Change retailer's default user
fluent profile update <profile> --retailer <retailer-ref> --user <user-ref>
```

| Flag | Required | Description |
|------|----------|-------------|
| `--user` | Conditional | User reference to set as default |
| `--username` | Conditional | Username (requires --password) |
| `--password` | Conditional | Password (requires --username) |
| `--retailer` | Conditional | Retailer ref (required with --id) |
| `--id` | Conditional | Retailer numeric ID (required when adding retailer) |

### `profile export <profile-name>`

Export profile as Postman environment.

```bash
fluent profile export <profile-name> --format postman --retailer <retailer-ref>
```

| Flag | Required | Description |
|------|----------|-------------|
| `--format` | Yes | Export format (only `postman` supported) |
| `--retailer` | No | Include retailer context (repeatable) |

**Output:** `postman.<profile>.<retailer>.environment.json`

### `profile retailers [profile-name]`

List retailers configured for a profile.

```bash
fluent profile retailers              # uses active profile
fluent profile retailers <profile>    # specific profile
```

### `profile clear`

Clear the active profile/retailer context.

```bash
fluent profile clear
```

### `profile purge-sessions`

Remove stale session files from `~/.fluentcommerce/.sessions/`.

```bash
fluent profile purge-sessions
```

### Profile File Structure

```
~/.fluentcommerce/
├── <profile-name>/
│   ├── profile.json                    # { "accountId": "...", "baseUrl": "..." }
│   ├── user.<username>.json            # { "username": "...", "password": "..." }
│   └── retailer.<retailer-ref>.json    # { "id": "3", "ref": "Acme", "user": "admin" }
└── .sessions/
    └── <session-files>
```

**Manual retailer registration:** When the CLI doesn't know about a retailer (e.g., `fluent workflow list` fails with "retailer does not exist"), create the retailer JSON manually:

```json
// ~/.fluentcommerce/<profile>/retailer.<retailer-ref>.json
{
  "id": "<retailer-numeric-id>",
  "ref": "<retailer-ref>",
  "user": "<username>"
}
```

Then retry the command. This is equivalent to `fluent profile update <profile> --retailer <ref> --id <id>`.

---

## 2. `fluent module` — Module Management

### `module list`

List all installed modules on the account.

```bash
fluent module list -p <profile>
```

| Flag | Required | Description |
|------|----------|-------------|
| `-p, --profile` | Yes | Profile to use |

### `module describe <module>`

Show module contents (assets, workflows, settings, rules).

```bash
fluent module describe <module-source>
fluent module describe <module-source> --module-version 1.2.0
```

| Flag | Required | Description |
|------|----------|-------------|
| `--base-dir` | No | Extraction directory (default: `.tmp`) |
| `--module-version` | No | Version for reference modules (default: `latest`) |

`<module-source>` can be: a reference name (`core`, `order`), a URL, or a local path.

### `module config <module>`

Generate a module configuration file from the module's template.

```bash
fluent module config <module-source> \
  -p <profile> -r <retailer-ref>
```

| Flag | Required | Description |
|------|----------|-------------|
| `-p, --profile` | Yes | Profile to use |
| `-r, --retailer` | Yes | Retailer context |
| `--base-dir` | No | Extraction directory (default: `.tmp`) |
| `--module-version` | No | Version for reference modules (default: `latest`) |

**Output:** `module.config.<retailer>.<module-name>.json`

**Always check for unreplaced tokens before installing:**
```bash
rg '\[\[.*\]\]' module.config.*.json
```

```powershell
# PowerShell
Select-String -Path "module.config.*.json" -Pattern '\[\[.*\]\]'
```

Common tokens: `[[retailer.id]]`, `[[productCatalogue.ref]]`, `[[network.ref.hd]]`, `[[network.ref.cc]]`, `[[virtualCatalogue.ref]]`, `[[inventoryCatalogue.ref]]`

### `module install <module>`

Install a module to an account/retailer.

```bash
fluent module install <module-source> \
  -p <profile> -r <retailer-ref> \
  -c <config-file> \
  --exclude workflows \
  --force
```

| Flag | Required | Description |
|------|----------|-------------|
| `-p, --profile` | Yes | Profile to use |
| `-r, --retailer` | Yes | Target retailer |
| `-c, --config` | No | Config file (auto-discovers `module.config.<retailer>.<module>.json`) |
| `-w, --wait` | No | Wait between tasks in ms (default: `2000`) |
| `--base-dir` | No | Extraction directory (default: `.tmp`) |
| `--module-version` | No | Version for reference modules (default: `latest`) |
| `-i, --include` | No | Only install these assets (repeatable). Path inside module ZIP. |
| `-e, --exclude` | No | Skip these assets (repeatable). Path inside module ZIP. |
| `-f, --force` | No | Force reinstall even if same/higher version exists |

**Filter examples:**
```bash
--exclude workflows                              # skip all workflows
--exclude settings                               # skip all settings
--include workflows/fc-workflow-order-hd.json    # only this workflow
--exclude workflows --exclude settings           # skip both
```

**Version bumping for custom modules:** Same version = "already uploaded". Bump in: parent `pom.xml`, child `pom.xml` files, and `resources/module.json`.

### `module create [template-path]`

Scaffold a new module from a template.

```bash
fluent module create                          # use default Fluent template
fluent module create ./my-template.zip        # use custom template
fluent module create -b ./modules -n my-ext   # specify dir and name
```

| Flag | Required | Description |
|------|----------|-------------|
| `-b, --base-dir` | No | Directory to create module in (default: `.`) |
| `-n, --name` | No | Module name (sets `module.json` name field) |

**Output:** Standard module directory structure with `resources/module.json`, plugin scaffold, etc.

---

## 3. `fluent retailer` — Retailer Management

### `retailer create <retailer-ref>`

Create a new retailer on the account.

```bash
fluent retailer create <retailer-ref> \
  --email <email> \
  -p <profile>
```

| Flag | Required | Description |
|------|----------|-------------|
| `--email` | Yes | Retailer admin email |
| `-p, --profile` | Yes | Profile to use |
| `--trading-name` | No | Trading name (defaults to `<retailer-ref>`) |
| `--region` | No | Region |
| `--phone-number` | No | Phone number |
| `--website` | No | Website URL |

**IMPORTANT:** Always use the CLI for retailer creation. The `createRetailer` GraphQL mutation creates REST-only entities invisible to GraphQL queries.

### `retailer list`

List all locally configured retailers across all profiles.

```bash
fluent retailer list
```

**Output:** Table with Profile ID, Retailer Ref, Retailer ID columns. This lists local config files, not remote retailers.

---

## 4. `fluent setting` — Settings Management

### `setting list`

List settings (summary view: name, context, contextId, valueType).

```bash
fluent setting list -p <profile> -r <retailer-ref>
fluent setting list -p <profile> -r <retailer-ref> --name "%manifest%"
fluent setting list -p <profile> -r <retailer-ref> --context retailer --json
```

| Flag | Required | Description |
|------|----------|-------------|
| `-p, --profile` | Yes | Profile to use |
| `-r, --retailer` | Yes | Retailer context |
| `-n, --name` | No | Filter by name (`%` wildcards). Repeatable. |
| `-f, --first` | No | Limit results (disables auto-pagination) |
| `--context` | No | Filter: `account`, `retailer`, or `all` |
| `-j, --json` | No | Output as JSON (default: `false`) |

### `setting get`

Get detailed settings including full values (id, name, context, contextId, valueType, value, lobValue).

```bash
fluent setting get -p <profile> -r <retailer-ref>
fluent setting get -p <profile> -r <retailer-ref> --name "%order%" --json
```

| Flag | Required | Description |
|------|----------|-------------|
| `-p, --profile` | Yes | Profile to use |
| `-r, --retailer` | Yes | Retailer context |
| `-n, --name` | No | Filter by name (`%` wildcards). Repeatable. |
| `-f, --first` | No | Limit results (disables auto-pagination) |
| `--context` | No | Filter: `account`, `retailer`, or `all` |
| `-j, --json` | No | Output as JSON (default: `true`) |

**Difference between `list` and `get`:** `list` shows summary (no values), `get` shows full detail including `value` and `lobValue` (large object value for JSON settings).

---

## 5. `fluent workflow` — Workflow Operations

### `workflow list`

List all workflows for a retailer.

```bash
fluent workflow list -p <profile> -r <retailer-ref>
fluent workflow list -p <profile> -r <retailer-ref> --json
```

| Flag | Required | Description |
|------|----------|-------------|
| `-p, --profile` | Yes | Profile to use |
| `-r, --retailer` | Yes | Retailer context |
| `--json` | No | Output as JSON (for piping to jq) |

### `workflow download`

Download one or all workflows.

```bash
fluent workflow download -p <profile> -r <retailer-ref> -w ORDER::HD -o ./workflows/
fluent workflow download -p <profile> -r <retailer-ref> -w all -o ./workflows/
fluent workflow download -p <profile> -r <retailer-ref> -w all --json
```

| Flag | Required | Description |
|------|----------|-------------|
| `-p, --profile` | Yes | Profile to use |
| `-r, --retailer` | Yes | Retailer context |
| `-w, --workflow` | No | Workflow name or `all` (default: `all`) |
| `-o, --output-folder` | No | Output directory (default: `.`) |
| `--json` | No | Write to stdout as JSON instead of files |

**Windows gotcha:** Workflow names contain `::` (e.g., `ORDER::HD`). Windows forbids `:` in filenames. Both `-w <name>` and `-w all` fail on Windows because the CLI writes filenames like `ORDER::HD.json`. Use `--json` to output to stdout, then split and save with sanitized filenames (for example `ORDER__HD.json`) and persist `workflow-file-map.json` (original name -> filename). If MCP servers are connected, prefer MCP-based download which returns JSON content without writing files.

### `workflow merge <fragment> <target>`

Merge a workflow fragment into a base workflow.

```bash
fluent workflow merge ./fragment.json ORDER::HD -p <profile> -r <retailer-ref>
fluent workflow merge ./fragment.json ./workflows/ORDER__HD.json   # local file target
```

| Flag | Required | Description |
|------|----------|-------------|
| `-p, --profile` | Conditional | Required when target is a workflow name (not file) |
| `-r, --retailer` | Conditional | Required when target is a workflow name |

**Output:** `<target>.merged.json`

**Known bug:** Merge works locally but fails to upload with `token:undefined`. Workaround: upload merged file via REST API.

---

## 6. `fluent workflowlog` — Workflow Modification History

Track which modules/fragments have been applied to workflows.

### `workflowlog list`

```bash
fluent workflowlog list -p <profile> -r <retailer-ref>
```

### `workflowlog describe <workflow-name> [position]`

```bash
# Summary of all log entries
fluent workflowlog describe ORDER::HD -p <profile> -r <retailer-ref>

# Full detail of specific entry (0-based index)
fluent workflowlog describe ORDER::HD 0 -p <profile> -r <retailer-ref>
```

Pipe through `jq '.workflow'` to extract the workflow JSON from a specific log entry.

### `workflowlog insert <workflow-path> <module-name> <position>`

```bash
fluent workflowlog insert ./my-fragment.json my-extension 1 \
  -p <profile> -r <retailer-ref>
fluent workflowlog insert ./my-fragment.json my-extension 1 \
  -p <profile> -r <retailer-ref> -c module.config.json
```

| Flag | Required | Description |
|------|----------|-------------|
| `-p, --profile` | Yes | Profile to use |
| `-r, --retailer` | Yes | Retailer context |
| `-c, --config` | No | Module config file (for template variable substitution) |

### `workflowlog delete <workflow-name> <position>`

```bash
fluent workflowlog delete ORDER::HD 1 -p <profile> -r <retailer-ref>
```

Position is 0-based. Use `workflowlog describe` to find the position first.

---

## 7. `fluent mcp` — MCP Server

### `mcp server`

Start the built-in MCP server for Claude Code integration.

```bash
fluent mcp server --stdio
fluent mcp server --stdio --log-level debug
```

| Flag | Required | Description |
|------|----------|-------------|
| `--stdio` | Yes | Use stdio transport (required for IDE integration) |
| `--log-level` | No | `trace`, `debug`, `info`, `warn`, `error` (default: `info`) |

**`.mcp.json` configuration:**
```json
{
  "mcpServers": {
    "fluent-mcp": {
      "command": "fluent",
      "args": ["mcp", "server", "--stdio"],
      "env": {
        "FLUENT_PROFILE": "<profile-name>"
      }
    }
  }
}
```

The MCP server provides GraphQL query building, validation, workflow list/download, and health checks to AI coding assistants.

---

## REST API Fallback

When CLI commands fail or lack features, use the REST API directly.

> **Cross-platform note:** The REST API examples below use bash syntax and require bash, Git Bash, or WSL on Windows. The Fluent CLI and MCP tools (e.g., `graphql.query`, `event.send`) are the recommended cross-platform approach.

### Get OAuth Token

```bash
# IMPORTANT: Use $FLUENT_USERNAME, not $USER — $USER resolves to the OS login name on Unix/macOS.
TOKEN=$(curl -s -X POST "$BASE_URL/oauth/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "username=$FLUENT_USERNAME&password=$PASS&client_id=$ACCOUNT&client_secret=$SECRET&grant_type=password&scope=api" \
  | python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])")
# Note: Use `python` instead of `python3` on Windows if `python3` is not available.
```

```powershell
# PowerShell
# Use $FLUENT_USERNAME, not $USER (which resolves to OS login name)
$body = @{
  username      = $FLUENT_USERNAME
  password      = $PASS
  client_id     = $ACCOUNT
  client_secret = $SECRET
  grant_type    = "password"
  scope         = "api"
}
$response = Invoke-RestMethod -Uri "$BASE_URL/oauth/token" -Method Post -Body $body -ContentType "application/x-www-form-urlencoded"
$TOKEN = $response.access_token
```

### Upload Workflow via REST

```bash
curl -s -X PUT "$BASE_URL/api/v4.1/workflow" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -H "fluent.account: $ACCOUNT" \
  -d @workflow.json
```

```powershell
# PowerShell
$headers = @{
  "Authorization"  = "Bearer $TOKEN"
  "fluent.account" = $ACCOUNT
}
$workflow = Get-Content "workflow.json" -Raw
Invoke-RestMethod -Uri "$BASE_URL/api/v4.1/workflow" -Method Put -Headers $headers -Body $workflow -ContentType "application/json"
```

Requires a **retailer-scoped token** (not account-level).

---

## Account Identification from URL

The Fluent account name is extracted from the base URL, not from GraphQL:

```
https://<account>[.<environment>].api.fluentretail.com
```

| URL | Account | Environment |
|-----|---------|-------------|
| `https://acme.test.api.fluentretail.com` | `acme` | test |
| `https://acme.sandbox.api.fluentretail.com` | `acme` | sandbox |
| `https://acme.api.fluentretail.com` | `acme` | **production** |

No `.test.` or `.sandbox.` qualifier = **production** — proceed with caution.

---

## Cross-Cutting Gotchas

| Issue | Affected Commands | Workaround |
|-------|------------------|------------|
| `::` in filenames | `workflow download` | Both `-w <name>` and `-w all` fail on Windows; use `--json` flag or prefer MCP-based download |
| `token:undefined` on upload | `workflow merge` | Upload via REST API manually |
| Retailer not in local profile | `workflow list/download`, `setting list/get` | `fluent profile update <profile> --retailer <ref> --id <id>` or create `retailer.<ref>.json` manually |
| 403 on workflow upload | REST API | Use retailer-scoped token, not account-level |
| Module version unchanged | `module install` | Bump version in pom.xml + module.json, or use `--force` |
| Config tokens unreplaced | `module install` | Run `grep '\[\[.*\]\]'` on config files before install |
| `createRetailer` GraphQL | N/A | Always use `fluent retailer create` CLI instead |

---

## Module Types

Fluent modules fall into three categories:

| Type | Description | Contains Plugins? | Examples |
|------|-------------|-------------------|----------|
| **Reference** | Core Fluent-provided modules that deliver standard OMS functionality. Downloaded by name during `module install`. | Yes (OOTB rules) | `core`, `fulfilment`, `order`, `inventory` |
| **Extension** | Custom modules built by implementation teams. Contain Java plugin code (business rules), workflow fragments, settings, and data assets. | Yes (custom rules) | `fc-module-custom-extensions`, `fc-module-returns` |
| **Data** | Modules that carry only data assets (locations, products, inventory, settings) with no plugin code. Used for environment seeding, test data, or retailer-specific configuration. | No | `b2c-sample-data`, `product-catalog-data` |

**Reference modules** are versioned and hosted by Fluent. Install them by name:
```bash
fluent module install core -p <profile> -r <retailer>
```

**Extension and Data modules** are built locally and installed from a path or ZIP:
```bash
fluent module install dist/my-module-1.0.0.zip -p <profile> -r <retailer> -c <config>
```

---

## Module Dependencies

Reference modules have a strict install order. Installing out of order causes `Module dependency '<module>' not installed` errors.

| Order | Module | Dependencies | What It Provides |
|-------|--------|-------------|------------------|
| 1 | `core` | None | Base entity types, OOTB rules (SetState, SendEvent, etc.), core workflows |
| 2 | `fulfilment` | `core` | Fulfilment workflows, wave management, pick/pack rules |
| 3 | `order` | `core`, `fulfilment` | Order workflows (HD, CC), fulfilment options, sourcing |
| 4 | `inventory` | `core` | Inventory management, catalogue rules, stock adjustments |
| 5 | Custom extensions | Varies (check `module.json`) | Your business logic, custom rules, workflow fragments |

**Always verify dependencies before install:**
```bash
fluent module describe <module-source>   # shows module.json including dependencies
fluent module list -p <profile>          # shows what is already installed
```

**Common sequence for a new retailer:**
```bash
fluent module install core       -p <profile> -r <retailer> -c <core-config>
fluent module install fulfilment -p <profile> -r <retailer> -c <fulfilment-config>
fluent module install order      -p <profile> -r <retailer> -c <order-config>
fluent module install inventory  -p <profile> -r <retailer> -c <inventory-config>
fluent module install dist/my-extension.zip -p <profile> -r <retailer> -c <ext-config>
```

---

## Config Prefix System

The CLI uses a **prefix system** in `module.config.<retailer>.<module>.json` files to scope variable values to specific asset contexts. This allows the same variable name to resolve to different values in workflows vs. settings vs. data assets.

### Prefix Format

Config keys follow the pattern: `<prefix>:<variable.name>`

| Prefix | Applies To | Specificity | Example |
|--------|-----------|-------------|---------|
| `default:` | All assets (workflows, settings, data) | 0 (lowest, fallback) | `"default:network.ref": "NET_DEFAULT"` |
| `workflow:` | Workflows only | 0 | `"workflow:notification.enabled": "true"` |
| `workflow:<type>:` | Workflows matching entity type | 1 | `"workflow:order:network.ref": "NET_ORDER"` |
| `workflow:<type>:<subtype>:` | Workflows matching type + subtype | 2 (highest) | `"workflow:order:hd:carrier.ref": "HD_CARRIER"` |
| `setting:` | Settings only | 0 | `"setting:api.timeout": "30000"` |

### Specificity Rules

The CLI counts colons in the prefix to determine specificity. More colons = higher priority. When two keys resolve to the same variable, the most specific wins. On a tie, the first key in the file wins.

**Example resolution for workflow `ORDER::HD`:**
```json
{
  "default:network.ref": "NET1",                    // specificity 0
  "workflow:network.ref": "NET2",                   // specificity 0 (tie with default)
  "workflow:order:network.ref": "NET3",             // specificity 1
  "workflow:order:hd:network.ref": "NET4"           // specificity 2 — WINS
}
```

Result: `[[network.ref]]` in the ORDER::HD workflow resolves to `"NET4"`.

### Context-Based Filtering

The CLI filters recognized prefixes based on which asset folder is being processed:

| Asset Folder | Recognized Prefixes |
|-------------|---------------------|
| `assets/workflows/` | `default:`, `workflow:`, `workflow:<type>:`, `workflow:<type>:<subtype>:` |
| `assets/settings/` | `default:`, `setting:` |
| All other folders (locations, products, etc.) | `default:` only |

**Important:** Data assets (users, locations, networks, products, carriers, etc.) only recognize the `default:` prefix. There is no `location:`, `network:`, or `product:` prefix.

### Built-in Auto-Injected Variables

These variables are always available without defining them in `module.config.json`:

| Variable | Description |
|----------|-------------|
| `account.id` | Account identifier (used in rule name prefixes) |
| `retailer.id` | Retailer numeric ID |
| `retailer.ref` | Retailer reference string |
| `retailer.name` | Retailer trading name |

**Note:** `account.host` is NOT auto-injected. Define it in config if needed (e.g., `"default:account.host": "acme.sandbox.api.fluentretail.com"`).

### Config Example

**module.config.RETAILER_A.my-module.json:**
```json
{
  "default:network.ref": "NETWORK_DEFAULT",
  "default:catalogue.ref": "PC:MASTER:5",

  "workflow:order:network.ref": "NETWORK_FULFILMENT",
  "workflow:order:hd:carrier.ref": "HD_CARRIER",
  "workflow:order:cc:carrier.ref": "CC_CARRIER",

  "setting:api.timeout": "30000",
  "setting:retry.count": "3"
}
```

---

## Variable Syntax

The CLI uses `[[variable]]` tokens in JSON and CSV asset files for environment-specific substitution during `module install`.

| Syntax | Used In | Example |
|--------|---------|---------|
| `[[variable]]` | JSON/CSV assets, workflow fragments | `[[retailer.id]]`, `[[network.ref]]`, `[[account.id]]` |

### Substitution Rules

- **Only `[[...]]` is processed.** Other syntaxes (`${}`, `{{}}`) are NOT recognized.
- **Unresolved tokens are left as-is.** The CLI does not error on missing values — it silently keeps the `[[token]]` in the output. Always check for unreplaced tokens before installing: `rg '\[\[.*\]\]' module.config.*.json`
- **`module.config.json` is a values-only template.** Keys must be scoped with prefixes (`default:`, `workflow:`, `setting:`). Unscoped keys do not participate in substitution.
- **Config values must be scalars** (string, number, boolean). If your template uses metadata objects with `type`/`description` fields, replace them with real values before installing.

### Variable Flow

1. Define variables in `resources/module.config.json` (template)
2. Use `[[variable]]` tokens in asset files under `resources/assets/`
3. Run `fluent module config <module> -p <profile> -r <retailer>` to generate a config file
4. Edit the generated `module.config.<retailer>.<module>.json` with real values
5. Install with `fluent module install <module> -c <config-file> ...`

---

## Module Structure

Complete canonical directory layout for a Fluent CLI module:

```
my-module/
|
+-- resources/                          <- Module content root
|   |
|   +-- module.json                     <- Module metadata (name, version, dependencies)
|   +-- module.config.json              <- Variable template (required; can be empty {})
|   |
|   +-- assets/                         <- All deployable assets
|       +-- workflows/                  <- Workflow JSON files (*.json)
|       +-- settings/                   <- Settings JSON files (*.json)
|       +-- locations/                  <- Location JSON files (*.json)
|       +-- users/                      <- User JSON files (*.json)
|       +-- roles/                      <- Role JSON files (*.json)
|       +-- networks/                   <- Network JSON files (*.json)
|       +-- carriers/                   <- Carrier JSON files (*.json)
|       +-- product-catalogues/         <- Product catalogue JSON files (*.json)
|       +-- categories/                 <- Category CSV files (*.csv)
|       +-- products/                   <- Product CSV files (*.csv)
|       +-- inventory-catalogues/       <- Inventory catalogue JSON files (*.json)
|       +-- inventory/                  <- Inventory CSV files (*.csv)
|       +-- virtual-catalogues/         <- Virtual catalogue JSON files (*.json)
|       +-- control-groups/             <- Control group JSON files (*.json)
|       +-- controls/                   <- Control JSON files (*.json)
|       +-- storage-areas/              <- Storage area JSON files (*.json)
|       +-- payment-service-providers/  <- PSP JSON files (*.json)
|       +-- workflow-fragments/         <- Workflow fragment files (optional)
|           +-- <workflow-name>/        <- Subfolder per target workflow
|               +-- *.json
|
+-- plugins/                            <- Java plugin code (optional, extension modules only)
|   +-- pom.xml                         <- Maven parent POM
|   +-- rules/                          <- Business rule Java classes
|   +-- types/                          <- Model/DTO Java classes
|   +-- util/                           <- Utility Java classes
|
+-- scripts/
|   +-- build-module.sh                 <- Build script
|
+-- dist/                               <- Build output (created after build)
    +-- my-module-1.0.0.zip             <- Deployable module package
```

**Key notes:**
- `module.config.json` is required even if empty (`{}`).
- `plugins/` is only present in extension modules with custom Java rules.
- Workflow fragments must be in subfolders under `workflow-fragments/` named after the target workflow. Files placed directly under `workflow-fragments/` are ignored.
- `module.json` defines `name`, `version`, `title`, `description`, `authors`, `dependencies`, and `contracts`.

**module.json example:**
```json
{
  "_schema": "1.0.0",
  "name": "sample/custom-extensions",
  "version": "1.0.0",
  "title": "Custom Extensions",
  "description": "Custom business rules and workflow extensions",
  "authors": [{ "name": "Implementation Team" }],
  "dependencies": [],
  "contracts": []
}
```

---

## Selective Asset Installation

Use `--include` and `--exclude` flags on `module install` to deploy only specific asset types. Paths match folder names inside the module's `assets/` directory.

### Filterable Paths

| Path | Asset Type |
|------|-----------|
| `workflows` | Workflow JSON files |
| `settings` | Settings JSON files |
| `rules` | Java plugin JARs |
| `locations` | Location definitions |
| `users` | User definitions |
| `roles` | Role definitions |
| `networks` | Network definitions |
| `carriers` | Carrier definitions |
| `products` | Product CSV data |
| `categories` | Category CSV data |
| `inventory` | Inventory CSV data |
| `product-catalogues` | Product catalogue definitions |
| `inventory-catalogues` | Inventory catalogue definitions |
| `virtual-catalogues` | Virtual catalogue definitions |
| `workflow-fragments` | Workflow fragment files |

### Common Scenarios

**Skip workflows for multi-retailer installs** (when each retailer has unique workflows):
```bash
fluent module install dist/my-module.zip -p <profile> -r <retailer> --exclude workflows
```

**Plugin-only update** (recompiled Java rules, workflows/settings unchanged):
```bash
fluent module install dist/my-module.zip -p <profile> -r <retailer> --include rules --force
```

**Workflows + settings only** (common update pattern):
```bash
fluent module install dist/my-module.zip -p <profile> -r <retailer> \
  --include workflows settings --force
```

**Production install without test data:**
```bash
fluent module install dist/my-module.zip -p <profile> -r <retailer> \
  --exclude products inventory categories
```

**Large dataset chunking** (avoid timeouts):
```bash
# Step 1: Infrastructure (everything except bulk data)
fluent module install dist/my-module.zip -p <profile> -r <retailer> --exclude products inventory

# Step 2: Products (with increased wait)
fluent module install dist/my-module.zip -p <profile> -r <retailer> --include products --wait 5000

# Step 3: Inventory
fluent module install dist/my-module.zip -p <profile> -r <retailer> --include inventory --wait 5000
```

**Fast dev iteration** (deploy only what changed):
```bash
# Full install first time
fluent module install dist/my-module.zip -p dev -r DEV -c config.json

# Subsequent iterations — only changed assets
fluent module install dist/my-module.zip -p dev -r DEV --include workflows --force
```

---

## Workflow Fragment Strategies

Workflow fragments use `mergeStrategy` on rulesets, rules, statuses, and triggers to control how they combine with the base workflow during `module install` or `workflow merge`.

| Strategy | Behavior | When to Use |
|----------|----------|-------------|
| **`merge`** | Adds or updates rules/triggers/userActions within an existing ruleset. New rulesets are added. Duplicate rules (same name + props) are ignored. Use `index` on rules to control insertion position. | Adding custom logic to reference module rulesets. Extending without breaking existing rules. |
| **`replace`** | Completely replaces the entire matched ruleset (or rule/status/trigger). The fragment's content becomes the new content. | Replacing obsolete logic. Taking full ownership of a ruleset. |
| **`keep`** | Preserves the original element from the base workflow. The fragment's element is ignored if a match exists. | Conditional additions — only add if not already present. Safe defaults. |
| **`delete`** | Removes the matched element from the workflow. No-op if the element does not exist. Processed before `replace` and `merge`. | Removing deprecated rulesets or rules. Cleanup during upgrades. |

### Matching Keys

Elements are matched for strategy resolution using these keys:

| Element | Matching Key |
|---------|-------------|
| Rulesets | `name \| type \| subtype \| [trigger statuses]` |
| Statuses | `name \| entityType` |
| Triggers | `status` |
| User Actions | `eventName` (canonical). Some merge paths may also use `context[0].label` as a secondary heuristic. |

### Strict User Action Contract (Anti-Hallucination)

When workflow fragments add or merge `userActions`, enforce:
1. Keep `userActions` at ruleset level (never inside rule props).
2. Set explicit `eventName` for every action (do not infer from `label`).
3. Keep `context[]` to documented fields (`label`, `type`, `modules`, optional `confirm`).
4. Keep `attributes[]` to documented fields (`name`, `type`, `mandatory`, optional `source`, `options`).
5. If action visibility is missing in UI, verify ALL THREE mandatory Transition API params (`module` specific name — `"all"` returns NOTHING, `flexType`, `flexVersion`) before changing schema.

### Fragment Location in Modules

```
resources/assets/workflow-fragments/<workflow-name>/*.json
```

Fragments are sorted alphabetically by filename and processed in order. Files directly under `workflow-fragments/` (not in a subfolder) are ignored.

### Fragment Template

```json
{
  "name": "ORDER::<SUBTYPE>",
  "entityType": "ORDER",
  "entitySubtype": "<SUBTYPE>",
  "rulesets": [
    {
      "name": "<RULESET_NAME>",
      "type": "ORDER",
      "mergeStrategy": "merge",
      "rules": [
        {
          "name": "[[account.id]].<module>.<RuleName>",
          "mergeStrategy": "merge",
          "index": 0,
          "props": {
            "yourProp": "<value>"
          }
        }
      ],
      "triggers": [{ "status": "CREATED" }],
      "userActions": []
    }
  ]
}
```

---

## Troubleshooting Quick Reference

Top error messages from the Fluent CLI with causes and fixes.

### Critical Errors

| Error | Cause | Fix |
|-------|-------|-----|
| `Auth failed: 401 for <email>` | Invalid credentials or expired password | Update password: `fluent profile update <profile> --user <user> --username <user> --password <new-pass>`. Purge sessions: `fluent profile purge-sessions`. |
| `Module dependency '<module>' not installed` | Required module not present on account | Install dependencies in order: `core` -> `fulfilment` -> `order` -> `inventory` -> custom. Check `module.json` dependencies. |
| `Invalid Module: core - a valid module should contain: assets folder, module.json file` | Module structure invalid or corrupt | Verify with `fluent module describe <module>`. Ensure `resources/module.json` and `resources/assets/` exist. |
| `Request timeout` / `connect ETIMEDOUT` | Network timeout or API unavailable | Check network connectivity. Verify API endpoint is reachable. Retry command. Use `--wait` to increase delays. |

### High Priority Errors

| Error | Cause | Fix |
|-------|-------|-----|
| `Module not found: <module>` | Wrong module name or path | For reference modules use exact names: `core`, `fulfilment`, `order`. For local modules verify the path exists. |
| `Profile '<name>' not found` | Profile does not exist | List profiles: `fluent profile list`. Create: `fluent profile create <name> ...`. |
| `Retailer configuration is required but was not provided` | Missing `--retailer` flag or active context | Set active retailer: `fluent profile use <profile> --retailer <ref>`. Or add `--retailer <ref>` to the command. |
| `Token '<placeholder>' not resolved` | Missing variable in config file | Run `fluent module config <module> -p <profile> -r <retailer>` to regenerate config. Fill all `[[...]]` placeholders before install. |
| `Missing required option: --id` / `--email` | Required parameter omitted | Check command help: `fluent <command> --help`. Add the required flag. |

### Medium Priority Errors

| Error | Cause | Fix |
|-------|-------|-----|
| `Setting '<name>' not found` | Setting does not exist or wrong name | List settings with wildcard: `fluent setting list -p <profile> -r <retailer> --name '%<pattern>%'`. Check spelling and context. |
| `Workflow '<name>' already exists` | Workflow conflict during install | Use `--exclude workflows` to skip, or `--force` to overwrite. |
| `Invalid workflow definition` | Workflow JSON has structural errors | Validate JSON syntax. Check required fields: `name`, `entityType`, `statuses`, `rulesets`. |
| `Workflow '<name>' not found` | Workflow does not exist in retailer | List workflows: `fluent workflow list -p <profile> -r <retailer>`. Verify spelling. |
| `Fragment workflow file does not exist` | Fragment file path invalid | Verify the file exists at the specified path. Use absolute or correct relative path. |

### Low Priority Warnings

| Error | Cause | Fix |
|-------|-------|-----|
| `Command not found: fluent` | CLI not in PATH or not installed | Verify: `npm list -g fluent-cli`. Reinstall if needed. Check PATH includes npm global bin directory. |
| `No active profile set` | No profile selected | Set active: `fluent profile use <profile> --retailer <retailer>`. |
| `Module config file not found` | Config file missing or wrong name | Generate: `fluent module config <module> -p <profile> -r <retailer>`. Expected name: `module.config.<retailer>.<module>.json`. |
| `Workflow log position '<pos>' not found` | Invalid log entry position | List logs: `fluent workflowlog describe <workflow> -p <profile> -r <retailer>`. Positions are 0-based. |

### Quick Diagnostic Commands

```bash
fluent --version                           # Verify CLI installed
fluent profile active                      # Check active profile/retailer
fluent profile purge-sessions              # Purge all session configs (fixes many auth issues)
fluent --debug <command>                   # Enable verbose debug output
fluent module describe <module-path>       # Validate module structure
fluent module list -p <profile>            # Check installed modules on account
```

---

## Quick Reference Card

```
fluent profile  create|list|active|use|clear|update|export|purge-sessions|retailers
fluent module   config|create|describe|install|list
fluent retailer create|list
fluent setting  get|list
fluent workflow download|list|merge
fluent workflowlog delete|describe|insert|list
fluent mcp      server
```
