@controllerai/cli 0.2.18 → 0.2.21

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 (45) hide show
  1. package/package.json +6 -4
  2. package/skills/controllerai-agents/SKILL.md +66 -152
  3. package/skills/controllerai-agents/references/instructions-and-versioning.md +32 -34
  4. package/skills/controllerai-ai-nodes/SKILL.md +57 -65
  5. package/skills/controllerai-ai-nodes/references/selection-and-testing.md +44 -26
  6. package/skills/controllerai-data/SKILL.md +65 -118
  7. package/skills/controllerai-data/references/data-rails.md +24 -26
  8. package/skills/controllerai-expressions/SKILL.md +48 -117
  9. package/skills/controllerai-expressions/references/dsl-and-recipes.md +42 -40
  10. package/skills/controllerai-flow-control/SKILL.md +66 -122
  11. package/skills/controllerai-flow-control/references/patterns.md +23 -60
  12. package/skills/controllerai-integration-actions/SKILL.md +47 -75
  13. package/skills/controllerai-node-config/SKILL.md +60 -130
  14. package/skills/controllerai-node-config/references/prop-and-readiness.md +28 -78
  15. package/skills/controllerai-runs/SKILL.md +50 -85
  16. package/skills/controllerai-runs/references/debugging.md +24 -22
  17. package/skills/controllerai-start/SKILL.md +53 -58
  18. package/skills/controllerai-start/references/mcp-tool-map.md +21 -16
  19. package/skills/controllerai-triggers/SKILL.md +62 -159
  20. package/skills/controllerai-triggers/references/lifecycle.md +36 -48
  21. package/skills/controllerai-workflows/SKILL.md +70 -70
  22. package/skills/controllerai-workflows/references/command-map.md +19 -44
  23. package/skills/manifest.json +80 -77
  24. package/skills-mcp/controllerai-agents/SKILL.md +121 -0
  25. package/skills-mcp/controllerai-agents/references/instructions-and-versioning.md +76 -0
  26. package/skills-mcp/controllerai-ai-nodes/SKILL.md +92 -0
  27. package/skills-mcp/controllerai-ai-nodes/references/selection-and-testing.md +66 -0
  28. package/skills-mcp/controllerai-data/SKILL.md +119 -0
  29. package/skills-mcp/controllerai-data/references/data-rails.md +45 -0
  30. package/skills-mcp/controllerai-expressions/SKILL.md +98 -0
  31. package/skills-mcp/controllerai-expressions/references/dsl-and-recipes.md +136 -0
  32. package/skills-mcp/controllerai-flow-control/SKILL.md +114 -0
  33. package/skills-mcp/controllerai-flow-control/references/patterns.md +83 -0
  34. package/skills-mcp/controllerai-integration-actions/SKILL.md +89 -0
  35. package/skills-mcp/controllerai-node-config/SKILL.md +106 -0
  36. package/skills-mcp/controllerai-node-config/references/prop-and-readiness.md +49 -0
  37. package/skills-mcp/controllerai-runs/SKILL.md +88 -0
  38. package/skills-mcp/controllerai-runs/references/debugging.md +53 -0
  39. package/skills-mcp/controllerai-start/SKILL.md +80 -0
  40. package/skills-mcp/controllerai-start/references/mcp-tool-map.md +175 -0
  41. package/skills-mcp/controllerai-triggers/SKILL.md +112 -0
  42. package/skills-mcp/controllerai-triggers/references/lifecycle.md +59 -0
  43. package/skills-mcp/controllerai-workflows/SKILL.md +109 -0
  44. package/skills-mcp/controllerai-workflows/references/command-map.md +1 -0
  45. package/skills-mcp/manifest.json +189 -0
@@ -1,192 +1,122 @@
1
1
  ---
2
2
  name: controllerai-node-config
3
- description: Discover, initialize, configure, connect, and verify Controller AI workflow nodes. Use when adding an action, selecting an integration component, binding an account, setting node props, enabling optional or dynamic props, choosing provider-backed options, wiring nodes, or fixing a node that is not ready to run.
3
+ description: Discover, add, connect, configure, wire, and verify Controller AI workflow nodes. Use when adding an action, choosing a component, binding an account, setting props (static, optional, option-backed or dynamic), wiring nodes, resolving an output type, or fixing a node that is not ready.
4
4
  ---
5
+ <!-- generated from .claude/skills by cli/scripts/render-skills.mjs; edit the source -->
5
6
 
6
- # Controller AI node configuration
7
+ # Node configuration
7
8
 
8
- The `cai ...` examples are canonical grammar. Use the transport selected in `controllerai-start` and its MCP tool map; never mix transports in one task.
9
+ ## Use this when
9
10
 
10
- A node is ready only after its component, connection, dependency-ordered props, wiring, and output type are valid. Treat configuration as a state machine, not a bag of property writes.
11
+ - A flow needs an action from an app or a native service, and the node has to be found, added, bound to an account, configured and wired.
12
+ - A node reports missing connection, missing or disabled required props, pending selectors, or an unresolved output type.
11
13
 
12
- ## Deterministic sequence
14
+ Computed values and conditions belong to `controllerai-expressions`; Router, If/Else, loops and subflows to `controllerai-flow-control`; Ask AI provider, model and typed output to `controllerai-ai-nodes`; tests and execution evidence to `controllerai-runs`.
13
15
 
14
- ### 1. Find an exact component
16
+ ## How it works
15
17
 
16
- ```bash
17
- cai integration actions "<capability>" --json
18
- cai integration action --integration <nodeSlug> --key <nodeKey> --json
19
- ```
20
-
21
- Use the returned `nodeSlug` and full `key`. Do not infer a component key from its display name. If discovery is broad, narrow it with:
22
-
23
- ```bash
24
- cai integration search "<integration>" --actions --json
25
- cai integration actions "<action>" --integration <nodeSlug> --json
26
- ```
27
-
28
- Inspect static prop metadata before creating the node. `required`, `remoteOptions`, and `reloadProps` determine configuration order.
29
-
30
- ### 2. Resolve the account
18
+ A **node** is a configured instance of a **component**: an integration action, a native data, file or AI action, or a control node. The component defines the props, whether an account is required, and the output shape. A node becomes usable in stages: component, connection, props in dependency order, then wiring and a concrete output type for whatever reads it downstream; each stage has its own readiness signal, so configure it as a sequence, not as one batch of property writes.
31
19
 
32
- If the component requires auth:
33
-
34
- ```bash
35
- cai connection list --node <nodeSlug> --json
36
- ```
20
+ **Connections** are the authorized accounts of an integration. A saved active connection proves a binding exists, not that the provider still accepts it; a representative request proves that. Changing a node's connection invalidates every connection-scoped option: re-fetch and re-verify them.
37
21
 
38
- - One active connection: use its exact `id` as the `connectionId`.
39
- - Several: use an explicit user preference; otherwise ask which account.
40
- - None: add the real component without `--connection`; `missingConnection: true` is a valid handoff state. On CLI, get the link with `cai connection connect <nodeSlug> --no-open` and share it right away; do not block on `--wait` before sharing.
22
+ **Props** come in kinds: static values; optional props that exist in the catalog and appear once enabled; option-backed props whose values come from static lists or a provider lookup; reload selectors (`reloadProps: true`) that change the schema of later props; and expression-capable props that take a dynamic value. Options are resolved in prop order: an earlier single-choice selector gates later lookups. `optionsAvailability` reports `available`, `blocked_upstream` with `blockedBy`, or `dynamic_upstream`; when the field is absent, availability is unknown, not available.
41
23
 
42
- MCP: call `connection_connect_url` with `nodeSlug`, show its `url` as a markdown link, ask the user to finish, then confirm with `connection_list` using its `integration`.
24
+ **Readiness** (the node status read) reports distinct blockers: `missingConnection`, `missingRequiredProps`, `disabledRequiredProps` (the selector that activates them is named in `blockedBy` and `next`), `pendingReloadProps`, an unset subflow target or an invalid static option, and `dynamicSelectorNotes` (non-blocking: dependents still reflect the last concrete selection). `readyForExpressions` means the connection and the required and reload props are complete; `readyForRun` means it can execute; `readyForDownstreamExpressions` additionally means the output type is concrete. Readiness does not check wiring. `outputTypeStatus` is `concrete`, `unresolved` or `none` (a sink or control node has no output); an unresolved integration output is learned from a representative run, a supported output selector or a declared sample, and adoption changes only that node, so two instances of a generic component can learn different shapes. `next` is diagnostic guidance phrased as a CLI step: apply it through the current surface and its policy rather than executing it blindly.
43
25
 
44
- After they confirm, run `cai connection list --integration <nodeSlug> --json` and bind the new ID with `cai node set-connection <nodeId> --connection <connectionId>`.
26
+ ## Rules
45
27
 
46
- Never substitute a connection from a similar slug.
28
+ 1. **Use the exact component the discovery returned** (`nodeSlug` and full `key`); never infer a key from a display name, and never swap in a similar integration or a raw HTTP request (`registry_http-http-request`) because a connection is missing. A user's mention of an endpoint is context, not a request to hand-roll the call.
29
+ 2. **Add a node without a connection when no account exists.** `missingConnection: true` is a valid handoff state; get the user's authorization and bind the exact new connection ID afterwards. Never ask for a provider credential in chat.
30
+ 3. **Configure in dependency order and read back after every write.** Set reload selectors before their dependents, re-read props after each selector or connection change, and treat a write as done only after readback plus `node status`.
31
+ 4. **Write only props that exist.** Materialized props and catalog optionals are writable; a name absent from both is an error. Setting a catalog optional enables it automatically; do not enable first. If that write then fails, the prop stays enabled: disable it and re-read.
32
+ 5. **Repair in place.** Keep the node ID, wiring, conditions and references, because downstream bindings and subflow mappings point at that ID. Replace a node only when the requested component itself changes; then reconnect and revalidate every dependent.
33
+ 6. **Keep value and label together for option-backed props.** Labels are how providers that do not index opaque IDs are searched and how values are verified. Outside `dynamic_upstream`, a value that is not in the advertised options fails closed.
34
+ 7. **Wire before writing an expression that reads upstream data**, and use branch connections for Router and If/Else outputs.
35
+ 8. **Never fabricate an output schema.** Resolve the type with a representative run, a supported output selector, or a documented provider sample declared as unverified; preserve a static contract instead of overwriting it with an inferred one.
36
+ 9. **Update Data writes every enabled field that resolves to a value.** A field that resolves to nothing is left out, but an enabled field that resolves to null or empty text overwrites the stored value, so disable fields you enabled by accident and inspect the resolved values before running.
47
37
 
48
- Rename or change the default with `cai connection update <id> [--name "<displayName>"] [--default|--no-default]` (MCP: `connection_update`); delete only intentionally with `cai connection delete <id> --yes` (MCP: `connection_delete`).
49
- Deleting a connection immediately removes authorization from bound nodes and agent tools.
38
+ ## Recipes
50
39
 
51
- A missing connection is never a reason to substitute `registry_http-http-request` for a catalog component. A raw endpoint mentioned by the user is background context, not an instruction to hand-roll the call.
52
-
53
- ### 3. Initialize once
40
+ ### Find the component
54
41
 
55
42
  ```bash
56
- cai node init \
57
- --flow <flowId> \
58
- --node <nodeSlug> \
59
- --key <nodeKey> \
60
- --name "<data this node produces>" \
61
- --connection <connectionId> \
62
- --after <upstreamNodeId> \
63
- --json
43
+ cai integration actions "<capability>" --json
44
+ cai integration action --integration <nodeSlug> --key <key> --json
64
45
  ```
65
46
 
66
- MCP: use `node_add`; `cai node init` is the CLI alias of `cai node add`.
67
-
68
- Omit flags that do not apply. `--after` creates the ordinary main/error wire at creation. Use it when later props need upstream data. Initialization also accepts `--props`, but use it only for static, non-option values already present in the inspected component metadata. Never inline a `remoteOptions` value, a reload selector and its dependents, or a prop that has not materialized yet; initialize first and set those sequentially. Use `--enable-prop <name...>` only for optional props confirmed by component metadata.
47
+ Narrow a broad result with `cai integration search "<integration>" --actions --json`, then `cai integration actions "<action>" --integration <nodeSlug> --json`. Read `required`, `remoteOptions` and `reloadProps` before adding: they decide the configuration order.
69
48
 
70
- Capture the returned `nodeId`; do not rediscover it by name. Inspect the complete create result before projecting fields. A missing projection is not proof that creation failed, so read the captured ID or exact flow inventory before any retry.
71
-
72
- When repairing an existing node, keep its node ID and configure it in place. Do not delete and recreate it merely to clear bad props, select a component, or refresh generated props; deletion discards wiring, conditions, and identity-based references. Replace it only when the requested component itself must change. Then capture the replacement ID, reconnect every dependent, and revalidate them.
73
-
74
- ### 4. Follow readiness, not guesses
49
+ ### Resolve the account
75
50
 
76
51
  ```bash
77
- cai node status <nodeId> --json
78
- cai node props <nodeId> --json
52
+ cai connection list --integration <nodeSlug> --json
79
53
  ```
80
54
 
81
- 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.
82
-
83
- Work through blockers in this order:
84
-
85
- 1. Missing connection
86
- 2. Required selector props with `reloadProps`
87
- 3. Newly revealed required props
88
- 4. Static and remote-option props
89
- 5. Wiring required for expressions
90
- 6. Expressions
91
- 7. Unresolved output type
92
-
93
- 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.
94
-
95
- 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.
55
+ One active connection: use its ID. Several: follow the user's stated preference, otherwise ask which account. None: add the node without a connection and hand off.
96
56
 
97
- ### 5. Set props safely
98
-
99
- Static value:
57
+ Get the authorization link with `cai connection connect <nodeSlug> --no-open` and share it right away rather than waiting on `--wait`. After the user confirms, list connections again and bind the new ID.
100
58
 
101
59
  ```bash
102
- cai node set <nodeId> --prop <exactName> --value '<literal-or-json>' --json
60
+ cai node set-connection <nodeId> --connection <connectionId> --json
61
+ cai node status <nodeId> --json
103
62
  ```
104
63
 
105
- MCP: use `node_prop_set` with `value`; it also handles expression writes through `js`.
106
-
107
- Optional prop:
64
+ ### Add the node
108
65
 
109
66
  ```bash
110
- cai node optional-props <nodeId> --json
111
- cai node set <nodeId> --prop <exactName> --value '<literal-or-json>' --json
112
- # or: cai expr set <nodeId> --prop <exactName> --js '<expression>' --json
67
+ cai node add --flow <flowId> --node <nodeSlug> --key <key> --name "<data this node produces>" --connection <connectionId> --after <upstreamNodeId> --json
113
68
  ```
114
69
 
115
- MCP: `cai expr set` is the `js` form of `node_prop_set`.
70
+ Name the node after its purpose or the value it produces. Omit flags that do not apply. `--after` wires the upstream node's main output (or `--output error`) at creation, which later expressions need. Initial `--props` may carry only inspected static values, and `--enable-prop <name...>` is for optionals confirmed by the metadata. Never pass a remote option, a reload selector with its dependents, or a prop that has not materialized at creation. Capture the returned `nodeId`, then inspect `propsReadback` and `readiness` in the result and fix only rejected or missing fields.
116
71
 
117
- `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.
118
-
119
- MCP: use `node_optional_prop_set` with `enabled: false` to disable or `enabled: true` to enable.
120
-
121
- Remote or dynamic option:
72
+ ### Follow readiness
122
73
 
123
74
  ```bash
124
- cai node options <nodeId> --prop <exactName> --query "<specific label>" --json
125
- cai node set <nodeId> \
126
- --prop <exactName> \
127
- --value '<returned value>' \
128
- --label '<returned label>' \
129
- --json
75
+ cai node status <nodeId> --json
76
+ cai node props <nodeId> --json
130
77
  ```
131
78
 
132
- `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.
133
-
134
- For an ordinary remote option, preserve both fields from the same returned option. The label is not cosmetic: it is used to search providers that do not index opaque IDs, then the returned value is verified before writing. For a multi-select, pass a JSON array of returned values and one `--label` argument per value, in the same order. The write supplies the persisted label shape, chooses the correct expression storage channel, and verifies read-back.
79
+ Clear blockers in this order: connection; required reload selectors; newly revealed required props; static and option-backed props; wiring an expression needs; expressions; output type. Use `next` as the guide for the next step. After a concrete selector or connection change, re-read props: fields appear, disappear or reset. `cai node reload <nodeId> --json` re-resolves dependents without re-setting a selector; when a materialized selector is unset it returns `reconcileSkipped: "unset_selector"` and preserves the dependents.
135
80
 
136
- When an earlier selector makes the prop `dynamic_upstream`, no option list exists. Use a known exact ID or an expression:
81
+ ### Set a prop
137
82
 
138
83
  ```bash
139
- cai node set <nodeId> --prop <exactName> --value '<exact-id>' --label '<display label>' --json
140
- cai node set <nodeId> --prop <exactName> --js '<expression>' --json
84
+ cai node set <nodeId> --prop <exactName> --value '<literal-or-json>' --json
85
+ cai node optional-props <nodeId> --json
86
+ cai node options <nodeId> --prop <exactName> --query "<specific label>" --json
87
+ cai node set <nodeId> --prop <exactName> --value '<returned value>' --label '<returned label>' --json
88
+ cai node disable-prop <nodeId> --prop <exactName>
141
89
  ```
142
90
 
143
- `--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.
91
+ Multi-select takes a JSON array of returned values and one `--label` per value in the same order. `node options` continues a provider page with `--prev-context '<context JSON>'` and previews under uncommitted earlier values with repeatable `--for '<earlierProp>=<value>'` (valid JSON is typed, bare text stays a string). When options are `blocked_upstream`, the error names the selector and prints the exact command to run first. For `dynamic_upstream`, no list exists: write a known exact ID with `--value` plus `--label`, or an expression with `--js`.
144
92
 
145
- 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.
93
+ For a component whose dependent props exist only after a concrete selection, materialize a template first: set one concrete value, re-read props and configure the revealed dependents, then switch the selector to an expression. The dependents persist from that last concrete selection; starting dynamic leaves them absent. For dynamic values, load `controllerai-expressions`.
146
94
 
147
- For dynamic values, load `controllerai-expressions` and prefer `cai expr set`.
148
-
149
- ### 6. Wire and verify
150
-
151
- Ordinary outputs:
95
+ ### Wire
152
96
 
153
97
  ```bash
154
98
  cai node connect --flow <flowId> --from <sourceNodeId> --to <targetNodeId> --output main --json
155
99
  ```
156
100
 
157
- Use `--output error` only for the automatic error path. Router and If/Else outputs require `cai branch connect` from the flow-control skill.
101
+ `--output error` is only for the automatic error path. Router and If/Else outputs use branch connections from `controllerai-flow-control`.
158
102
 
159
- Finish with:
103
+ ### Resolve the output type
160
104
 
161
105
  ```bash
162
- cai node status <nodeId> --json
163
- cai run node <nodeId> --inputs <values.json> --json
106
+ cai run node <nodeId> --inputs '<json>' --json
107
+ cai node declare-output <nodeId> --sample-file - --json
164
108
  ```
165
109
 
166
- MCP: `run_node` takes the parsed `inputs` object and `waitSeconds` (default 60, max 120).
110
+ `--inputs` and `--sample-file` also take a file path; `--sample-file -` reads the documented response from stdin.
167
111
 
168
- 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.
169
-
170
- MCP: `run_flow` takes the parsed `inputs` object and `waitSeconds` (default 60, max 120).
171
-
172
- If a dynamic provider action cannot be run but its response is documented, declare an unverified output contract:
173
-
174
- ```bash
175
- cai node declare-output <nodeId> --sample-file provider-response.json --json
176
- ```
112
+ Prefer the representative run: the completed execution is checked for ownership and terminal state, then its output shape is adopted for that node. Inspect `outputTypeAdoption` in the run result: `no_observed_output` on a data-producing action means the run returned nothing reusable, so rerun it with inputs that return data only when a downstream binding needs the type and the additional real action is authorized; on a sink or control node it is the expected result. `error` means stop and surface it. Declare a documented sample (an object or a non-empty array of items) when the action is unavailable, unsafe or declined; it stays unverified until the first real run. A node test with a wired input is an isolated check; upstream expressions are verified only by running the containing flow. Adoption is node-local: a discovery run on a scratch node never types the node in the flow. Read `controllerai-runs` for discovery.
177
113
 
178
- MCP: call `node_output_type_declare` with the parsed provider response in `sample`; the server cannot read `provider-response.json`.
114
+ ## Verify
179
115
 
180
- 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.
116
+ `node status` shows no blockers for the requested readiness level, every written prop reads back with the intended value and label, the wiring matches the flow, and the output type is concrete before downstream fields are bound. Expression context (`cai expr context <nodeId> --prop <prop> --json`) lists the upstream binding you expect.
181
117
 
182
- Read [references/prop-and-readiness.md](references/prop-and-readiness.md) when a prop is dynamic, option-backed, expression-capable, or unexpectedly absent.
118
+ ## Report
183
119
 
184
- ## Hard rules
120
+ The component and connection used, which props were set and which remain for the user (a missing authorization above all), and whether the output type was verified by a run or only declared.
185
121
 
186
- - Configure props in returned order; later props may depend on earlier values.
187
- - Never write a prop absent from `node props`.
188
- - Let `node set` or `expr set` auto-enable catalog-only optional props; disable the prop explicitly after a failed write.
189
- - Wire before authoring an expression that consumes upstream data.
190
- - Changing a connection invalidates connection-scoped options; re-read props and options.
191
- - A successful write is not completion. Require read-back plus `node status`.
192
- - 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.
122
+ Read [references/prop-and-readiness.md](references/prop-and-readiness.md) when a prop is dynamic, option-backed, expression-capable, or unexpectedly absent, or when a status field needs its exact meaning.
@@ -1,112 +1,62 @@
1
+ <!-- generated from .claude/skills by cli/scripts/render-skills.mjs; edit the source -->
1
2
  # Prop and readiness reference
2
3
 
3
- ## What `cai node status` means
4
-
5
- The JSON response reports:
4
+ ## What `cai node status` reports
6
5
 
7
6
  - `missingConnection`: an authenticated component has no account bound.
8
7
  - `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.
8
+ - `disabledRequiredProps`: names of required props currently disabled by an activating selector. `blockedBy` and `next` name that selector.
10
9
  - `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.
12
- - `outputTypeStatus`: `concrete`, `unresolved`, or `none`. Connection-port wrappers never count as a concrete process output.
13
- - `readyForExpressions`: connection and required/reload props are complete. The source still must be wired before its binding appears in expression context.
14
- - `readyForRun`: connection and required/reload props are complete; running may be the step that discovers a concrete output type.
15
- - `readyForDownstreamExpressions`: the node is runnable and its actual process output type is concrete enough for downstream field bindings.
16
- - `next`: the canonical next diagnostic command.
17
-
18
- Follow `next`, then read status again. Do not treat `readyForRun` as proof that downstream fields are typed; require `readyForDownstreamExpressions` for that.
19
-
20
- For an existing node with a missing connection, a browser handoff alone is not enough. After the user connects, list the compatible accounts, bind the chosen ID, and re-read status:
21
-
22
- ```bash
23
- cai connection connect <nodeSlug>
24
- cai connection list --node <nodeSlug> --json
25
- cai node set-connection <nodeId> --connection <connectionId> --json
26
- cai node status <nodeId> --json
27
- ```
28
-
29
- MCP: replace `cai connection connect` with `connection_connect_url { nodeSlug }`; the other calls map directly.
10
+ - `dynamicSelectorNotes`: reload selectors holding dynamic values whose dependents were not re-resolved. Non-blocking; read them even when the node is ready.
11
+ - `outputTypeStatus`: `concrete`, `unresolved` or `none`. Connection-port wrappers never count as a concrete process output.
12
+ - `readyForExpressions`: connection and required/reload props complete. The source still has to be wired before its binding appears in expression context.
13
+ - `readyForRun`: runnable; the run may be what discovers the output type.
14
+ - `readyForDownstreamExpressions`: runnable and the process output type is concrete enough for downstream field bindings. Require this, not `readyForRun`, before binding downstream fields.
15
+ - `next`: diagnostic guidance for the next step, phrased as a CLI command; apply it through the current surface and its policy.
30
16
 
31
17
  ## Prop channels
32
18
 
33
- Use `cai node set`; it selects the persisted shape from live metadata.
19
+ `cai node set` picks the channel from live metadata; the readback shows it as a decompiled view:
34
20
 
35
- | Intent | Command input | Persisted channel |
21
+ | Intent | Input | Readback view |
36
22
  | --- | --- | --- |
37
- | Static text, JSON text, scalar, object, or list | `--value` | `value` |
38
- | Dynamic text, JSON text, or custom data | `--js` | `valueJs` |
39
- | Dynamic non-text prop with expression mode | `--js` | `expressionValueJs` |
23
+ | Static text, JSON text, scalar, or (where the prop allows it) object or list | `--value` | `value` |
24
+ | Dynamic text, JSON text or custom data | `--js` | `valueJs` |
25
+ | Dynamic non-text prop in expression mode | `--js` | `expressionValueJs` |
40
26
 
41
- MCP: both `cai node set` and `cai expr set` use `node_prop_set`; pass exactly one of `value`, `js`, or `rawExpressionJson`.
27
+ A custom-data prop takes only a string, a finite number or a boolean as a literal. A compiled literal may have no decompiled view at all.
42
28
 
43
- Do not force a channel with internal fields. `cai node set` and `cai expr set` compile first and verify the actual channel after writing.
29
+ Never force a channel through internal fields. The expression setters compile before writing (a raw tree is validated by the backend), and every setter verifies the actual channel in the readback.
44
30
 
45
31
  ## Option-backed props
46
32
 
47
- Static options are declared in component/prop metadata. Remote options require current connection and earlier prop values.
33
+ Static options are declared in the component metadata. Remote options need the current connection and the earlier prop values. When dependency metadata is present, each option-bearing prop reports:
48
34
 
49
- When dependency metadata is available, each option-bearing prop reports:
35
+ - `available`: no earlier selector blocks the lookup (a connection or provider failure can still stop it).
36
+ - `blocked_upstream` with `blockedBy`: an earlier single-choice selector is unset. Follow the error's exact command first.
37
+ - `dynamic_upstream`: an earlier single-choice selector holds an expression, so no concrete option list exists. Write a known exact ID with its display label, or an expression. This is the only case that skips membership validation; it still needs prop metadata and verified readback.
50
38
 
51
- - `available`: no earlier selector blocks option resolution; connection or provider failures can still stop the lookup.
52
- - `blocked_upstream` with `blockedBy`: an earlier single `DROPDOWN` selector is unset.
53
- - `dynamic_upstream`: an earlier single `DROPDOWN` selector is dynamic, so no concrete option list exists.
39
+ Older backends and responses without a dependency catalog omit these fields; absence means unknown.
54
40
 
55
- 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`.
41
+ Pass the value and the label from the same live option. Many providers search labels rather than opaque IDs, so a copied ID without its label may be impossible to re-verify. Multi-select takes an ordered array of values and an aligned array of labels; the readback shows `{value, label}` records.
56
42
 
57
43
  ```bash
58
44
  cai node options <nodeId> --prop <name> --query "<specific search>" --json
59
- cai node set <nodeId> --prop <name> --value '<option.value>' --label '<option.label>' --json
60
- ```
61
-
62
- 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 write constructs the required array of `{value,label}` records for read-back/UI compatibility.
63
-
64
- Continue a provider page with the opaque context printed by the previous call:
65
-
66
- ```bash
67
45
  cai node options <nodeId> --prop <name> --prev-context '<context JSON>' --json
68
- ```
69
-
70
- Preview options under uncommitted earlier values with repeatable overrides; valid JSON becomes a typed literal and bare text remains a string:
71
-
72
- ```bash
73
46
  cai node options <nodeId> --prop <name> --for '<selector>=<value>' --for '<other>=true' --json
47
+ cai node set <nodeId> --prop <name> --value '<option.value>' --label '<option.label>' --json
74
48
  ```
75
49
 
76
- 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.
77
-
78
50
  ## Reload selectors
79
51
 
80
- A prop with `reloadProps:true` changes the downstream prop schema. Set it statically, wait for the mutation, and immediately re-read:
81
-
82
- ```bash
83
- cai node set <nodeId> --prop <selector> --value '<value>' --json
84
- cai node props <nodeId> --json
85
- cai node status <nodeId> --json
86
- ```
87
-
88
- 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.
89
-
90
- Do not batch dependent values into stale metadata. A provider, model family, spreadsheet, database, or action selector commonly triggers this behavior.
91
-
92
- For a component whose dependent schema exists only after a concrete upstream selection, materialize a template before going dynamic:
52
+ A prop with `reloadProps: true` changes the schema of later props. Set it, then immediately re-read props and status. Provider, model family, spreadsheet, database and action selectors commonly behave this way; never batch their dependents against stale metadata.
93
53
 
94
- 1. Set the selector to one concrete value.
95
- 2. Re-read props and configure or record the revealed dependents.
96
- 3. Switch the selector to a dynamic value with `--js`.
54
+ A prop reload re-resolves current values without re-setting a selector. If a materialized reload selector is unset, it returns `reconcileSkipped: "unset_selector"` and preserves the materialized dependents instead of reconciling them.
97
55
 
98
- 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.
56
+ For a component whose dependent schema exists only after a concrete selection: set one concrete value, re-read and configure the revealed dependents, then switch the selector to an expression. The dependents persist from the last concrete selection; starting dynamic leaves them absent, and neither the dynamic write nor a reload materializes them.
99
57
 
100
58
  ## Output type
101
59
 
102
- An unresolved output blocks trustworthy downstream field expressions. Resolve it by one of:
103
-
104
- - Set the component's supported output/data type selector.
105
- - Run the configured node with representative inputs.
106
- - Probe an action with `cai run discover` only when its real-world side effects are acceptable.
107
-
108
- After the run, read `cai node status` and `cai expr context` again. Do not infer fields from an example response alone if the platform did not adopt a concrete type.
109
-
110
- Completed node and flow runs pass the exact node-execution ID back for ownership, workflow, node, component-snapshot, and terminal-status checks before deriving the persisted output shape; callers never supply the type name. Adoption updates only that non-static node, so separate instances of generic components such as HTTP can learn different schemas. Inspect `outputTypeAdoption`/`outputTypeAdoptions` in the run result. If it reports `no_observed_output`, use a representative input that returns data and rerun. If it reports `error`, stop and surface that error rather than inventing a schema.
60
+ Resolve an unresolved output by setting the component's supported output or data-type selector, by running the configured node with representative inputs, or by declaring a documented provider sample as unverified. A discovery run (`controllerai-runs`) probes a component that is not in the graph on a scratch node: it deletes that node afterwards, keeps the scratch flow for reuse, and never types a node in the real flow.
111
61
 
112
- MCP: `run_node` and `run_flow` take `inputs` inline and `waitSeconds` from 0 through 120.
62
+ A completed run passes its exact node-execution ID back for ownership, workflow, node, component-snapshot and terminal-state checks, then the persisted output shape is adopted for that non-static node only. Read `outputTypeAdoption` (or `outputTypeAdoptions`) in the run result: `no_observed_output` means the run produced no reusable output, which is expected for a sink or control node and, for a data-producing action, a reason to rerun with representative data only when a downstream binding needs the type; `error` means stop and surface it. After adoption, re-read `node status` and the expression context. An example response alone never establishes a type.