@controllerai/cli 0.2.8 → 0.2.10

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.
Files changed (53) hide show
  1. package/dist/api/client.js +20 -5
  2. package/dist/api/client.js.map +1 -1
  3. package/dist/argv.js +330 -29
  4. package/dist/argv.js.map +1 -1
  5. package/dist/commands/agent.js +247 -26
  6. package/dist/commands/agent.js.map +1 -1
  7. package/dist/commands/auth.js +21 -5
  8. package/dist/commands/auth.js.map +1 -1
  9. package/dist/commands/doctor.js +63 -4
  10. package/dist/commands/doctor.js.map +1 -1
  11. package/dist/commands/exec.js +161 -49
  12. package/dist/commands/exec.js.map +1 -1
  13. package/dist/commands/expr.js +284 -53
  14. package/dist/commands/expr.js.map +1 -1
  15. package/dist/commands/flow.js +58 -14
  16. package/dist/commands/flow.js.map +1 -1
  17. package/dist/commands/node.js +746 -173
  18. package/dist/commands/node.js.map +1 -1
  19. package/dist/commands/organize.js +1 -1
  20. package/dist/commands/organize.js.map +1 -1
  21. package/dist/commands/run.js +165 -33
  22. package/dist/commands/run.js.map +1 -1
  23. package/dist/commands/schema.js +8 -7
  24. package/dist/commands/schema.js.map +1 -1
  25. package/dist/commands/workflow.js +151 -24
  26. package/dist/commands/workflow.js.map +1 -1
  27. package/dist/config.js +152 -6
  28. package/dist/config.js.map +1 -1
  29. package/dist/context.js +66 -5
  30. package/dist/context.js.map +1 -1
  31. package/dist/index.js +11 -1
  32. package/dist/index.js.map +1 -1
  33. package/dist/nodeProps.js +333 -10
  34. package/dist/nodeProps.js.map +1 -1
  35. package/dist/output.js +6 -1
  36. package/dist/output.js.map +1 -1
  37. package/dist/permissionTool.js +93 -0
  38. package/dist/permissionTool.js.map +1 -0
  39. package/package.json +1 -1
  40. package/skills/controllerai-agents/SKILL.md +27 -9
  41. package/skills/controllerai-agents/references/instructions-and-versioning.md +1 -1
  42. package/skills/controllerai-data/SKILL.md +19 -0
  43. package/skills/controllerai-data/references/data-rails.md +1 -1
  44. package/skills/controllerai-expressions/SKILL.md +8 -2
  45. package/skills/controllerai-flow-control/SKILL.md +2 -0
  46. package/skills/controllerai-node-config/SKILL.md +33 -6
  47. package/skills/controllerai-node-config/references/prop-and-readiness.md +34 -0
  48. package/skills/controllerai-runs/SKILL.md +16 -4
  49. package/skills/controllerai-runs/references/debugging.md +1 -1
  50. package/skills/controllerai-start/SKILL.md +1 -0
  51. package/skills/controllerai-workflows/SKILL.md +13 -8
  52. package/skills/controllerai-workflows/references/command-map.md +3 -2
  53. package/skills/manifest.json +58 -58
@@ -45,6 +45,7 @@ cai run flow <flowId> --inputs values.json --json
45
45
  ```
46
46
 
47
47
  Capture the successful workflow execution ID. Workflow inputs become tool parameters and outputs become its result.
48
+ Before attaching a workflow tool, require a nonempty output contract and verify that the completed run returns it; otherwise the agent receives an empty result.
48
49
 
49
50
  ## 3. Create and assemble the draft
50
51
 
@@ -68,11 +69,16 @@ cai agent add-workflow <agentId> \
68
69
  --description "Use when ...; accepts ...; returns ..." \
69
70
  --json
70
71
 
71
- cai agent add-file <agentId> --file <path> --json
72
+ cai agent add-file <agentId> --file <path> --space knowledge --json
73
+ cai agent add-file <agentId> --file <path> --space shared --json
74
+ cai agent files <agentId> --space knowledge --json
75
+ cai agent files <agentId> --space shared --live --json
72
76
  cai agent tools <agentId> --json
73
77
  cai agent get <agentId> --json
74
78
  ```
75
79
 
80
+ Use `cai agent files <agentId> [--space <knowledge|shared>] [--live]` to read file inventories. Adding with `--space shared` updates the live runtime file space immediately without publishing; an active agent sees it on the next turn, while a disabled agent sees it after enablement.
81
+
76
82
  Permission is part of agent design, not an afterthought. For every tool, settle the approval level WITH the user before attaching: present the tool list and ask which steps they want a human in the loop for ("should sending the email require your approval each time, or run automatically?"). The default is no approval. Add `--require-confirmation` for consequential writes, deletion, external communications, permission changes, purchases/spend, or an ambiguous destination; `cai agent update-tool` changes it later. Omitting the flag must be the user's informed autonomy decision, not an unnoticed default.
77
83
 
78
84
  Keep the two modes straight:
@@ -89,9 +95,19 @@ Publishing the agent snapshots its display name, instructions, tool identities,
89
95
 
90
96
  Publishing is a hard cutover: live conversations that are mid-turn are interrupted immediately (the person's in-flight answer never arrives), their unexecuted approval requests expire, and each conversation reopens on its own next message running the new version. Time publishes with that in mind and tell the user what a publish does to active conversations.
91
97
 
98
+ Runtime lifecycle changes do not require publishing:
99
+
100
+ ```bash
101
+ cai agent update <agentId> --disabled --json
102
+ cai agent update <agentId> --enabled --json
103
+ cai agent delete <agentId> --confirm --json
104
+ ```
105
+
106
+ Disable pauses runtime immediately; enable resumes it immediately. Delete is soft: it revokes live access, requests best-effort termination of active sessions and pending approvals, retains conversation history but makes it inaccessible, has no CLI restore, and does not guard dependent workflows, which can fail later.
107
+
92
108
  ## Runtime usage boundary
93
109
 
94
- The user's local Codex, Claude, or other coding-agent subscription can cover builder reasoning. Hosted agent tests and conversations consume Controller AI runtime usage from the organization's shared pool. Connected providers may add charges or side effects. State this before starting a hosted test or describing this route as free.
110
+ The user's coding-agent subscription covers builder reasoning, but hosted agent tests and conversations consume Controller AI runtime usage from the organization's pool, and connected providers may add charges or side effects. Say so before starting a hosted test or calling this route free.
95
111
 
96
112
  ## 4. Verify the draft as an agent
97
113
 
@@ -104,7 +120,7 @@ cai agent conversation history <conversationId> --json
104
120
 
105
121
  Test requests that should and should not select each tool. Verify exact arguments, truthful use of results, errors, and knowledge behavior.
106
122
 
107
- The user can also test the draft themselves in the product — offer them the agent's page in the app so they can try it hands-on before publishing (`cai agent create`/`publish`/`test` outputs include `appUrl` links to the agent and conversation pages when the app origin is known). Their impression of the conversation matters more than your transcript reading.
123
+ Also offer the user the agent's app page to try the draft hands-on before publishing (`create`/`publish`/`test` outputs include `appUrl` links when the app origin is known). Their impression outweighs your transcript reading.
108
124
 
109
125
  - For a workflow tool, correlate a side-effectful call with its terminal workflow execution ID.
110
126
  - For a direct integration action, inspect persisted conversation action events/run result and the intended external effect. Direct actions do not create workflow execution IDs.
@@ -112,11 +128,13 @@ The user can also test the draft themselves in the product — offer them the ag
112
128
  For pending approval, inspect the exact request before choosing:
113
129
 
114
130
  ```bash
115
- cai agent conversation approve <conversationId> --request <requestId> --tool <toolName> --json
116
- cai agent conversation deny <conversationId> --request <requestId> --tool <toolName> --message "<reason>" --json
131
+ cai agent conversation approve <conversationId> --request <requestId> --json
132
+ cai agent conversation deny <conversationId> --request <requestId> --message "<reason>" --json
117
133
  ```
118
134
 
119
- Do not approve merely to make a test continue.
135
+ The server resolves the tool from the permission request; do not pass a human-readable tool name. Do not approve merely to make a test continue.
136
+
137
+ After `cai agent remove-tool`, test both a request that must no longer use the removed capability and a representative retained capability.
120
138
 
121
139
  ## 5. Publish in dependency order
122
140
 
@@ -153,16 +171,16 @@ Draft evidence does not prove the live agent. Test is owner-only. Shared users a
153
171
 
154
172
  ## 6. Offer Slack and organization sharing
155
173
 
156
- After a successful publish, offer the next steps rather than waiting to be asked:
174
+ After a successful publish, offer the next steps unprompted:
157
175
 
158
- - **Slack**: if the user wants to talk to the agent in Slack, that requires the Slack ↔ Controller AI connection plus per-agent Slack configuration (agent slug, channel) — both set up in the product, not the CLI. Point the user to the relevant product page and offer to walk them through it.
176
+ - **Slack**: talking to the agent in Slack needs the Slack ↔ Controller AI connection plus per-agent Slack configuration (slug, channel), both set up in the product, not the CLI — point the user there and offer to walk them through it.
159
177
  - **Sharing**: agents remain private unless the user explicitly asks for organization access:
160
178
 
161
179
  ```bash
162
180
  cai agent visibility <agentId> --value organization --json
163
181
  ```
164
182
 
165
- Organization members use the published version. Direct actions run through the agent owner's connected external account, while Controller AI usage comes from the organization's shared pool. Rebinding, revoking, or detaching that live grant can immediately affect published agents. Return to private visibility to revoke organization access.
183
+ Organization members use the published version. Direct actions run through the owner's connected external account; usage comes from the organization's pool. Rebinding or revoking that live grant immediately affects published agents. Return to private visibility to revoke access.
166
184
 
167
185
  ## Final report
168
186
 
@@ -66,7 +66,7 @@ Do not republish the agent merely to make a followed workflow's new live release
66
66
 
67
67
  | Layer | Evidence |
68
68
  | --- | --- |
69
- | Workflow tool | Completed development `cai run flow` execution |
69
+ | Workflow tool | Completed development `cai run flow` execution; an intentional `cai run flow <flowId> --target live --confirm-live` execution is stronger evidence of published behavior than a draft-agent proxy |
70
70
  | Direct action | Persisted conversation action/run events, returned result, and intended external effect |
71
71
  | Draft routing | Draft conversation chooses the correct tool and arguments |
72
72
  | Published workflow | `workflow status` reports the intended live release and active state |
@@ -79,6 +79,8 @@ cai data fields --type custom.customer --json
79
79
 
80
80
  Never feed a queried record directly into a write. Build a new fields object keyed by the `writeKey` mapping and omit reserved `id`, `createdAt`, and `updatedAt`.
81
81
 
82
+ Fields may be typed `date`. Their values are strict ISO-8601 strings (`"2026-06-05"` or `"2026-06-05T12:30:00Z"`) on both write and read; anything else is rejected. Reserved `createdAt`/`updatedAt` are currently `text` — use `.toDate()` before date operations on them.
83
+
82
84
  ## Work on the correct rail
83
85
 
84
86
  Development is the default:
@@ -93,6 +95,23 @@ Use `--env live` only when the user intends to inspect or mutate production stat
93
95
 
94
96
  `data query --query` is plain-text search over serialized records and metadata, not a field predicate. Perform exact field filtering inside workflow expressions or inspect results explicitly.
95
97
 
98
+ ## Delete records explicitly
99
+
100
+ Record deletion is CLI/REST-only; no workflow data node exposes it. Delete one known record or an explicit set of IDs:
101
+
102
+ ```bash
103
+ cai data delete <recordId> --type custom.customer --env dev --json
104
+ cai data delete-many --type custom.customer --records <id1,id2> --env dev --json
105
+ ```
106
+
107
+ Delete every record in a collection only with explicit user intent; `--all` also requires `--yes`:
108
+
109
+ ```bash
110
+ cai data delete-many --type custom.customer --all --yes --env dev --json
111
+ ```
112
+
113
+ The default rail is development. Use `--env live` only for an intentional production deletion, then query that same rail to verify the result.
114
+
96
115
  ## Import and promote
97
116
 
98
117
  Validate CSV before writing:
@@ -25,7 +25,7 @@ Field IDs are contracts. Prefer keeping an ID stable and changing only its displ
25
25
  ## Destructive operations
26
26
 
27
27
  - `data delete` soft-deletes one record.
28
- - `data delete-many --all` is broad and development-only through its REST route.
28
+ - `data delete-many --all --yes` is broad, REST-backed, and DEVELOPMENT-ONLY — `--env live` is refused (`DEV_ONLY_ROUTE`). The only live write paths are single-record `data create/update/delete --env live` and `copy-to-live`.
29
29
  - `schema delete` removes access to the whole collection and breaks its type references.
30
30
  - CSV `--mode commit` appends rows.
31
31
  - `copy-to-live` changes production data.
@@ -46,6 +46,8 @@ Copy binding and field names exactly. Important sources include:
46
46
 
47
47
  Do not derive a binding from a display label. Context flags duplicate display names and supplies the de-duplicated JS name, input ID, and source node.
48
48
 
49
+ When compilation reports an unknown field, copy a typeable display-derived accessor it advertises; field IDs appear second for disambiguation.
50
+
49
51
  ### 3. Use only advertised syntax
50
52
 
51
53
  Get the current operation catalog when needed:
@@ -56,9 +58,11 @@ cai expr ops --type <text|number|date|list|boolean|file|custom> --json
56
58
 
57
59
  Keep the program to optional `const` declarations followed by one final expression. Do not use loops, assignments, `new`, regular expressions, optional chaining, arbitrary library methods, or object construction unless the current compiler catalog explicitly supports them.
58
60
 
61
+ Date values are ISO-8601 strings on the wire (`"2026-06-05"` or `"2026-06-05T12:30:00Z"`). A `date`-typed flow input or field is used directly with date operations; only `text` values need `.toDate()` first. For epoch text, pass the unit literal explicitly: `flow.timestamp.toDate("epoch_seconds")` or `flow.timestamp.toDate("epoch_millis")`. The ops table renders that argument generically; never guess the unit from digit count.
62
+
59
63
  Read [references/dsl-and-recipes.md](references/dsl-and-recipes.md) for canonical patterns.
60
64
 
61
- ### 4. Compile, write, and read back atomically
65
+ ### 4. Compile, write, and read back
62
66
 
63
67
  For a node prop, prefer:
64
68
 
@@ -72,7 +76,9 @@ For multiline expressions or shell-sensitive templates, put the exact source in
72
76
  cai expr set <nodeId> --prop <propName> --js-file expression.js --json
73
77
  ```
74
78
 
75
- This fetches target metadata, compiles without writing on failure, chooses `valueJs` versus `expressionValueJs`, persists, and verifies read-back.
79
+ This fetches target metadata, auto-enables a catalog-only optional target when needed, compiles before writing the value, persists to the correct channel, and verifies read-back. If validation or the value write then fails, the prop stays enabled; repair with `cai node disable-prop <nodeId> --prop <propName>`.
80
+
81
+ Array channels are not interchangeable. On a value-channel `SHORT_TEXT_ARRAY`, a scalar expression replaces the whole array with one dynamic element; it does not append. List-typed expressions on value-channel array props are rejected. Use `cai node set <nodeId> --prop <propName> --value '["a","b"]'` for a static list, or use a list-typed expression only where prop metadata exposes whole-array expression mode.
76
82
 
77
83
  For a side-effect-free check:
78
84
 
@@ -103,6 +103,8 @@ Inside loop mappings, `item` exists only where context exposes it. Inside the bo
103
103
 
104
104
  Loops run sequentially. `--continue-on-error` applies to a failed child iteration; a list expression or mapping/config expression that fails before the child starts still aborts the loop. Test empty, one-item, several-item, over-limit, and intended iteration-error behavior.
105
105
 
106
+ Never enable continue-on-error on a money path; charges, purchases, transfers, refunds, and other spend must fail fast.
107
+
106
108
  ## Subflows and convergence
107
109
 
108
110
  Define the called flow's inputs and outputs first. Then initialize a Run flow component and bind it:
@@ -63,6 +63,8 @@ cai node status <nodeId> --json
63
63
  cai node props <nodeId> --json
64
64
  ```
65
65
 
66
+ For option-backed props, `node props` and write readback may report `optionsAvailability`: `available`, `blocked_upstream` with `blockedBy`, or `dynamic_upstream`. It is positional: earlier single `DROPDOWN` selectors gate later options. Older backends, and responses without a dependency catalog, may omit it; treat absence as unknown, not available.
67
+
66
68
  Work through blockers in this order:
67
69
 
68
70
  1. Missing connection
@@ -73,7 +75,9 @@ Work through blockers in this order:
73
75
  6. Expressions
74
76
  7. Unresolved output type
75
77
 
76
- Re-run `node props` after every reload selector or connection change. Dynamic props can appear, disappear, or reset.
78
+ Follow `next`. When a disabled required prop has an activating selector, its blocker names that selector; when it is the next blocker, `next` gives the exact `cai node set` command. `dynamicSelectorNotes` is non-blocking: a node may read ready while its dynamic selector's dependents still reflect the last concrete resolution.
79
+
80
+ After every concrete reload-selector or connection change, re-run `node props`; dynamic props can appear, disappear, or reset. Use `cai node reload <nodeId> --json` to re-resolve without re-setting a selector. If an explicit reload finds an unset materialized reload selector, it returns `reconcileSkipped: "unset_selector"` plus a note and preserves materialized dependent props instead of reconciling them.
77
81
 
78
82
  ### 5. Set props safely
79
83
 
@@ -87,10 +91,12 @@ Optional prop:
87
91
 
88
92
  ```bash
89
93
  cai node optional-props <nodeId> --json
90
- cai node enable-prop <nodeId> --prop <exactName> --json
91
- cai node props <nodeId> --json
94
+ cai node set <nodeId> --prop <exactName> --value '<literal-or-json>' --json
95
+ # or: cai expr set <nodeId> --prop <exactName> --js '<expression>' --json
92
96
  ```
93
97
 
98
+ `node set` and `expr set` auto-enable a catalog-only optional prop, refresh its metadata, then write. Do not run a separate enable step first. If validation or the later write fails, the prop stays enabled; repair with `cai node disable-prop <nodeId> --prop <exactName>` and re-read props. This is also the repair for the Update-data wipe footgun: that action writes every enabled field, so disable any accidentally enabled field before running it.
99
+
94
100
  Remote or dynamic option:
95
101
 
96
102
  ```bash
@@ -102,7 +108,20 @@ cai node set <nodeId> \
102
108
  --json
103
109
  ```
104
110
 
105
- For a remote option, preserve both fields from the same returned option. The label is not cosmetic: the CLI uses it to search providers that do not index opaque IDs, then verifies that the returned value still matches before writing. For a multi-select, pass a JSON array of returned values and one `--label` argument per value, in the same order. The CLI supplies the persisted label shape, chooses the correct expression storage channel, and verifies read-back. If metadata or options cannot be fetched, it fails closed; do not bypass that with a raw API call.
111
+ `node options` also supports `--prev-context '<context JSON>'` from the preceding page and repeatable `--for '<earlierProp>=<value>'` overrides for read-only hypothetical resolution; JSON literals are accepted and bare text stays a string. If options are `blocked_upstream`, both `node options` and `node set` name the blocking prop and print the exact `cai node set` command to run first.
112
+
113
+ For an ordinary remote option, preserve both fields from the same returned option. The label is not cosmetic: the CLI uses it to search providers that do not index opaque IDs, then verifies that the returned value still matches before writing. For a multi-select, pass a JSON array of returned values and one `--label` argument per value, in the same order. The CLI supplies the persisted label shape, chooses the correct expression storage channel, and verifies read-back.
114
+
115
+ When an earlier selector makes the prop `dynamic_upstream`, no option list exists. Use a known exact ID or an expression:
116
+
117
+ ```bash
118
+ cai node set <nodeId> --prop <exactName> --value '<exact-id>' --label '<display label>' --json
119
+ cai node set <nodeId> --prop <exactName> --js '<expression>' --json
120
+ ```
121
+
122
+ `--value` stores the literal without provider-option validation and prints a note; on a label-bearing selector, `--label` controls its display label. This is the sole raw `--value` exception when the CLI has an advertised option set: outside `dynamic_upstream`, a missing prop row, a failed or empty advertised remote-options lookup, or a value absent from advertised options fails closed. The exception still requires prop metadata and verified read-back. Do not bypass failures with a raw API call.
123
+
124
+ For components whose dependent props exist only after a concrete selector value, use a template first: set one concrete value, re-read `node props`, configure or record the revealed dependents, then switch the selector to `--js`. Those materialized props persist as the last concrete schema. Starting dynamic leaves them absent; neither that write nor `node reload` materializes them until one concrete selection is made.
106
125
 
107
126
  For dynamic values, load `controllerai-expressions` and prefer `cai expr set`.
108
127
 
@@ -125,14 +144,22 @@ cai run node <nodeId> --inputs <values.json> --json
125
144
 
126
145
  If the node has a wired input or consumes `inputs.<name>`, the node test is only an isolated configuration check. Run `cai run flow <flowId> --inputs <values.json> --json` before declaring its upstream expressions verified.
127
146
 
147
+ If a dynamic provider action cannot be run but its response is documented, declare an unverified output contract:
148
+
149
+ ```bash
150
+ cai node declare-output <nodeId> --sample-file provider-response.json --json
151
+ ```
152
+
153
+ The sample must be a JSON object or a non-empty JSON array of provider items. Re-read status and expression context afterward; the first real completed run verifies the declaration.
154
+
128
155
  Read [references/prop-and-readiness.md](references/prop-and-readiness.md) when a prop is dynamic, option-backed, expression-capable, or unexpectedly absent.
129
156
 
130
157
  ## Hard rules
131
158
 
132
159
  - Configure props in returned order; later props may depend on earlier values.
133
160
  - Never write a prop absent from `node props`.
134
- - Enable catalog-only optional props before writing them.
161
+ - Let `node set` or `expr set` auto-enable catalog-only optional props; disable the prop explicitly after a failed write.
135
162
  - Wire before authoring an expression that consumes upstream data.
136
163
  - Changing a connection invalidates connection-scoped options; re-read props and options.
137
164
  - A successful write is not completion. Require read-back plus `node status`.
138
- - If output type remains unresolved, perform a realistic development test and inspect the resulting execution. Never fabricate an output schema.
165
+ - If output type remains unresolved, perform a realistic development test and inspect the resulting execution. Declare only a documented provider sample; never fabricate an output schema.
@@ -6,7 +6,9 @@ The JSON response reports:
6
6
 
7
7
  - `missingConnection`: an authenticated component has no account bound.
8
8
  - `missingRequiredProps`: materialized required props without a value.
9
+ - `disabledRequiredProps`: required props currently disabled by an activating selector. When that selector can be resolved, its blocker names the selector; when it is next, `next` gives the exact `cai node set` command.
9
10
  - `pendingReloadProps`: selectors that must be set before dependent props are trustworthy.
11
+ - `dynamicSelectorNotes`: reload selectors holding dynamic values whose dependents were not re-resolved. These notes do not block readiness, so inspect them even when the node reads ready.
10
12
  - `outputTypeStatus`: `concrete`, `unresolved`, or `none`. Connection-port wrappers never count as a concrete process output.
11
13
  - `readyForExpressions`: connection and required/reload props are complete. The source still must be wired before its binding appears in expression context.
12
14
  - `readyForRun`: connection and required/reload props are complete; running may be the step that discovers a concrete output type.
@@ -40,6 +42,14 @@ Do not force a channel with internal fields. `cai node set` and `cai expr set` c
40
42
 
41
43
  Static options are declared in component/prop metadata. Remote options require current connection and earlier prop values.
42
44
 
45
+ When dependency metadata is available, each option-bearing prop reports:
46
+
47
+ - `available`: no earlier selector blocks option resolution; connection or provider failures can still stop the lookup.
48
+ - `blocked_upstream` with `blockedBy`: an earlier single `DROPDOWN` selector is unset.
49
+ - `dynamic_upstream`: an earlier single `DROPDOWN` selector is dynamic, so no concrete option list exists.
50
+
51
+ The backend computes this in prop order. Older backends, and current responses without a dependency catalog, omit these fields; do not interpret absence as `available`.
52
+
43
53
  ```bash
44
54
  cai node options <nodeId> --prop <name> --query "<specific search>" --json
45
55
  cai node set <nodeId> --prop <name> --value '<option.value>' --label '<option.label>' --json
@@ -47,6 +57,20 @@ cai node set <nodeId> --prop <name> --value '<option.value>' --label '<option.la
47
57
 
48
58
  Pass the value and label from the same live option. Remote providers often search labels rather than opaque values, so omitting `--label` can make a valid copied ID impossible to re-verify. For multi-select, pass a JSON array of returned values plus one `--label` argument per value in matching order. The CLI constructs the required array of `{value,label}` records for read-back/UI compatibility.
49
59
 
60
+ Continue a provider page with the opaque context printed by the previous call:
61
+
62
+ ```bash
63
+ cai node options <nodeId> --prop <name> --prev-context '<context JSON>' --json
64
+ ```
65
+
66
+ Preview options under uncommitted earlier values with repeatable overrides; valid JSON becomes a typed literal and bare text remains a string:
67
+
68
+ ```bash
69
+ cai node options <nodeId> --prop <name> --for '<selector>=<value>' --for '<other>=true' --json
70
+ ```
71
+
72
+ For `blocked_upstream`, follow the error's exact command for `blockedBy`. For `dynamic_upstream`, `node options` returns no list; `node set --value '<exact-id>'` deliberately stores a known literal without provider membership validation and prints a note. Add `--label '<display label>'` when the prop is label-bearing, or use `node set --js '<expression>'`. For an advertised option set outside that state, a missing prop row, a failed or empty advertised remote-options lookup, or a value absent from advertised options fails closed.
73
+
50
74
  ## Reload selectors
51
75
 
52
76
  A prop with `reloadProps:true` changes the downstream prop schema. Set it statically, wait for the mutation, and immediately re-read:
@@ -57,8 +81,18 @@ cai node props <nodeId> --json
57
81
  cai node status <nodeId> --json
58
82
  ```
59
83
 
84
+ Use `cai node reload <nodeId> --json` to re-resolve current values explicitly instead of re-setting a selector. If any materialized reload selector is unset, the command returns `reconcileSkipped: "unset_selector"` and a note; that skipped path updates metadata without reconciling or deleting materialized dependent props.
85
+
60
86
  Do not batch dependent values into stale metadata. A provider, model family, spreadsheet, database, or action selector commonly triggers this behavior.
61
87
 
88
+ For a component whose dependent schema exists only after a concrete upstream selection, materialize a template before going dynamic:
89
+
90
+ 1. Set the selector to one concrete value.
91
+ 2. Re-read props and configure or record the revealed dependents.
92
+ 3. Switch the selector to a dynamic value with `--js`.
93
+
94
+ The dependent props persist from the last concrete selection. Starting with a dynamic selector leaves them absent, and neither the dynamic write nor an explicit reload can materialize them until the selector has held a concrete value once.
95
+
62
96
  ## Output type
63
97
 
64
98
  An unresolved output blocks trustworthy downstream field expressions. Resolve it by one of:
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  name: controllerai-runs
3
- description: Run and debug Controller AI nodes and flows on the development version — execution history, ports, outputs, skip reasons, and resolved configs. Use when verifying or testing a build, investigating a failed or green-but-wrong run, resolving an unknown output type, checking expression values, or proving what data and configuration reached each node.
3
+ description: Run and debug Controller AI nodes on development and flows on development or the published live version — execution history, ports, outputs, skip reasons, and resolved configs. Use when verifying or testing a build, investigating a failed or green-but-wrong run, resolving an unknown output type, checking expression values, or proving what data and configuration reached each node.
4
4
  ---
5
5
 
6
6
  # Controller AI runs
7
7
 
8
- Think "dev run", not "test". The development version is a real environment with its own data store — like an app's dev environment — and there is NO simulation mode: a dev run executes real integration actions (messages send, records change, provider usage is spent). Dev isolation covers the data store only. Running is a required part of building — one successful run is how a dynamic node's output type gets resolved for the next step — so the job is never "avoid running"; it is to mitigate risk before running.
8
+ Think "real run", not "simulation". `run node` always uses development; `run flow` defaults to development and can target the published live version. Both rails execute real integration actions (messages send, records change, provider usage is spent); development isolation covers the data store only. Running is a required part of building — one successful run is how a dynamic node's output type gets resolved for the next step — so mitigate risk before running.
9
9
 
10
10
  ## Consequential actions: mitigate with the user, don't refuse
11
11
 
12
- Before dev-running an action with external consequences (send, reject, delete, charge), tell the user plainly what will really happen and ask for a safe target:
12
+ Before running an action with external consequences (send, reject, delete, charge), tell the user plainly what will really happen and ask for a safe target:
13
13
 
14
14
  - Email/message sends → "What address/channel can I send the dev run to?" (often the user's own).
15
15
  - Record deletes/updates → "Is there a record I can safely use, or shall I create one first and delete that?"
@@ -25,7 +25,13 @@ cai node declare-output <nodeId> --sample-file shape.json
25
25
 
26
26
  ## First live run is part of development
27
27
 
28
- Publishing and running live is a legitimate, supervised development step — not a process failure. For risky sends, build the safe-audience harness: branch on the `isLiveVersion` data source with If/Else — the false branch targets the developer (own email/channel), the true branch targets the real audience. The first live run under supervision is how remaining problems surface.
28
+ After publishing, run the published version directly under supervision:
29
+
30
+ ```bash
31
+ cai run flow <flowId> --inputs values.json --target live --confirm-live --json
32
+ ```
33
+
34
+ This command fires external actions and spends usage. For risky sends, build the safe-audience harness: branch on the `isLiveVersion` data source with If/Else — the false branch targets the developer (own email/channel), the true branch targets the real audience. Use this direct live run for explicit verification; do not wait for a real trigger event.
29
35
 
30
36
  ## Prepare exact run inputs
31
37
 
@@ -44,6 +50,10 @@ Use returned opaque input IDs. A compact input file can be a flat map:
44
50
 
45
51
  Do not key test values by a guessed display name.
46
52
 
53
+ Before an isolated node run, `cai run inputs <nodeId> --json` calls `get_node_test_inputs`; supply every referenced `flowInputs[].id` explicitly. Missing one fails before execution with `ISOLATED_FLOW_CONTEXT_REQUIRED`. Explicit `null`, `""`, `false`, and `0` are valid supplied values.
54
+
55
+ Date-typed inputs take plain ISO-8601 strings, e.g. `"2026-06-05"` or `"2026-06-05T12:30:00Z"` (no double-encoding, no epoch strings).
56
+
47
57
  ## Run the smallest useful scope
48
58
 
49
59
  Start with a changed node, then run its containing flow:
@@ -63,6 +73,7 @@ For every node test, inspect:
63
73
  - `skipReason`
64
74
  - `runScope`, especially `upstreamNodesExecuted` and `endToEndValidationRequired`
65
75
  - `resolvedConfigs`
76
+ - `resolvedConfigs[].resolutionWarnings`: trust every structured entry; `[]` is authoritatively clean. Runs also surface entries on stderr, so read stderr even when the execution completed.
66
77
  - `outputTypeAdoption`: the server verifies the exact completed `nodeExecutionId`, derives its persisted output shape, and updates only that non-static node. `adopted` or `already_typed` lets the next `node status` converge; `no_observed_output` means the representative run returned no reusable shape. `adoptedNodeIds` must be empty or contain only the tested node; stop if it names a sibling.
67
78
  - output shape and values
68
79
 
@@ -99,6 +110,7 @@ After successful output discovery, re-read `cai node status` and downstream `cai
99
110
 
100
111
  ## Completion gate
101
112
 
113
+ - Gate scripts on `cai workflow validate`; it exits 1 when the response has `valid: false`.
102
114
  - The test exercised the changed path with credible values.
103
115
  - The first unexpected node, if any, was identified rather than inferred from the final error.
104
116
  - All dynamic configs resolved to intended values.
@@ -9,7 +9,7 @@ cai workflow status --json
9
9
  cai flow get <flowId> --json
10
10
  ```
11
11
 
12
- Manual node/flow tests use development. Trigger replay defaults to the development rail, but both development and live replay can call real providers and create external effects. Live replay additionally requires `--target live --confirm-live`.
12
+ Node runs use development. Flow runs default to development; `cai run flow <flowId> --target live --confirm-live` runs the published version. Trigger replay also defaults to development and uses the same flags for live. Every rail can call real providers and create external effects.
13
13
 
14
14
  ## 2. Find the first divergence
15
15
 
@@ -44,5 +44,6 @@ The platform reference lives at https://docs.getcontroller.ai. Fetch https://doc
44
44
  - Local coding-agent subscriptions cover builder reasoning, not Controller AI hosted-agent runtime usage.
45
45
  - Provider actions can send messages, mutate or delete records, and incur provider charges. Decide the per-action confirmation policy before attaching one.
46
46
  - Never publish, share with the organization, replay a live trigger, or perform a consequential external test without clear user intent.
47
+ - When a platform limitation blocks the outcome, STOP and report the partial result with the blocking error; never keep probing until the clock expires.
47
48
 
48
49
  At completion, report what was created, what is still draft or live, the evidence actually observed, and any connection or user decision still required.
@@ -16,12 +16,16 @@ cai use <workflowId>
16
16
  cai workflow status --json
17
17
  ```
18
18
 
19
- If no workflow exists, create and pin one:
19
+ If no workflow exists, create it with its final name:
20
20
 
21
21
  ```bash
22
22
  cai workflow create --name "<clear outcome-oriented name>" --json
23
23
  ```
24
24
 
25
+ Read `selected`, `effectiveWorkflowId`, and `pinSource` from the result; creation does not guarantee that the new workflow won the effective pin. If `selected` is false, rerun without `--workflow` when `pinSource` is `flag`; otherwise run `cai use <id>` for a stored pin or clear an inherited `CAI_WORKFLOW` pin in the parent environment, then re-check context. Use `cai config reset` to clear stale stored pins; it cannot clear an environment pin. `cai doctor` verifies that the effective workflow pin and its development head are readable. Do not create and then rename: `workflow create --name` submits the name directly.
26
+
27
+ A new workflow already ships with one empty flow. Rename that flow and build in it — do not add a second flow for the first piece of work; only add flows for genuinely separate canvases. A stray empty "Flow 1" left behind is clutter the user has to clean up.
28
+
25
29
  Use IDs returned by the CLI. Never invent workflow, flow, node, prop, event, field, route, or connection identifiers.
26
30
 
27
31
  To orient inside a workflow, prefer one call over many:
@@ -38,8 +42,9 @@ It returns the whole map compactly — every flow with typed inputs/outputs, its
38
42
  2. Inspect the current workflow before editing: `cai workflow outline`, then `cai flow get <flowId>` for the flows you will touch.
39
43
  3. Create or select a flow. Define flow inputs and outputs before nodes that derive props from them.
40
44
  4. Build in execution order. After each material change, read it back with the corresponding `get`, `props`, `status`, or `list` command.
41
- 5. Test on the development rail. Debug every failed or suspicious node; a green top-level status alone is insufficient.
42
- 6. Re-read `cai workflow status`. Publish only when the user asked for a live change or clearly authorized deployment.
45
+ 5. After a headless build, run `cai flow layout <flowId>` once per changed flow at the end; an open builder auto-tidies itself.
46
+ 6. Test on the development rail. Debug every failed or suspicious node; a green top-level status alone is insufficient.
47
+ 7. Re-read `cai workflow status`. Publish only when the user asked for a live change or clearly authorized deployment.
43
48
 
44
49
  For multi-domain work, read [references/command-map.md](references/command-map.md) before editing.
45
50
 
@@ -59,18 +64,18 @@ Load the narrow skill when the task reaches that surface:
59
64
  ## Lifecycle rules
60
65
 
61
66
  - All graph edits target development. Live remains unchanged until `cai workflow publish`.
62
- - Prefer `--json` for decisions and IDs; human tables are for presentation.
67
+ - Prefer `--json` for decisions and IDs; human tables are for presentation. If human output looks odd, re-run the same read with `--json` before acting.
63
68
  - A workflow contains flows; a flow is one canvas. Do not confuse their IDs.
64
- - For flow inputs, pass a human `--display` label and capture the returned `jsBinding`. The server derives, deduplicates, and then freezes that binding; `--name` is only a legacy display alias and renaming the label does not rename expressions.
69
+ - For flow inputs, pass a human `--display` label and use the compiler-current binding from the latest `cai flow get` (`jsBinding`) or `cai workflow outline` (`binding`). An input rename can change it: re-read bindings after every rename and never cache their spellings across renames. `legacyBinding` is diagnostic-only; never use it in expressions.
65
70
  - Name nodes after the data they produce. Downstream input bindings are seeded from that name when wired.
66
- - Use `cai workflow save --name "<checkpoint>"` before a risky rewrite when version history is available.
67
- - **Edit the graph with git-like freedom.** Every save is a version state — `cai workflow history` lists them, `cai workflow restore <stateId>` is the undo. Duplicate, delete, and refactor boldly; nothing inside the graph is unrecoverable. Restore rolls back the DEFINITION (graph and schemas) only — record data is unversioned and stays as it is. External side effects (sent messages, provider calls) are equally outside the undo.
71
+ - Use `cai workflow save --name "<checkpoint>"` before a risky rewrite. Named saves and state renames work on every plan.
72
+ - **Edit the graph with a plan-aware safety net.** Each save is a version state. `cai workflow history` has no age cutoff on Free, Max, or custom plans and a 90-day window on Pro/Starter; expand a group with `cai workflow history --group <groupId>` to get its state IDs. Restore with `cai workflow restore --state <stateId>` within 7 days on Free, 90 days on Pro/Starter, or without an age limit on Max/custom. Duplicate, delete, and refactor with that window in mind. Restore rolls back the DEFINITION (graph and schemas) only — record data is unversioned and stays as it is. External side effects (sent messages, provider calls) are equally outside the undo.
68
73
  - **Validate after structural edits, don't ask permission before them.** After deleting a flow, deleting a type, or a large refactor — and before publish — run `cai workflow validate` and fix what it lists: unlinked subflow callers, dangling type references, branch problems, trigger issues. Deleting a flow deletes its nodes, edges, inputs/outputs, and attached triggers, and breaks callers in other flows — exactly like deleting a function breaks its call sites; validate shows every break.
69
74
  - On a conflict, re-read current state and reapply intent. Do not replay stale IDs or whole documents.
70
75
  - Never delete a workflow without the user's explicit intent; the CLI requires `--yes` but that is not a substitute for authorization. `cai workflow delete` tears down deployed triggers and soft-deletes the workflow row. Historical workflow/version data remains stored, but there is currently no CLI restore command for the deleted row.
71
76
  - **Know the dependency graph before deleting or refactoring shared resources.** `cai deps` shows which agents attach this workflow as a tool (LIVE or draft), which workflows call it, and which connections it uses; `cai deps --account` maps the whole account. Deleting a workflow that agents depend on is refused with the dependents named — bring that list to the user, then `--force` only on their informed choice (a LIVE agent changes behavior immediately).
72
77
  - **Check the account feed when recent activity matters.** `cai events` lists what happened in the account, newest first: connections created, workflow edits/publishes/runs, agents created/published, members added. Filter with `--type` (comma-separated), `--since 30m|2h|7d|<ISO>`, `--for-workflow <id>`; page with `--cursor`. Typical uses: `cai events --type connection.created --since 10m` to see whether the user finished connecting, `cai events --since 24h` to catch up at session start, `cai events --for-workflow <id> --type workflow.run` for recent run activity. The feed cannot show connection deletions, settings changes, or member removals — absence there proves nothing.
73
- - **Share the platform, not just text.** At the right moments, hand the user the real product page — command outputs include `appUrl` when the app origin is known: after `workflow publish` (the live builder view), after `run flow`/`run node` (the run page, to follow along), after `agent publish`/`test` (agent and conversation pages), and `connection connect` prints the connect link (use `--wait` to continue automatically once they connect). When the user asks for a link at any other time, don't guess URLs: `cai workflow get`, `cai workflow status`, and `cai agent get` include `appUrl`. When you cannot perform something (settings, product-only surfaces), give the link instead of apologizing.
78
+ - **Share the platform, not just text.** At the right moments, hand the user the real product page — command outputs include `appUrl` when the app origin is known: after `workflow publish` (the live builder view), after development `run flow`/`run node` (the run page; live flow runs omit it), after `agent publish`/`test` (agent and conversation pages), and `connection connect` prints the connect link (use `--wait` to continue automatically once they connect). When the user asks for a link at any other time, don't guess URLs: `cai workflow get`, `cai workflow status`, and `cai agent get` include `appUrl`. When you cannot perform something (settings, product-only surfaces), give the link instead of apologizing.
74
79
  - Never silently weaken the request to make a test pass. Report an unsupported capability or ask about a real product decision.
75
80
 
76
81
  ## Completion gate
@@ -7,6 +7,7 @@ Read only the sections relevant to the requested work. Use `cai <domain> --help`
7
7
  ```text
8
8
  cai connect
9
9
  cai doctor
10
+ cai config reset [--local|--global]
10
11
  cai auth status
11
12
  cai workflow list|create|get|rename|describe|duplicate|delete
12
13
  cai workflow state|status|versions|releases|history|save|restore|publish
@@ -18,7 +19,7 @@ cai use <workflowId>
18
19
  ## Canvas and graph
19
20
 
20
21
  ```text
21
- cai flow list|get|create|rename|duplicate|delete|reorder
22
+ cai flow list|get|create|rename|duplicate|delete|reorder|layout
22
23
  cai flow input add|update|delete
23
24
  cai flow output add|update|delete
24
25
  cai node find|search|components|component
@@ -27,7 +28,7 @@ cai node init|status|get|props|set|connect|disconnect|delete
27
28
 
28
29
  Declare flow outputs before adding a Return response node. Its props are derived from those outputs.
29
30
 
30
- `cai flow input add <flowId> --display "<human label>" --type <type>` returns the exact frozen `jsBinding`. Copy it or re-read expression context; never infer it from the label after deduplication.
31
+ `cai flow input add <flowId> --display "<human label>" --type <type>` returns the compiler-current `jsBinding`. Use the latest value from `flow get` (`jsBinding`) or `workflow outline` (`binding`), re-read it after every input rename, and never cache its spelling across renames. `legacyBinding` is diagnostic-only.
31
32
 
32
33
  ## Conditions and composition
33
34