> ## Documentation Index
> Fetch the complete documentation index at: https://docs.jelou.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Workflows and testing

> Create and validate workflows, test them locally with traces and a dashboard, debug production conversations with jelou logs, and reset a user's state.

These commands cover the cycle of building, testing, and debugging a project's
workflows: authoring and validation (`jelou workflow`), local testing with traces
(`jelou test`), production triage (`jelou logs`), and user state reset
(`jelou users`).

<Note>
  Syncing workflows to local files (`jelou link`, `pull`,
  `status`, `push`, `incoming`) is documented in
  [Projects and channels](/en/guides/cli/project).
</Note>

## `jelou workflow`

| Subcommand                              | Description                                                                                                                       |
| --------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `list [--project-id <id>]`              | Lists projects; with `--project-id`, lists the project's skills/channels                                                          |
| `create --project-id <id> --name "<n>"` | Creates a new workflow in a project                                                                                               |
| `node-spec [<type>] [--list]`           | Prints one node type's schema (`--list` lists all types, or pass a type name for its full JSON) without loading the whole catalog |
| `validate [<file>]`                     | Validates the `workflows/*.json` against the canonical validator                                                                  |

<Note>
  `jelou workflow` has 16 subcommands in total (besides the ones above:
  `update`, `set-default`, `delete`/`rm`, `hide`, `unhide`, `allow-user`,
  `allow-country`, `evaluate`, `skill`, `build`, `branches`,
  `canonicalize-branch`, `inject-ecommerce`, `adopt`, `authoring`). Explore them
  with `jelou workflow --describe`.
</Note>

```bash theme={null}
jelou workflow list
jelou workflow list --project-id 01kf13bcth4ytadcx9h8pq8w9h --agent
jelou workflow create --project-id 01kf13bcth4ytadcx9h8pq8w9h --name "Order Generation V3"
jelou workflow node-spec --list
jelou workflow node-spec AI_TASK
jelou workflow validate
jelou workflow validate workflows/saludo.whatsapp.json
jelou workflow validate --allow-warnings
jelou workflow validate --fix workflows/draft.json
jelou workflow validate --partial workflows/draft.json
```

`validate` runs a canonical multi-phase pipeline (schema → autofix →
normalize → ids → config → quality → whatsapp → edges → lint → finalize) and
reports `{ status, errorCount, warnCount }` per phase. With errors it exits with
a non-zero code; `--allow-warnings` exits 0 if only warnings remain.

Additional flags: `--fix` (alias `--write`) canonicalizes the file in place
(mints ids, normalizes branch tokens, repairs edge handles); `--quiet` only
prints files that have errors or warnings; `--out <path>` saves the same JSON
payload to disk in addition to stdout.

`--partial <file>` runs the full validator on a single in-progress draft in
*preview* mode: it returns rich diagnostics but never gates — it always
exits 0 regardless of errors. As of v1.88, a validate-on-write hook runs this
same preview automatically the moment an AI agent writes a workflow's JSON,
so diagnostics arrive immediately (they're advisory only: they never block
the write).

Also as of v1.88, `validate` now validates `tools/*.json` files too (not
just `workflows/*.json`) using the real tool-push rules, and it no longer
incorrectly flags `$output.set()` inside a tool's CODE node — that's the
correct way a tool returns a value.

## `jelou test`

Test workflows locally: send messages, persist traces and chats, and
inspect them.

| Subcommand                                    | Description                                                                                                                               |
| --------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `tool <slug> --input k=v`                     | Executes a tool server-side and reports which output fired (in the CLI's own `--help` output, `tool` now leads the list, ahead of `send`) |
| `send text --target <slug> --message "<txt>"` | Sends a message to a workflow and persists the trace                                                                                      |
| `turn status <execution-id> --target <slug>`  | Long-polls an in-flight turn until it closes                                                                                              |
| `chats list --target <slug>`                  | Lists the recorded chats (executions)                                                                                                     |
| `chats show <id> --target <slug>`             | Detail of a chat (turns + rendered output)                                                                                                |
| `trace <execution-id> --target <slug>`        | Inspects an execution's trace                                                                                                             |
| `grep <query> --target <slug>`                | Full-text search across recorded user/assistant messages                                                                                  |
| `stats --target <slug>`                       | Aggregate counts, terminal-state breakdown, and `qa.db` storage size                                                                      |
| `reset <execution-id> --target <slug>`        | Clears the gateway-side cache for an execution so it reruns from the start                                                                |
| `cleanup --target <slug>`                     | Drops old `qa.db` runs per the retention policy                                                                                           |
| `dashboard`                                   | Starts the local testing dashboard                                                                                                        |
| `finish <execution-id> --target <slug>`       | Marks a recorded run with a PASS/FAIL/INCONCLUSIVE verdict                                                                                |
| `whatsapp <verb>`                             | Testing with a real WhatsApp account (experimental)                                                                                       |

```bash theme={null}
jelou test tool generar-otp --input identificacion=0912345678
jelou test send text --target saludo-web --message "hi"
jelou test send text --target saludo-web --execution <id> --message "next"
jelou test chats list --target saludo-web --terminal TIMEOUT --since 7d --json
jelou test trace sKI7morplA4LKUAX51Mqx --target saludo-web
```

### Local testing dashboard

```bash theme={null}
jelou test dashboard            # opens the browser at http://127.0.0.1:8766
jelou test dashboard --port 9090
jelou test dashboard --repo otro-repo--abc123   # reads another repo's qa.db
jelou test dashboard --no-open
```

It brings up a **single-URL local web interface** (Hono server + React UI) to
visually inspect your workflow tests — it's the graphical version of what
`jelou test send text`, `jelou test chats list`, and `jelou test trace`
produce.

**What it shows:**

* **Targets / workflows** — the workflows you can test (those that have
  recorded runs, plus the ones in the lockfile even if they don't have any
  yet).
* **Runs (test chats)** — each recorded test conversation, with its turns, the
  rendered message, and its terminal status (`STABLE`, `TIMEOUT`,
  `HARNESS_STALL`, `HARNESS_ERROR`).
* **Per-node trace** — for each run, the workflow's step-by-step execution:
  each node with its initial and final state.

Internally it serves these read-only endpoints
(`/api/targets`, `/api/workflows`, `/api/runs`, `/api/runs/:id`,
`/api/runs/:id/trace`) and, if there's a profile that can send messages, it
lets you **start new chats** from the UI (`POST /api/chats`,
`/api/runs/:id/messages`).

**What data it works with:**

* It reads the per-target **`qa.db`** files (SQLite) — the **same** ones the
  other `jelou test` commands create and query. There's no separate database:
  the dashboard only visualizes them.
* Data is isolated per **repo** (`repo-id` segment = git root directory name +
  a short hash) and per **profile**. That's why you must run it inside the repo
  with your runs, or point it at another one with `--repo <segment>`.

| Flag                   | Description                                                            |
| ---------------------- | ---------------------------------------------------------------------- |
| `--port <n>`           | TCP port (default 8766; if it's taken, uses a free one)                |
| `--host <host>`        | Host to bind to (must be loopback: `127.0.0.1`, `::1`, or `localhost`) |
| `--repo <segment>`     | Reads another repo's `qa.db` instead of the current one                |
| `--open` / `--no-open` | Whether to open the browser automatically                              |

It's **local-only** (listens on loopback); for remote access use SSH port
forwarding: `ssh -L 8766:localhost:8766 <host>`.

<Note>
  The BrainOps bundles `jelou-build-workflow` and `jelou-test-workflow`
  ([skills](/en/guides/cli/skills)) orchestrate this build-and-test cycle for
  workflows from an AI agent.
</Note>

## `jelou logs` — production conversation triage

**Read-only** access to a bot's conversation history. It lets you drill down
from conversation → chat timeline → the node that failed.

| Subcommand                                | Description                                  |
| ----------------------------------------- | -------------------------------------------- |
| `conversations list --bot-id <id>`        | Lists conversations (one row per user × day) |
| `chat --bot-id <id> --user-id <phone>`    | A user's timeline (messages + executions)    |
| `node --execution-id <id> --node-id <id>` | Debugs a single node execution               |

```bash theme={null}
jelou logs conversations list --bot-id d42d688c-1c3f-4b99-9f32-70e14a10b365
jelou logs conversations list --bot-id d42d688c-… --message "return"
jelou logs chat --bot-id d42d688c-… --user-id 593959216623 --failed-only
jelou logs node --execution-id sKI7morplA4LKUAX51Mqx --node-id 69eb6c946b3d065a3bc6cc44
```

They all accept `--from`/`--to` (ISO-8601), `--cursor` for pagination, and `--out <path>` to save the JSON envelope. The `--bot-id` is the bot connected to the
channel — discover it with `jelou channels list`. The drill-down flow prints the
next command under each FAILED execution.

## `jelou users reset`

Hard-resets a user's cached state with a bot (clears the `state`,
`skill`, and `state_manual` keys). Useful before re-testing from scratch or to
unblock a user stuck in a loop.

```bash theme={null}
jelou users reset --bot-id d42d688c-… --user-id 593959216623 --yes
jelou users reset --channel-id 01KR… --user-id 593959216623 --yes
```

<Warning>
  It's destructive: in-flight conversations lose their context. `--bot-id` and
  `--channel-id` are mutually exclusive; under `--agent`/`--no-input`, `--yes` is
  required.
</Warning>
