@controllerai/cli 0.2.20 → 0.2.22
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 +6 -3
- package/dist/api/client.js +5 -38
- package/dist/api/client.js.map +1 -1
- package/dist/commands/agent.js +169 -146
- package/dist/commands/agent.js.map +1 -1
- package/dist/commands/expr.js +10 -3
- package/dist/commands/expr.js.map +1 -1
- package/dist/commands/integration.js +30 -10
- package/dist/commands/integration.js.map +1 -1
- package/dist/commands/skills.js +1 -0
- package/dist/commands/skills.js.map +1 -1
- package/dist/commands/templateSetup.js +42 -0
- package/dist/commands/templateSetup.js.map +1 -0
- package/dist/commands/workflow.js +6 -7
- package/dist/commands/workflow.js.map +1 -1
- package/dist/errors.js +2 -5
- package/dist/errors.js.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/permissionTool.js +1 -1
- package/dist/permissionTool.js.map +1 -1
- package/package.json +6 -4
- package/skills/controllerai-agents/SKILL.md +109 -26
- package/skills/controllerai-agents/references/instructions-and-versioning.md +32 -34
- package/skills/controllerai-ai-nodes/SKILL.md +83 -10
- package/skills/controllerai-ai-nodes/references/selection-and-testing.md +44 -26
- package/skills/controllerai-data/SKILL.md +106 -34
- package/skills/controllerai-data/references/data-rails.md +24 -26
- package/skills/controllerai-expressions/SKILL.md +82 -29
- package/skills/controllerai-expressions/references/dsl-and-recipes.md +42 -40
- package/skills/controllerai-flow-control/SKILL.md +104 -21
- package/skills/controllerai-flow-control/references/patterns.md +23 -60
- package/skills/controllerai-integration-actions/SKILL.md +89 -11
- package/skills/controllerai-node-config/SKILL.md +108 -18
- package/skills/controllerai-node-config/references/prop-and-readiness.md +28 -78
- package/skills/controllerai-runs/SKILL.md +82 -25
- package/skills/controllerai-runs/references/debugging.md +24 -22
- package/skills/controllerai-start/SKILL.md +63 -35
- package/skills/controllerai-start/references/mcp-tool-map.md +22 -21
- package/skills/controllerai-template-setup/SKILL.md +132 -0
- package/skills/controllerai-template-setup/agents/openai.yaml +4 -0
- package/skills/controllerai-triggers/SKILL.md +113 -16
- package/skills/controllerai-triggers/references/lifecycle.md +36 -48
- package/skills/controllerai-workflows/SKILL.md +105 -25
- package/skills/controllerai-workflows/references/command-map.md +20 -44
- package/skills/manifest.json +96 -136
- package/skills-mcp/controllerai-agents/SKILL.md +121 -0
- package/skills-mcp/controllerai-agents/references/instructions-and-versioning.md +76 -0
- package/skills-mcp/controllerai-ai-nodes/SKILL.md +91 -0
- package/skills-mcp/controllerai-ai-nodes/references/selection-and-testing.md +66 -0
- package/skills-mcp/controllerai-data/SKILL.md +116 -0
- package/skills-mcp/controllerai-data/references/data-rails.md +43 -0
- package/skills-mcp/controllerai-expressions/SKILL.md +97 -0
- package/skills-mcp/controllerai-expressions/references/dsl-and-recipes.md +136 -0
- package/skills-mcp/controllerai-flow-control/SKILL.md +112 -0
- package/skills-mcp/controllerai-flow-control/references/patterns.md +82 -0
- package/skills-mcp/controllerai-integration-actions/SKILL.md +90 -0
- package/skills-mcp/controllerai-node-config/SKILL.md +106 -0
- package/skills-mcp/controllerai-node-config/references/prop-and-readiness.md +49 -0
- package/skills-mcp/controllerai-runs/SKILL.md +87 -0
- package/skills-mcp/controllerai-runs/references/debugging.md +53 -0
- package/skills-mcp/controllerai-start/SKILL.md +82 -0
- package/skills-mcp/controllerai-start/references/mcp-tool-map.md +177 -0
- package/skills-mcp/controllerai-template-setup/SKILL.md +10 -0
- package/skills-mcp/controllerai-triggers/SKILL.md +109 -0
- package/skills-mcp/controllerai-triggers/references/lifecycle.md +59 -0
- package/skills-mcp/controllerai-workflows/SKILL.md +108 -0
- package/skills-mcp/controllerai-workflows/references/command-map.md +1 -0
- package/skills-mcp/manifest.json +200 -0
- package/skills/controllerai-agents/references/command-reference.md +0 -205
- package/skills/controllerai-ai-nodes/references/command-reference.md +0 -98
- package/skills/controllerai-data/references/command-reference.md +0 -177
- package/skills/controllerai-expressions/references/command-reference.md +0 -166
- package/skills/controllerai-flow-control/references/command-reference.md +0 -171
- package/skills/controllerai-integration-actions/references/command-reference.md +0 -118
- package/skills/controllerai-node-config/references/command-reference.md +0 -186
- package/skills/controllerai-runs/references/command-reference.md +0 -113
- package/skills/controllerai-triggers/references/command-reference.md +0 -215
- package/skills/controllerai-workflows/references/command-reference.md +0 -118
|
@@ -1,32 +1,122 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: controllerai-node-config
|
|
3
|
-
description: Discover
|
|
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
|
-
#
|
|
7
|
+
# Node configuration
|
|
7
8
|
|
|
8
|
-
|
|
9
|
+
## Use this when
|
|
9
10
|
|
|
10
|
-
|
|
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
|
-
|
|
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
|
-
|
|
16
|
+
## How it works
|
|
15
17
|
|
|
16
|
-
|
|
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.
|
|
17
19
|
|
|
18
|
-
|
|
19
|
-
2. Bind a required connection. Use `connection_connect_url` only when the user needs to connect an account; never request provider credentials in chat.
|
|
20
|
-
3. Set selectors first, reload properties with `node_prop_list`, then read the resulting schema.
|
|
21
|
-
4. Enable optional fields before setting them. Omission and an enabled empty value can have different effects, especially for updates.
|
|
22
|
-
5. Set literal properties with `value`; use `js` for computed values. Read `expr_context` for expected types and available inputs.
|
|
23
|
-
6. Wire the source output channel to the destination. Use returned output/port IDs; “main” and “error” are distinct channels.
|
|
24
|
-
7. Inspect `node_status` and `node_get`, test the step or complete flow, then verify the saved output type and downstream mapping.
|
|
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.
|
|
25
21
|
|
|
26
|
-
|
|
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.
|
|
27
23
|
|
|
28
|
-
|
|
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.
|
|
29
25
|
|
|
30
|
-
|
|
26
|
+
## Rules
|
|
31
27
|
|
|
32
|
-
|
|
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.
|
|
37
|
+
|
|
38
|
+
## Recipes
|
|
39
|
+
|
|
40
|
+
### Find the component
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
cai integration actions "<capability>" --json
|
|
44
|
+
cai integration action --integration <nodeSlug> --key <key> --json
|
|
45
|
+
```
|
|
46
|
+
|
|
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.
|
|
48
|
+
|
|
49
|
+
### Resolve the account
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
cai connection list --integration <nodeSlug> --json
|
|
53
|
+
```
|
|
54
|
+
|
|
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.
|
|
56
|
+
|
|
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.
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
cai node set-connection <nodeId> --connection <connectionId> --json
|
|
61
|
+
cai node status <nodeId> --json
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Add the node
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
cai node add --flow <flowId> --node <nodeSlug> --key <key> --name "<data this node produces>" --connection <connectionId> --after <upstreamNodeId> --json
|
|
68
|
+
```
|
|
69
|
+
|
|
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.
|
|
71
|
+
|
|
72
|
+
### Follow readiness
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
cai node status <nodeId> --json
|
|
76
|
+
cai node props <nodeId> --json
|
|
77
|
+
```
|
|
78
|
+
|
|
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.
|
|
80
|
+
|
|
81
|
+
### Set a prop
|
|
82
|
+
|
|
83
|
+
```bash
|
|
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>
|
|
89
|
+
```
|
|
90
|
+
|
|
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`.
|
|
92
|
+
|
|
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`.
|
|
94
|
+
|
|
95
|
+
### Wire
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
cai node connect --flow <flowId> --from <sourceNodeId> --to <targetNodeId> --output main --json
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
`--output error` is only for the automatic error path. Router and If/Else outputs use branch connections from `controllerai-flow-control`.
|
|
102
|
+
|
|
103
|
+
### Resolve the output type
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
cai run node <nodeId> --inputs '<json>' --json
|
|
107
|
+
cai node declare-output <nodeId> --sample-file - --json
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
`--inputs` and `--sample-file` also take a file path; `--sample-file -` reads the documented response from stdin.
|
|
111
|
+
|
|
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.
|
|
113
|
+
|
|
114
|
+
## Verify
|
|
115
|
+
|
|
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.
|
|
117
|
+
|
|
118
|
+
## Report
|
|
119
|
+
|
|
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.
|
|
121
|
+
|
|
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`
|
|
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.
|
|
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.
|
|
12
|
-
- `outputTypeStatus`: `concrete`, `unresolved
|
|
13
|
-
- `readyForExpressions`: connection and required/reload props
|
|
14
|
-
- `readyForRun`:
|
|
15
|
-
- `readyForDownstreamExpressions`:
|
|
16
|
-
- `next`: the
|
|
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
|
-
|
|
19
|
+
`cai node set` picks the channel from live metadata; the readback shows it as a decompiled view:
|
|
34
20
|
|
|
35
|
-
| Intent |
|
|
21
|
+
| Intent | Input | Readback view |
|
|
36
22
|
| --- | --- | --- |
|
|
37
|
-
| Static text, JSON text, scalar, object
|
|
38
|
-
| Dynamic text, JSON text
|
|
39
|
-
| Dynamic non-text prop
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
@@ -1,41 +1,98 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: controllerai-runs
|
|
3
|
-
description:
|
|
3
|
+
description: Run Controller AI nodes and flows and read execution evidence: inputs, resolved configs, outputs, ports, skips, warnings and output-type adoption. Use when proving a build works, investigating a failed or green-but-wrong run, resolving a dynamic output type, or checking what an expression produced at runtime.
|
|
4
4
|
---
|
|
5
|
+
<!-- generated from .claude/skills by cli/scripts/render-skills.mjs; edit the source -->
|
|
5
6
|
|
|
6
|
-
#
|
|
7
|
+
# Runs
|
|
7
8
|
|
|
8
|
-
|
|
9
|
+
## Use this when
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
- A node or flow was just built or changed and needs proof with real values.
|
|
12
|
+
- A run failed, or finished green with empty, partial or wrong data.
|
|
13
|
+
- A dynamic node's output type is unknown and downstream expressions cannot be written.
|
|
11
14
|
|
|
12
|
-
|
|
13
|
-
- Run a **flow** to verify connected steps and the return contract. Choose development or the published live version explicitly.
|
|
14
|
-
- Test an **agent conversation** to verify its tool choice and file handling, then correlate workflow calls with their executions.
|
|
15
|
-
- Replay a **trigger sample** into development to verify event-to-flow mapping before enabling live behavior.
|
|
15
|
+
Expression authoring belongs to `controllerai-expressions`, branch and loop structure to `controllerai-flow-control`, trigger replay to `controllerai-triggers`.
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
## How it works
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
**A run is real.** Node runs always execute on development; flow runs execute on development by default or, explicitly, on the published live version. Both call the real providers: messages send, records change, usage is spent. Development isolation covers the workflow data store only.
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
**Running resolves types.** A dynamic integration node gets its output type from one completed representative run (`outputTypeAdoption`), and every downstream expression depends on that type. When the user declines to run a consequential action, the fallback is a declared output contract built from the provider's documented response; it is marked `declared (unverified)` and the first real completed run verifies it.
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
**Three scopes.** A node run isolates the node's own configuration and does not execute wired upstream nodes; `runScope.endToEndValidationRequired` is computed from the wiring before the run and says that upstream-derived values need a containing-flow check, while `resolvedConfigs` shows what they actually were. A flow run executes the wiring and proves `inputs.<name>` expressions and the return contract. A discovery run creates a scratch node from a component that is not in the graph inside a reusable scratch flow, executes it and deletes the node (the flow stays), only to learn what it returns; it types nothing in the real flow.
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
**Inputs are keyed by ID.** `run inputs` lists the exact input IDs a node or flow reads. A flow lists every declared input with a `used` flag: supply the used ones (an omitted used input falls back to its saved test value), and values for unused inputs are accepted and ignored. An isolated node run must receive every referenced `flowInputs[].id` or it fails before executing with `ISOLATED_FLOW_CONTEXT_REQUIRED`. Explicit `null`, `""`, `false` and `0` are supplied values; dates are plain ISO-8601 text.
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
**The evidence.** `status` and `errorMessage`; `skipReason` (`only_when_false`, `upstream_skipped`); `runScope`; `resolvedConfigs`, where a null entry on a dynamic prop that the contract did not intend is a silent expression failure on an otherwise green run, and each entry's `resolutionWarnings` (an explicit `[]` means the resolver reported nothing; the value still has to match the contract); the output shape and values; and the adoption result, `outputTypeAdoption` on a node run or `outputTypeAdoptions` on a flow run, where `adopted` or `already_typed` lets the node status converge, `no_observed_output` means the run returned no reusable shape, and each entry's `adoptedNodeIds` must be empty or name only its own node.
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
| --- | --- |
|
|
31
|
-
| Missing required config | Selector choice, refreshed props, enabled fields and literal/expression mode |
|
|
32
|
-
| Unknown field/binding | Node expression context, exact connection output and current input binding |
|
|
33
|
-
| Empty query | Record environment, field key, optional-filter handling and matching semantics |
|
|
34
|
-
| Provider authentication failure | Connection identity and provider error code; saved active status is not a fresh credential test |
|
|
35
|
-
| Green run but no useful output | Return-node mappings, skipped branches and resolved empty values |
|
|
36
|
-
| Mutation result too large or uncertain | Download/reference receipt and exact current target state before retrying |
|
|
37
|
-
| Graph changed unexpectedly | Saved-state history and current node/edge identities; do not replace a newer graph with a cached copy |
|
|
29
|
+
**Outcomes.** A run ends `completed`, `completed_with_error` (a handled error path, the expected result when testing continue-on-error), `failed` or `cancelled`; it can also stop `paused` waiting on something, or still be running when the wait ends. The CLI polls until a terminal status, a pause or its `--timeout` (milliseconds); a non-success result exits non-zero and carries the execution ID and last snapshot in `error.detail`. A running or paused status means inspect that execution later, never dispatch the run again.
|
|
38
30
|
|
|
39
|
-
|
|
31
|
+
## Rules
|
|
40
32
|
|
|
41
|
-
|
|
33
|
+
1. **Mitigate, do not refuse.** Before a send, delete, charge or people-affecting run, say what will really happen and agree a safe target: the user's own address or channel, a record created for the test, a person the user names. Reuse authorization the task already gave; ask only for what it did not cover.
|
|
34
|
+
2. **A declined run is declared, not skipped.** Declare the output from the provider's documented response, say it is unverified, and name the first real run as the verification step.
|
|
35
|
+
3. **Smallest scope first, then the containing flow.** A node run proves configuration; only a flow run proves upstream-derived values and the return value.
|
|
36
|
+
4. **Green is not proof, and red is not always failure.** Read resolved configs, outputs, ports and skips; a `completed` run with empty or null output is a failure until the values are read and explained, a null dynamic config the contract did not intend is a failure even when the status is green, and a run that matched the scenario's expected status, outputs and effects passed even when that status is `completed_with_error`. `0` and `false` are values.
|
|
37
|
+
5. **Find the first divergence, not the last error.** Walk the execution tree, classify each node as completed, failed, skipped on purpose, skipped unexpectedly or absent; later failures are usually consequences.
|
|
38
|
+
6. **Verify the effect where it lives.** Data writes: query the same store. Files: open the artifact. Provider actions: the provider's result, not the execution ID.
|
|
39
|
+
7. **Never let a stalled run become a duplicate.** Inspect the returned execution; rerun only after it reached a terminal state and the cause is understood.
|
|
40
|
+
8. **Adoption stays on the tested node.** Stop if `adoptedNodeIds` names a sibling, and re-read `node status` and downstream expression contexts after a type is adopted.
|
|
41
|
+
|
|
42
|
+
## Recipes
|
|
43
|
+
|
|
44
|
+
### Prepare inputs and run
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
cai run inputs <nodeId> --json
|
|
48
|
+
cai run inputs <flowId> --flow --json
|
|
49
|
+
cai run node <nodeId> --inputs <values.json> --json
|
|
50
|
+
cai run flow <flowId> --inputs <values.json> --json
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
`--inputs` takes inline JSON, a file path or `-` for stdin; the value is a flat map of input ID to value. `--timeout <ms>` bounds the wait.
|
|
54
|
+
|
|
55
|
+
### Declare an output the user will not run yet
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
cai node declare-output <nodeId> --sample-file <shape.json>
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
The sample is a representative response object (or a non-empty array of them) taken from the provider's API reference.
|
|
62
|
+
|
|
63
|
+
### Discover what a component returns
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
cai run discover --node <nodeSlug> --key <componentKey> --connection <connectionId|none> --props '<json>' --json
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`--connection` is required (`none` for a component without auth); `--enable <prop>` enables optional props first; `--keep` retains the scratch node only when the user wants it.
|
|
70
|
+
Discovery calls the real action and spends usage. Never probe a destructive action just to learn its output: agree a safe target or declare the shape instead. Prefer testing a configured node: discovery returns `observedOutputType`, `nodeExecution`, `workflowExecutionId`, `scratchFlowId` and `nodeDeleted`, the full execution stays readable by ID, and the real node in the flow still has to be typed by its own run or a declaration.
|
|
71
|
+
With `--keep` the scratch node stays as well.
|
|
72
|
+
|
|
73
|
+
### Verify the published version
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
cai run flow <flowId> --inputs <values.json> --target live --confirm-live --json
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
When the user authorized live verification and named a safe target, run the published flow once under supervision instead of waiting for a real trigger event. It fires real actions and spends usage. Where the design calls for it, a safe-audience harness (an If/Else on `isLiveVersion` whose false branch targets the developer and whose true branch targets the real audience) protects development runs; the live run is still a real send, and adding that harness is a design change to agree, not a test step.
|
|
80
|
+
|
|
81
|
+
### Read the execution
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
cai exec tree <workflowExecutionId> --limit 50 --json
|
|
85
|
+
cai exec get <workflowExecutionId> --json
|
|
86
|
+
cai exec flow <flowExecutionId> --json
|
|
87
|
+
cai exec node <nodeExecutionId> --full --json
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Page the tree with the returned `nextCursor` (`--cursor`) and narrow a large run with repeatable `--status` or an exact `--flow <flowId>`. The tree locates the first unexpected status; the full node execution holds the resolved configuration and the untruncated output. Read [references/debugging.md](references/debugging.md) for the fault-isolation order and the symptom table.
|
|
91
|
+
|
|
92
|
+
## Verify
|
|
93
|
+
|
|
94
|
+
The run exercised the changed path with credible values; the first unexpected node, if any, was identified from the tree; every dynamic config resolved to the intended value and `resolutionWarnings` were read; the output shape and values match what downstream expects; skips are intentional and error paths accounted for; a flow run reached the scenario's expected status, outputs and effects after isolated fixes; the stored or external effect was checked where it lives; and any declared contract is still marked unverified in the report.
|
|
95
|
+
|
|
96
|
+
## Report
|
|
97
|
+
|
|
98
|
+
What ran and on which version, the execution IDs, what each run proved, what is declared but unverified, and what remains untested and why.
|
|
@@ -1,17 +1,16 @@
|
|
|
1
|
+
<!-- generated from .claude/skills by cli/scripts/render-skills.mjs; edit the source -->
|
|
1
2
|
# Execution debugging
|
|
2
3
|
|
|
3
4
|
Use this order; it avoids changing a downstream node when the defect is upstream.
|
|
4
5
|
|
|
5
|
-
## 1. Confirm
|
|
6
|
+
## 1. Confirm the version and the graph
|
|
6
7
|
|
|
7
8
|
```bash
|
|
8
9
|
cai workflow status --json
|
|
9
10
|
cai flow get <flowId> --json
|
|
10
11
|
```
|
|
11
12
|
|
|
12
|
-
Node runs use development. Flow runs
|
|
13
|
-
|
|
14
|
-
MCP: `run_flow` takes `waitSeconds` and may return before the execution is terminal.
|
|
13
|
+
Node runs use development. Flow runs use development unless the published version was selected explicitly. Every run can call real providers.
|
|
15
14
|
|
|
16
15
|
## 2. Find the first divergence
|
|
17
16
|
|
|
@@ -19,9 +18,7 @@ MCP: `run_flow` takes `waitSeconds` and may return before the execution is termi
|
|
|
19
18
|
cai exec tree <workflowExecutionId> --limit 50 --json
|
|
20
19
|
```
|
|
21
20
|
|
|
22
|
-
Follow `nextCursor` with `--cursor
|
|
23
|
-
run is large. Classify each node as completed, failed, skipped intentionally, skipped unexpectedly,
|
|
24
|
-
or absent. The first divergence is usually the cause; later failures are often consequences.
|
|
21
|
+
Follow `nextCursor` with `--cursor`; use repeatable `--status` or an exact `--flow <flowId>` on a large run. Classify each node as completed, completed with a handled error, failed, cancelled, paused, skipped on purpose (`only_when_false`), skipped unexpectedly (`upstream_skipped` behind a failure or a wrong branch), or absent. The first divergence is usually the cause; later failures are consequences.
|
|
25
22
|
|
|
26
23
|
## 3. Inspect the node boundary
|
|
27
24
|
|
|
@@ -29,29 +26,34 @@ or absent. The first divergence is usually the cause; later failures are often c
|
|
|
29
26
|
cai exec node <nodeExecutionId> --full --json
|
|
30
27
|
```
|
|
31
28
|
|
|
32
|
-
|
|
29
|
+
In order:
|
|
33
30
|
|
|
34
|
-
1. Resolved configs: did each expression resolve, and to the
|
|
35
|
-
2.
|
|
36
|
-
3.
|
|
37
|
-
4.
|
|
31
|
+
1. Resolved configs: did each expression resolve, and to the right type and value? A null entry on a dynamic prop that the contract did not intend is the failure even when the node is green; read each entry's `resolutionWarnings`.
|
|
32
|
+
2. Port: did the node select the branch or output the test expected?
|
|
33
|
+
3. Output: did the component return the promised shape and values? Compare a flow's return with its declared outputs.
|
|
34
|
+
4. Status and error: did the provider or the engine reject the call?
|
|
35
|
+
5. Upstream rows and wiring: did every expected producer run and connect to this node?
|
|
38
36
|
|
|
39
|
-
## 4. Fix by
|
|
37
|
+
## 4. Fix by symptom
|
|
40
38
|
|
|
41
|
-
|
|
|
39
|
+
| Symptom | Inspect next |
|
|
42
40
|
| --- | --- |
|
|
43
|
-
| Missing
|
|
44
|
-
| Null dynamic config | Expression binding, field path, or missing source value |
|
|
45
|
-
| Invalid option
|
|
41
|
+
| Missing or wrong input | Wiring, branch connection, or the test input ID |
|
|
42
|
+
| Null dynamic config | Expression binding, field path, or a missing source value |
|
|
43
|
+
| Invalid option or account | Node connection, dependency-ordered props, or a stale option |
|
|
46
44
|
| Provider error | Integration configuration, credentials, quota, or payload |
|
|
47
45
|
| Green node, wrong output | Component choice, output contract, or prompt |
|
|
48
|
-
| Unexpected skip |
|
|
46
|
+
| Unexpected skip | Guard, branch condition or order, or an upstream failure |
|
|
47
|
+
| Empty record query | Store (development versus live), field key, optional-filter semantics |
|
|
48
|
+
| Provider authentication failure | Connection identity and the provider's error; an active status is not a fresh credential test |
|
|
49
|
+
| Return value empty | Return node bindings, skipped branches, or resolved empty values |
|
|
49
50
|
|
|
50
|
-
Re-read metadata
|
|
51
|
+
Re-read metadata and contexts before editing. Rerun the smallest failed scope, then the full flow.
|
|
51
52
|
|
|
52
53
|
## 5. Avoid false confidence
|
|
53
54
|
|
|
54
55
|
- A compile pass does not prove runtime data exists.
|
|
55
|
-
- A node pass does not prove downstream mapping:
|
|
56
|
-
- A
|
|
57
|
-
- A top-level completed status does not prove every intended branch ran.
|
|
56
|
+
- A node pass does not prove downstream mapping: a node run does not execute wired upstream nodes.
|
|
57
|
+
- A development pass does not prove live data or the live release state.
|
|
58
|
+
- A top-level completed status does not prove every intended branch ran, and a loop's success does not prove every iteration.
|
|
59
|
+
- Keep the evidence of failed runs and separate it clearly from the final verified result; broaden the test when a fix changes shared behavior.
|