@imbrace/cli 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -337,6 +337,13 @@ imbrace data-board list-items --board-id <boardId> --json
337
337
 
338
338
  For complete CLI reference for coding agents, see [`llms.txt`](./llms.txt).
339
339
 
340
+ **Tip — one-shot setup for an AI agent:**
341
+ ```bash
342
+ imbrace docs > /tmp/imbrace-llms.txt # ~30 KB reference, bundled with the package
343
+ # then feed /tmp/imbrace-llms.txt into your agent's context (Claude Code, Cursor, ...)
344
+ ```
345
+ The `imbrace docs` command prints the full `llms.txt` shipped inside the npm package — no network or repo clone needed.
346
+
340
347
  ---
341
348
 
342
349
  ## Project Structure
@@ -0,0 +1,10 @@
1
+ import { Command } from "@oclif/core";
2
+ export default class Docs extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ path: import("@oclif/core/interfaces").BooleanFlag<boolean>;
7
+ json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
8
+ };
9
+ run(): Promise<void>;
10
+ }
@@ -0,0 +1,39 @@
1
+ import { Command, Flags } from "@oclif/core";
2
+ import { readFileSync, existsSync } from "node:fs";
3
+ import { fileURLToPath } from "node:url";
4
+ import { dirname, resolve } from "node:path";
5
+ export default class Docs extends Command {
6
+ static description = "Print the bundled llms.txt — a comprehensive command reference designed to be fed into a coding agent's context (Claude, Cursor, ...). Pipe to a file: `imbrace docs > llms.txt`.";
7
+ static examples = [
8
+ "imbrace docs # print full llms.txt to stdout",
9
+ "imbrace docs --path # print absolute path to bundled llms.txt",
10
+ "imbrace docs > /tmp/imbrace-llms.txt # save for an AI agent's context",
11
+ ];
12
+ static flags = {
13
+ path: Flags.boolean({ description: "Print only the absolute path to llms.txt (don't print contents)" }),
14
+ json: Flags.boolean({ description: "Output as JSON: { path, content }" }),
15
+ };
16
+ async run() {
17
+ const { flags } = await this.parse(Docs);
18
+ const here = dirname(fileURLToPath(import.meta.url));
19
+ const candidates = [
20
+ resolve(here, "../../llms.txt"),
21
+ resolve(here, "../llms.txt"),
22
+ resolve(here, "../../../llms.txt"),
23
+ ];
24
+ const llmsPath = candidates.find((p) => existsSync(p));
25
+ if (!llmsPath) {
26
+ this.error(`llms.txt not found. Looked in:\n${candidates.map((p) => ` - ${p}`).join("\n")}\n\nReinstall the package or fetch from https://github.com/imbraceltd/imbrace-cli/blob/main/llms.txt`);
27
+ }
28
+ if (flags.path && !flags.json) {
29
+ this.log(llmsPath);
30
+ return;
31
+ }
32
+ const content = readFileSync(llmsPath, "utf8");
33
+ if (flags.json) {
34
+ this.log(JSON.stringify({ path: llmsPath, content }, null, 2));
35
+ return;
36
+ }
37
+ this.log(content);
38
+ }
39
+ }
package/llms.txt ADDED
@@ -0,0 +1,625 @@
1
+ # Imbrace CLI
2
+
3
+ > Imbrace CLI allows coding agents and developers to interact with the Imbrace platform via command line. Imbrace is a CRM platform supporting AI chat assistants, data boards (CRM pipelines), workflows, and more.
4
+
5
+ Things to remember when using Imbrace CLI:
6
+
7
+ - Always run `imbrace login` first. Credentials are stored via the `conf` package — exact path depends on OS:
8
+ - macOS: `~/Library/Preferences/imbrace-nodejs/config.json`
9
+ - Linux: `~/.config/imbrace-nodejs/config.json`
10
+ - Windows: `%APPDATA%\imbrace-nodejs\Config\config.json`
11
+ - If a command returns a 401 error, run `imbrace login` again to refresh credentials.
12
+ - All commands support `--json` flag for machine-readable output — always use `--json` when scripting or using a coding agent.
13
+ - Run `imbrace data-board list --json` first to get Board IDs (`brd_...`) before using other data-board commands.
14
+ - Board items use the format `{ fields: [{ board_field_id, value }] }` — field IDs are fetched automatically in interactive mode.
15
+ - Field types available (16): `ShortText`, `LongText`, `Number`, `Date`, `Email`, `Phone`, `Currency`, `SingleSelection`, `MultipleSelection`, `Checkbox`, `Assignee`, `MultipleAssignee`, `Link`, `Notes`, `Origin`, `Priority`. **Do NOT use `Dropdown`** — backend rejects it (use `SingleSelection` instead).
16
+ - Run `imbrace ai-agent list --json` first to get Agent IDs before using other ai-agent commands.
17
+
18
+ ## Authentication
19
+
20
+ - `imbrace login --api-key api_xxx...` — Login with API key (recommended for CI/CD and coding agents)
21
+ - `imbrace login --email user@example.com --password mypass` — Login with email and password
22
+ - `imbrace logout` — Clear saved credentials
23
+ - `imbrace whoami --json` — Verify current authentication status
24
+
25
+ ## Built-in commands
26
+
27
+ - `imbrace help [command]` — Show help for any command
28
+ - `imbrace autocomplete [shell]` — Display shell completion install instructions (bash, zsh, fish, powershell)
29
+ - `imbrace --version` — Print CLI version
30
+
31
+ ## Data Board Commands
32
+
33
+ - `imbrace data-board list --json` — List all boards and their IDs (`brd_...`)
34
+ - `imbrace data-board create --name "Sales Pipeline" --json` — Create a new board
35
+ - `imbrace data-board create-field <boardId> --name "Company" --type ShortText --json` — Add a field to a board
36
+ - `imbrace data-board create-item <boardId> --fields '[{"board_field_id":"<id>","value":"Acme"}]' --json` — Create a record (Name field is required)
37
+ - `imbrace data-board list-items --board-id <id> --limit 20 --skip 0 --json` — List records with pagination
38
+ - `imbrace data-board list-items --board-id <id> --q "Acme" --json` — Full-text search records
39
+ - `imbrace data-board update-item <boardId> <itemId> --data '[{"key":"<fieldId>","value":"New"}]' --json` — Update a record
40
+ - `imbrace data-board delete-item <boardId> <itemId> --yes --json` — Delete a record
41
+ - `imbrace data-board export-csv --board-id <id> --out ./board.csv` — Export board to CSV file
42
+
43
+ ## AI Agent Commands
44
+
45
+ **CRUD:**
46
+ - `imbrace ai-agent list --json` — List all AI agents and their IDs
47
+ - `imbrace ai-agent get <id> --json` — Get details of an AI agent
48
+ - `imbrace ai-agent create --name "Sales Bot" --json` — Create (minimal — defaults to system provider, "Default" model)
49
+ - `imbrace ai-agent create --name "X" --instructions "..." --personality "..." --tone "..." --json` — Create with full Behavior Settings
50
+ - `imbrace ai-agent update <id> --name "New Name" --json` — Update any subset of fields (others preserved via PUT-merge)
51
+ - `imbrace ai-agent update <id> --temperature 0.7 --tone "Casual" --json` — Update Behavior Settings
52
+ - `imbrace ai-agent delete <id> --yes --json` — Delete an AI agent
53
+
54
+ **Discovery (LLM providers/models):**
55
+ - `imbrace ai-agent list-providers --json` — List LLM providers (system + custom). Returns the UUID `provider_id` to pass to `--provider-id`.
56
+ - `imbrace ai-agent list-models --provider-id <id> --json` — List models for a provider. Use `system` for the default provider.
57
+
58
+ **Discovery (Knowledge Hub):**
59
+ - `imbrace ai-agent list-folders [--search <q>] --json` — List Knowledge Hub folders for `--folder-ids`.
60
+ - `imbrace ai-agent list-files --folder-id <id> --json` — List files inside a folder for `--file-ids`.
61
+
62
+ ### AI Agent flags
63
+
64
+ `create` and `update` accept the same flags. `update` lets you change any subset; unspecified flags stay unchanged.
65
+
66
+ **Identity:**
67
+ - `--name` / `-n` — Agent name (required for create)
68
+ - `--description` / `-d` — Short description (shown under the title in UI list)
69
+ - `--instructions` / `-i` — System prompt sent on every chat
70
+
71
+ **Model:**
72
+ - `--model` — LLM model name (default: `Default` for system provider). Discover via `list-models`. **System provider only has one model named `Default`** — passing other names (like `gpt-4o`) makes the UI dropdown render empty even though the agent saves.
73
+ - `--provider-id` — LLM provider ID (default: `system`). Discover via `list-providers`. **Pass the UUID `provider_id`, NOT the MongoDB `_id`** — the UI matches dropdowns against the UUID.
74
+ - `--mode` — `standard` | `advanced` (default: standard)
75
+ - `--temperature` — 0.0–2.0 (default: 0.1). Lower = deterministic, higher = creative.
76
+
77
+ **Behavior Settings (UI tab):**
78
+ - `--personality` — Persona / role description → `personality_role`
79
+ - `--core-task` — Main tasks the agent performs → `core_task`
80
+ - `--tone` — Tone and style → `tone_and_style`
81
+ - `--response-length` — `short` | `medium` | `long`
82
+ - `--banned-words` — Comma-separated. **Word-level filter** on outputs (for topic refusal use `--instructions`).
83
+ - `--category` — `Support` | `Sales` | `Marketing` | `Team` | `Other`. Default: `Support`.
84
+ - `--guardrail-id` — Attach a guardrail by ID
85
+ - `--preload-information` — Static info auto-injected into context every chat
86
+
87
+ **Knowledge Support (UI tab) — comma-separated IDs:**
88
+ - `--folder-ids "id1,id2"` — Knowledge Hub folder IDs (RAG sources). Discover via `list-folders`.
89
+ - `--default-folder-id <id>` — Default folder for new files
90
+ - `--knowledge-hubs "id1,id2"` — Knowledge Hub IDs
91
+ - `--board-ids "brd_xxx,brd_yyy"` — Document Model (data board) IDs. Discover via `imbrace data-board list`.
92
+ - `--file-ids "id1,id2"` — Pre-uploaded file IDs. Discover via `list-files --folder-id <id>`.
93
+
94
+ **Runtime toggles (boolean, support `--no-X`):**
95
+ - `--show-thinking` / `--no-show-thinking` — Show model's thinking process (default: false)
96
+ - `--streaming` / `--no-streaming` — Stream response token-by-token (default: true)
97
+ - `--use-memory` / `--no-use-memory` — Remember conversation context across turns (default: true). **Known issue:** `--no-use-memory` at create may not stick (backend default override) — workaround: update after create.
98
+
99
+ **Other:**
100
+ - `--yes` / `-y` — Skip confirmation on delete
101
+ - `--json` — Full JSON output (machine-readable)
102
+ - `--id-only` — Print only the new agent ID (pipe-friendly, no jq). On `create` only.
103
+ - `-h` / `--help` — Show usage
104
+
105
+ ### Full create example (Behavior Settings + custom provider + Knowledge)
106
+
107
+ ```bash
108
+ # 1. Discover provider + model
109
+ imbrace ai-agent list-providers --json
110
+ imbrace ai-agent list-models --provider-id e2629292-7e9f-4d55-ba18-6827747eab33 --json
111
+
112
+ # 2. Discover Knowledge Hub folder + board (Document Model)
113
+ imbrace ai-agent list-folders --search support --json
114
+ imbrace data-board list --json
115
+
116
+ # 3. Create with full settings
117
+ imbrace ai-agent create \
118
+ --name "Customer Support Specialist" \
119
+ --description "Senior AI customer support agent" \
120
+ --instructions "You are a senior customer support specialist..." \
121
+ --personality "Friendly and professional" \
122
+ --core-task "Answer product inquiries, help track orders" \
123
+ --tone "Polite, professional, warm" \
124
+ --response-length "medium" \
125
+ --banned-words "stupid, idiot" \
126
+ --category "Support" \
127
+ --provider-id "e2629292-7e9f-4d55-ba18-6827747eab33" \
128
+ --model "gpt-4o-mini" \
129
+ --temperature 0.3 \
130
+ --folder-ids "69bb82faa2cc764639bc6bdb" \
131
+ --board-ids "brd_e5450d76-84d4-4c34-8b13-3d0f1873b53b" \
132
+ --json
133
+ ```
134
+
135
+ ### How AI Agent create works (under the hood)
136
+
137
+ `imbrace ai-agent create` calls `client.agent.createUseCase({ usecase, assistant })` from `@imbrace/sdk`, which atomically creates:
138
+ 1. An AI assistant (model, instructions, prompt)
139
+ 2. A web channel (for chat widget demo)
140
+ 3. A use-case template (the card shown on `cloud.imbrace.co/ai-agent`)
141
+
142
+ The `workflow_name` field is auto-generated as `<slug>_v<timestamp>` to ensure uniqueness — required by backend, must be snake_case (no spaces or special characters).
143
+
144
+ ### Full request body sent to backend
145
+
146
+ The route mirrors the frontend `createCustomUseCase` payload (see `new-frontend/src/pages/AIAssistantManagement/useAIAssistantFormHook.tsx`):
147
+
148
+ ```ts
149
+ {
150
+ usecase: { title, short_description, agent_type, demo_url, supported_channels },
151
+ assistant: {
152
+ // Identity
153
+ name, description, instructions, workflow_name, credential_name,
154
+ // Model
155
+ provider_id: "system", model_id: "gpt-4o",
156
+ // Agent scope
157
+ agent_type: "agent", mode: "standard", version: 2, channel, category,
158
+ // Behavior (Behavior Settings tab in UI)
159
+ personality_role, core_task, tone_and_style, response_length,
160
+ banned_words, preload_information, guardrail_id, show_thinking_process,
161
+ // Runtime
162
+ streaming: true, use_memory: true, temperature: 0.1,
163
+ // Knowledge (Knowledge Support tab in UI)
164
+ knowledge_hubs: [], folder_ids: [], default_folder_id, board_ids: [], file_ids: [],
165
+ // Advanced (Advanced Settings tab in UI)
166
+ workflow_function_call: [], sub_agents: [], team_leads: [],
167
+ // RAG / tooling
168
+ metadata: {
169
+ other_requirements: [], channel_id: "", team_ids: [], tool_server: null,
170
+ enable_echart: false, top_k_relevant_results: 3, top_k: 40, max_steps: 10
171
+ }
172
+ }
173
+ }
174
+ ```
175
+
176
+ **Fields not yet exposed via CLI flags** (set to defaults — modify via UI or future CLI updates): `channel`, `preload_information`, `knowledge_hubs`, `folder_ids`, `default_folder_id`, `board_ids`, `file_ids`, `workflow_function_call`, `sub_agents`, `team_leads`, `metadata.tool_server`, `metadata.team_ids`, `metadata.other_requirements`.
177
+
178
+ **IMPORTANT — All AI Agent content must be in English.** This includes `--name`, `--description`, and `--instructions`. Reasons:
179
+ 1. The slug for `workflow_name` is derived from the name. Vietnamese diacritics get stripped and produce unreadable slugs (e.g. `"Trợ lý hỗ trợ"` → `tr_l_h_tr_v...`).
180
+ 2. English content keeps logs, search, and downstream LLM behavior consistent.
181
+
182
+ If the user describes an agent in Vietnamese, translate the full payload to English before calling `imbrace ai-agent create`.
183
+
184
+ ## Workflow Commands
185
+
186
+ A workflow (powered by Activepieces) is a chain of nodes: a trigger fires, then actions run in sequence. Use it for automation — e.g. "when Slack message arrives → ask AI → reply to thread".
187
+
188
+ **Flow CRUD:**
189
+
190
+ - `imbrace workflow list --json` — List all workflows and their IDs
191
+ - `imbrace workflow list --folder-id <folderId> --json` — Filter to flows in one folder/category
192
+ - `imbrace workflow list --folder-id NULL --json` — Only flows that aren't in any folder
193
+ - `imbrace workflow get <flowId> --json` — Get details (including node tree)
194
+ - `imbrace workflow create --name "My Flow" --json` — Create an empty workflow
195
+ - `imbrace workflow create --name "X" --folder-id <folderId> --json` — Create directly inside a category folder
196
+ - `imbrace workflow move <flowId> --folder-id <folderId>` — Move a flow into a folder. Pass `NULL` to unfile.
197
+ - `imbrace workflow delete <flowId> --yes --json` — Delete a workflow
198
+
199
+ **Discover available integrations (pieces):**
200
+
201
+ - `imbrace workflow piece list --json` — List all 126 integrations (Slack, Gmail, OpenAI, ...)
202
+ - `imbrace workflow piece list --search slack --json` — Search integrations
203
+ - `imbrace workflow piece detail <pieceName> --json` — Get full schema (actions, triggers, input fields)
204
+
205
+ **Build node tree:**
206
+
207
+ - `imbrace workflow node list <flowId> --json` — Show the trigger + action chain
208
+ - `imbrace workflow node add <flowId> --type trigger --piece <name> --trigger-name <id> --input '{...}' --json` — Add trigger
209
+ - `imbrace workflow node add <flowId> --type action --piece <name> --action-name <id> --after <parent> --input '{...}' --json` — Add action
210
+ - `imbrace workflow node update <flowId> <nodeName> --input '{...}' --json` — Update node input
211
+ - `imbrace workflow node delete <flowId> <nodeName> --yes --json` — Remove a node
212
+ - `imbrace workflow node add-raw <flowId> --op-file <path>` — Apply raw flow operation. Use for advanced node types (`ROUTER`, `LOOP_ON_ITEMS`, `CODE`) that `node add` doesn't expose. Body shape: `{ type: "ADD_ACTION" \| "UPDATE_ACTION" \| "UPDATE_TRIGGER" \| "DELETE_ACTION", request: {...} }`. Also accepts `--op '<inline JSON>'` or `--stdin`.
213
+
214
+ **Run history:**
215
+
216
+ - `imbrace workflow runs --json` — List recent runs
217
+ - `imbrace workflow run-detail <runId> --json` — Get run details (status, failed step, logs)
218
+
219
+ **Connections (OAuth / API keys for external services):**
220
+
221
+ - `imbrace workflow conn list --json` — List saved connections
222
+ - `imbrace workflow conn get <connId> --json` — Get details of a single connection
223
+ - `imbrace workflow conn create --piece <name> --type <T> --value "<token>" --json` — Save credential. `--type`: `SECRET_TEXT` | `OAUTH2` | `CLOUD_OAUTH2` | `BASIC_AUTH` | `CUSTOM_AUTH`
224
+ - `imbrace workflow conn delete <connId> --yes` — Delete a connection
225
+
226
+ **Folders (organize flows — UI calls them "Categories"):**
227
+
228
+ - `imbrace workflow folder list --json` — List all folders
229
+ - `imbrace workflow folder get <folderId> --json` — Folder details
230
+ - `imbrace workflow folder create --name "Sales" --json` — Create (auto-resolves projectId)
231
+ - `imbrace workflow folder update <folderId> --name "Renamed" --json` — Rename
232
+ - `imbrace workflow folder delete <folderId> --yes` — Delete (flows inside become unfiled, NOT deleted)
233
+
234
+ The platform auto-creates 4 system folders that show up as Categories in the UI. Use `workflow folder list` to discover their IDs:
235
+
236
+ | UI Category | Backend folder name | Purpose |
237
+ |---|---|---|
238
+ | `Channel Workflow` | `Channel Workflow` | Messaging / channel automation |
239
+ | `Board Automation` | `Board Automation` | Triggered by data-board events; flows usually use the `automate-data-board` action with a `boardId` |
240
+ | `AI Agent Skills` | `AI Agent Capabilities` | Skills callable by AI agents |
241
+ | `Others` | `Others` | Default catch-all |
242
+
243
+ To make a flow appear in a UI Category, place it in the matching system folder via `workflow create --folder-id <id>` or `workflow move <flowId> --folder-id <id>`. Flows created with no folder land in "All flows" only (not in any Category).
244
+
245
+ **MCP servers (Model Context Protocol — let AI agents call piece tools):**
246
+
247
+ - `imbrace workflow mcp list --json` — List MCP servers for the project
248
+ - `imbrace workflow mcp get <mcpId> --json` — Server details (token NOT shown for security)
249
+ - `imbrace workflow mcp create --name "My MCP" --json` — Create. **Token is shown once at creation — save it immediately.**
250
+ - `imbrace workflow mcp rotate-token <mcpId> --yes` — Issue a new token. Old token stops working immediately.
251
+ - `imbrace workflow mcp delete <mcpId> --yes` — Delete the server
252
+
253
+ **Lifecycle:**
254
+
255
+ - `imbrace workflow publish <flowId>` — Lock current draft as published version (REQUIRED before enable)
256
+ - `imbrace workflow enable <flowId>` — Enable auto-trigger
257
+ - `imbrace workflow disable <flowId>` — Stop auto-trigger (keeps published version)
258
+
259
+ **Trigger flow manually:**
260
+
261
+ - `imbrace workflow run <flowId> --payload '{...}' --json` — Trigger async (fire-and-forget)
262
+ - `imbrace workflow run <flowId> --payload '{...}' --sync --json` — Trigger and wait. ⚠️ Sync polling may time out at ~30s even when the run finishes faster — fall back to `imbrace workflow runs` + `run-detail <runId>` to verify.
263
+
264
+ **Order matters:** create flow → add nodes → **publish** → **enable** → run. Trying to `enable` before `publish` returns 500 "publishedFlowVersionId is required".
265
+
266
+ ### Workflow flags
267
+
268
+ **Flow-level:**
269
+ - `--name` / `-n` — Workflow display name (required for create)
270
+ - `--folder-id` — Folder to place flow in
271
+ - `--yes` / `-y` — Skip confirmation on delete
272
+ - `--json` — Machine-readable output
273
+
274
+ **Node-level:**
275
+ - `--type` — `trigger` or `action`
276
+ - `--piece` — Piece name (e.g. `@activepieces/piece-slack`)
277
+ - `--trigger-name` — Trigger identifier from piece (when `--type trigger`)
278
+ - `--action-name` — Action identifier from piece (when `--type action`)
279
+ - `--after` — Place node after this step name (default: append at end)
280
+ - `--input` — JSON string with field values (use `{{trigger.X}}` or `{{step_N.output.Y}}` for variables)
281
+ - `--connection` — Connection ID to authenticate the piece
282
+
283
+ **Run flags:**
284
+ - `--payload` — JSON payload to send (becomes `trigger.body` in flow)
285
+ - `--sync` — Wait for flow to finish (timeout 60s); without it, fire-and-forget
286
+ - `--limit` — Max runs to list (default 10)
287
+
288
+ ### How Workflow create works (under the hood)
289
+
290
+ `imbrace workflow create` calls `client.activepieces.createFlow({ displayName, projectId })`. The route auto-discovers `projectId` from existing flows so the user doesn't pass it.
291
+
292
+ Adding/editing nodes calls `client.activepieces.applyFlowOperation(flowId, { type, request })` with operation types:
293
+ - `UPDATE_TRIGGER` — replace trigger node
294
+ - `ADD_ACTION` — add an action after a parent step
295
+ - `UPDATE_ACTION` — change input of an existing action
296
+ - `DELETE_ACTION` — remove a node and re-link parent → child
297
+ - `LOCK_AND_PUBLISH` — finalize current version (used by `workflow publish`)
298
+ - `CHANGE_STATUS` — toggle ENABLED/DISABLED (used by `workflow enable/disable`)
299
+
300
+ Piece schemas (`piece detail`) come from a raw `GET /activepieces/v1/pieces/<pieceName>` because SDK's `listPieces()` only returns counts (`actions: 25`, `triggers: 12`), not field schemas.
301
+
302
+ ### Flow JSON anatomy
303
+
304
+ A workflow stores its node tree under `version.trigger`, with `nextAction` linking the chain:
305
+
306
+ ```ts
307
+ {
308
+ id: "06oWoBQpL...",
309
+ status: "ENABLED" | "DISABLED",
310
+ version: {
311
+ displayName: "My Flow",
312
+ trigger: {
313
+ name: "trigger",
314
+ type: "PIECE_TRIGGER", // or BRANCH, LOOP_ON_ITEMS, CODE
315
+ settings: { pieceName, triggerName, input },
316
+ nextAction: {
317
+ name: "step_1",
318
+ type: "PIECE",
319
+ settings: { pieceName, actionName, input },
320
+ nextAction: { name: "step_2", ... }
321
+ }
322
+ }
323
+ }
324
+ }
325
+ ```
326
+
327
+ ### Variable syntax inside node `input`
328
+
329
+ - `{{trigger.body.X}}` — field X from trigger payload
330
+ - `{{trigger.X}}` — top-level trigger field (for piece triggers)
331
+ - `{{step_1.output.Y}}` — output field Y from step_1
332
+ - `{{connections.<connId>.access_token}}` — connection field
333
+
334
+ ### Workflow anatomy — 6 layers
335
+
336
+ ```
337
+ Project
338
+ └─ Flow (container — id, name, status: ENABLED/DISABLED)
339
+ └─ Version (snapshot — DRAFT or LOCKED, contains the node tree)
340
+ └─ Nodes (cây trigger + actions, linked via nextAction)
341
+ ├─ trigger (always 1, type PIECE_TRIGGER or EMPTY)
342
+ └─ step_1, step_2, ... (0..N actions)
343
+ └─ Runs (execution history — status, logs per run)
344
+
345
+ Cross-flow shared:
346
+ ├─ Connections (OAuth / API keys, reused across flows)
347
+ └─ Pieces (catalog of 126 integrations: Slack, Gmail, OpenAI, ...)
348
+ ```
349
+
350
+ ### Node types
351
+
352
+ A node's `type` field determines its role in the flow:
353
+
354
+ | Type | Role | CLI support |
355
+ |---|---|---|
356
+ | `PIECE_TRIGGER` | "When does the flow run" — Slack message, webhook, cron, ... | ✅ `node add --type trigger` |
357
+ | `PIECE` | "What runs after" — send Slack, ask AI, HTTP request, ... | ✅ `node add --type action` |
358
+ | `EMPTY` | Placeholder before a real trigger is set (default after `workflow create`) | ✅ Read-only |
359
+ | `ROUTER` | Multi-condition switch (replaces legacy BRANCH) | ✅ `node add-raw` |
360
+ | `LOOP_ON_ITEMS` | Loop over an array | ✅ `node add-raw` |
361
+ | `CODE` | Inline JavaScript | ✅ `node add-raw` |
362
+
363
+ Most flows use only `PIECE_TRIGGER` + `PIECE`. For the other 3 types use `node add-raw` with a full Activepieces operation payload — see shapes below.
364
+
365
+ **Constraints when composing advanced nodes:**
366
+ 1. `LOOP_ON_ITEMS` and `CODE` must have a `parentStep` of type `trigger` or `PIECE`. Setting parent to a `ROUTER` (or another LOOP) returns 400 `Router step parent undefined not found`. To put a LOOP/CODE inside a router branch, build the inner action as part of the ROUTER's `children` array, not as a separate ADD_ACTION.
367
+ 2. `node list` only walks the linear `trigger → nextAction → nextAction` chain. Children of `ROUTER` (in `children: []`) and the body of `LOOP_ON_ITEMS` (in `firstLoopAction`) are stored server-side but not displayed by the flat list. Use `workflow get <flowId> --json` to see the full nested tree.
368
+
369
+ **Gotchas when updating live flows:**
370
+ - **Flow lock** — if the user has the flow open in their browser, CLI updates may be rejected with `"edited at the last minute, try again later"` or silently overwritten when the UI auto-saves. Ask the user to close the flow editor tab before bulk-updating via CLI; verify with `workflow get --json` that your changes stuck.
371
+ - **AI Connector `assistant-request` prompt field** — the `prompt` input is a NESTED object, not a plain string. The UI form binds to `input.prompt.prompt`. Plain string values like `input.prompt = "text"` are accepted by the API but the UI renders the field as empty. Always send `{ "prompt": { "prompt": "actual text" } }`. The separate `custom_instructions` field IS a plain string and maps to the UI's "Custom Instructions" section.
372
+
373
+ ### Raw operation shapes for advanced nodes
374
+
375
+ For `ROUTER`, `LOOP_ON_ITEMS`, `CODE` use `imbrace workflow node add-raw <flowId> --op-file <path>`. The op file contains `{ type, request }` — the full Activepieces flow-operation body. Examples:
376
+
377
+ **ROUTER** — multi-condition switch:
378
+ ```json
379
+ {
380
+ "type": "ADD_ACTION",
381
+ "request": {
382
+ "parentStep": "trigger",
383
+ "action": {
384
+ "name": "step_1",
385
+ "type": "ROUTER",
386
+ "displayName": "Check priority",
387
+ "settings": {
388
+ "branches": [
389
+ {
390
+ "branchName": "High",
391
+ "branchType": "CONDITION",
392
+ "conditions": [[{
393
+ "operator": "TEXT_EXACTLY_MATCHES",
394
+ "firstValue": "{{trigger.body.priority}}",
395
+ "secondValue": "high",
396
+ "caseSensitive": false
397
+ }]]
398
+ },
399
+ { "branchName": "Default", "branchType": "FALLBACK" }
400
+ ],
401
+ "executionType": "EXECUTE_FIRST_MATCH",
402
+ "sampleData": {}
403
+ },
404
+ "children": [null, null],
405
+ "valid": true
406
+ }
407
+ }
408
+ }
409
+ ```
410
+
411
+ **LOOP_ON_ITEMS** — loop over an array. `parentStep` must be a `trigger` or `PIECE` (not a ROUTER):
412
+ ```json
413
+ {
414
+ "type": "ADD_ACTION",
415
+ "request": {
416
+ "parentStep": "trigger",
417
+ "action": {
418
+ "name": "step_1",
419
+ "type": "LOOP_ON_ITEMS",
420
+ "displayName": "Loop users",
421
+ "settings": { "items": "{{trigger.body.users}}" },
422
+ "firstLoopAction": null,
423
+ "valid": true
424
+ }
425
+ }
426
+ }
427
+ ```
428
+
429
+ **CODE** — inline JavaScript:
430
+ ```json
431
+ {
432
+ "type": "ADD_ACTION",
433
+ "request": {
434
+ "parentStep": "step_1",
435
+ "action": {
436
+ "name": "step_2",
437
+ "type": "CODE",
438
+ "displayName": "Transform",
439
+ "settings": {
440
+ "input": { "x": "{{trigger.body.value}}" },
441
+ "sourceCode": {
442
+ "code": "export const code = async (inputs) => ({ doubled: inputs.x * 2 });",
443
+ "packageJson": "{\"dependencies\":{}}"
444
+ }
445
+ },
446
+ "valid": true
447
+ }
448
+ }
449
+ }
450
+ ```
451
+
452
+ **Common operation types** for `add-raw`:
453
+ - `ADD_ACTION` — add a new node (with `parentStep` + `action` shape above)
454
+ - `UPDATE_ACTION` — replace an existing node's settings (request: `{ name, type, displayName, settings, valid }`)
455
+ - `UPDATE_TRIGGER` — replace the trigger node
456
+ - `DELETE_ACTION` — remove a node (request: `{ names: ["step_X"] }`)
457
+
458
+ ### Connection types
459
+
460
+ When calling `workflow conn create --type <X>` (Sprint 3), valid types are:
461
+
462
+ | Type | Use case |
463
+ |---|---|
464
+ | `SECRET_TEXT` | Simple API key (Slack bot token, OpenAI key) |
465
+ | `OAUTH2` | OAuth flow with custom app (Google, Slack OAuth) |
466
+ | `CLOUD_OAUTH2` | OAuth via Activepieces hosted apps (no custom app setup needed) |
467
+ | `BASIC_AUTH` | username + password |
468
+ | `CUSTOM_AUTH` | Custom format defined by the piece |
469
+
470
+ Use `imbrace workflow piece detail <pieceName>` to see which auth type a piece accepts.
471
+
472
+ ### Workflow lifecycle
473
+
474
+ ```
475
+ DRAFT (editing) → publish → LOCKED (production) → enable → ENABLED (auto-running)
476
+
477
+ disable (back to DISABLED but still LOCKED)
478
+ ```
479
+
480
+ - `workflow publish` locks the current draft version and marks it as the production version.
481
+ - `workflow enable` turns on auto-trigger — fires the flow whenever its trigger condition is met.
482
+ - `workflow disable` stops auto-trigger but keeps the published version intact.
483
+ - Edit after publish: backend creates a new DRAFT version; previous LOCKED version keeps running until you publish the new draft.
484
+
485
+ ## Setup
486
+
487
+ ```bash
488
+ # 1. Start the API
489
+ cd api && bun install && bun run dev
490
+
491
+ # 2. Install the CLI (one-shot — handles build, link, and cross-shell PATH)
492
+ cd .. && ./install.sh
493
+
494
+ # 3. Login
495
+ imbrace login --api-key api_xxx...
496
+
497
+ # 4. Verify
498
+ imbrace whoami --json
499
+ ```
500
+
501
+ The `install.sh` script symlinks `imbrace` into `/opt/homebrew/bin` (Apple Silicon) or `/usr/local/bin` so the command works even from shells that don't load nvm — for example conda's `(base)` env.
502
+
503
+ ## Quick Start for Coding Agents
504
+
505
+ ### Data Board
506
+ ```bash
507
+ # Get available boards
508
+ imbrace data-board list --json
509
+
510
+ # Create a board
511
+ imbrace data-board create --name "Leads" --json
512
+
513
+ # Add a field
514
+ imbrace data-board create-field <boardId> --name "Company" --type ShortText --json
515
+
516
+ # Add a record (Name field is required — use its field ID)
517
+ imbrace data-board create-item <boardId> --fields '[{"board_field_id":"<nameFieldId>","value":"John Doe"},{"board_field_id":"<fieldId>","value":"Acme Corp"}]' --json
518
+
519
+ # List records
520
+ imbrace data-board list-items --board-id <boardId> --json
521
+
522
+ # Export to CSV
523
+ imbrace data-board export-csv --board-id <boardId> --out ./leads.csv
524
+ ```
525
+
526
+ ### AI Agent
527
+ ```bash
528
+ # Discover what's available
529
+ imbrace ai-agent list --json
530
+ imbrace ai-agent list-providers --json
531
+ imbrace ai-agent list-models --provider-id system --json
532
+ imbrace ai-agent list-folders --json
533
+
534
+ # Create an agent (minimal)
535
+ imbrace ai-agent create --name "Sales Bot" --instructions "You are a sales assistant" --json
536
+
537
+ # Create with custom provider + Knowledge Hub folder
538
+ imbrace ai-agent create --name "RAG Bot" \
539
+ --instructions "Answer using the provided knowledge" \
540
+ --provider-id e2629292-7e9f-4d55-ba18-6827747eab33 \
541
+ --model gpt-4o-mini \
542
+ --folder-ids 69bb82faa2cc764639bc6bdb \
543
+ --json
544
+
545
+ # Update — partial (other fields preserved)
546
+ imbrace ai-agent update <agentId> --instructions "Updated" --temperature 0.7 --json
547
+
548
+ # Delete
549
+ imbrace ai-agent delete <agentId> --yes --json
550
+ ```
551
+
552
+ ### Workflow — build a Slack auto-reply bot end-to-end
553
+
554
+ **Note:** Steps 1, 3, 4, 5, 6, 7 use Sprint 1+2 commands (already implemented).
555
+ Steps 2, 8, 9 use Sprint 3 commands (**not yet implemented** — for now, do them via the [UI builder](https://cloud.imbrace.co/workflow-v2)).
556
+
557
+ ```bash
558
+ # 1. Discover Slack + AI integrations (schemas) ✅ Sprint 2
559
+ imbrace workflow piece list --search slack --json
560
+ imbrace workflow piece detail @activepieces/piece-slack --json
561
+ imbrace workflow piece detail @activepieces/piece-ai-connector --json
562
+
563
+ # 2. Save Slack token (one-time per workspace) ✅ Sprint 3
564
+ imbrace workflow conn create \
565
+ --piece @activepieces/piece-slack \
566
+ --type SECRET_TEXT \
567
+ --value "xoxb-actual-token" \
568
+ --json
569
+ # → note conn._id
570
+
571
+ # 3. Create empty flow ✅ Sprint 1
572
+ imbrace workflow create --name "Slack AI Reply Bot" --json
573
+ # → note flow._id
574
+
575
+ # 4. Add Slack trigger (catch new messages) ✅ Sprint 2
576
+ imbrace workflow node add <flowId> \
577
+ --type trigger \
578
+ --piece @activepieces/piece-slack \
579
+ --trigger-name new_message_in_channel \
580
+ --connection <connId> \
581
+ --input '{"channel":"C0XXXXX"}' \
582
+ --json
583
+
584
+ # 5. Add AI action (draft a reply) ✅ Sprint 2
585
+ imbrace workflow node add <flowId> \
586
+ --type action \
587
+ --piece @activepieces/piece-ai-connector \
588
+ --action-name ask \
589
+ --after trigger \
590
+ --input '{"modelName":"gpt-4o","prompt":"Draft a friendly reply to: {{trigger.text}}"}' \
591
+ --json
592
+
593
+ # 6. Add Slack reply (post answer back to thread) ✅ Sprint 2
594
+ imbrace workflow node add <flowId> \
595
+ --type action \
596
+ --piece @activepieces/piece-slack \
597
+ --action-name send_channel_message \
598
+ --after step_1 \
599
+ --connection <connId> \
600
+ --input '{"channel":"{{trigger.channel}}","text":"{{step_1.output.text}}","thread_ts":"{{trigger.ts}}"}' \
601
+ --json
602
+
603
+ # 7. Verify the node tree ✅ Sprint 2
604
+ imbrace workflow node list <flowId> --json
605
+
606
+ # 8. Test run with sample payload ✅ Sprint 3
607
+ # --sync may time out (~30s) even if the run finishes faster.
608
+ # If it times out, use 'workflow runs' + 'run-detail' to fetch the result.
609
+ imbrace workflow run <flowId> --sync \
610
+ --payload '{"text":"How do I reset my password?","channel":"C0XXXXX","ts":"1234.5"}' \
611
+ --json
612
+
613
+ # 9. Publish & enable so it runs automatically ✅ Sprint 3
614
+ imbrace workflow publish <flowId> --json
615
+ imbrace workflow enable <flowId> --json
616
+ ```
617
+
618
+ ## Adding a New Service
619
+
620
+ To add a new service (e.g. `workflow`):
621
+
622
+ 1. Create route in `api/src/routes/workflow.ts`
623
+ 2. Mount in `api/src/index.ts` with `authMiddleware`
624
+ 3. Create CLI commands in `cli/src/commands/workflow/`
625
+ 4. Add topic in `cli/package.json` under `oclif.topics`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@imbrace/cli",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "type": "module",
5
5
  "description": "CLI tool for interacting with the Imbrace CRM platform from the terminal",
6
6
  "repository": {
@@ -75,6 +75,7 @@
75
75
  },
76
76
  "files": [
77
77
  "/bin",
78
- "/dist"
78
+ "/dist",
79
+ "/llms.txt"
79
80
  ]
80
81
  }