Use the CLI
How do you run commands against the right account and workflow? Install cai in the assistant’s terminal, then confirm which account it is signed in to. This page pins the workflow with cai use <workflowId>. Every scoped command after that assumes the pin, in the same directory, with no CAI_WORKFLOW override.
This page documents CLI 0.2.24. For host installation, read Choose your setup. For an assistant that calls typed tools, read Remote MCP.
Install a command that stays available
Section titled “Install a command that stays available”In the app, open Connect for assistant setup instructions. Commands on this page run in your local terminal. The package needs Node.js 20 or newer and installs the cai executable. Install it globally, then print the version:
npm install -g @controllerai/cli@0.2.24cai --versionA one-off package run can leave authorization and skills behind without leaving cai installed. Before handing work to another terminal session, check that the durable command is there.
The in-product builder already has managed credentials, the CLI, and bundled skills. If a runtime component is missing, it must report that instead of installing packages, connecting an account, or upgrading itself.
Confirm the account first
Section titled “Confirm the account first”With an assistant, connect, then read the account and the local setup back:
cai connect --jsoncai auth status --jsoncai doctor --jsonconnect updates skills first. It then reuses a valid credential or starts browser authorization, and it checks the setup last. If the network fails while it is checking an existing credential, it does not start another login on its own. Finish authorization through the returned browser link. On a remote terminal, cai connect --no-open --json prints that link without opening a browser.
In auth status, read the account identity, the backend URL, the credential kind, and data.expiresAt. It warns when the stored expiry is past, malformed, or less than seven days away. Before a long task, run cai auth login --json to renew. Do not infer the terminal’s account from your browser session. In doctor, read every check and version row. A finished report does not mean every component is current. A workflow pin of none is valid.
For MCP, the matching check is account_status with {}. It reports the authenticated remote account, without inspecting your local installation.
Keep Invoice intake selected
Section titled “Keep Invoice intake selected”In the app, open Workflows and select Invoice intake, the example workflow from Your first workflow. With an assistant, list the workflows first and find the same one:
cai workflow list --jsonThe result contains data.items and data.hasMore. The default limit is 25. Find the Invoice intake you mean in data.items, check its identity, and note its id. The commands below use that value as <workflowId>. If data.hasMore is true and the workflow is not in the list, raise --limit and list again. Read the workflow, pin it to this directory, then confirm the pin:
cai workflow get --workflow <workflowId> --jsoncai use <workflowId> --jsoncai doctor --jsoncai use checks the workflow, then writes its ID to the global config and to .cai.json in the current directory. Reserve .cai.json for cai. That write replaces everything in the file with only workflowId. Pinning changes local command context, not the workflow definition. Check the returned name and localPinPath.
| Priority | Selection source | Where it applies |
|---|---|---|
| 1 | --workflow | This command. |
| 2 | CAI_WORKFLOW | Commands inheriting that environment variable. |
| 3 | .cai.json | The exact current directory; parent directories are not searched. |
| 4 | Global config | The fallback saved workflow. CAI_CONFIG selects the config file, not a workflow. |
Two directories keep their own local selections even when another session changes the global fallback. Sessions in the same directory share that directory’s pin. An explicit flag makes the target clear.
cai config reset --local --json clears the directory selection. If the local file is malformed, it is deleted. Without a scope flag, reset clears both saved selections and leaves credentials in place. If the global JSON is malformed, an all-scope reset stops before either pin changes. Reset cannot unset CAI_WORKFLOW in the parent shell.
Remote calls have no saved selection. The inventory and read tools are workflow_list and workflow_get. Pass the selected ID to workflow_get as workflowId.
Read the whole result
Section titled “Read the whole result”Every command accepts --json before or after its command path. A successful action returns ok, command, and data. Most failures return ok: false and an error object. Warnings appear on stderr and in the JSON warnings array. Read them before you pull out a single field. workflow validate --json is the exception to that failure format. Invalid output exits 1 with ok: true and data.valid: false.
Browser authorization can emit an authorization_required event before the final result. Read those events as they arrive so the person gets the link. When events come first, the final result is the last line of stdout. Ordinary JSON results span several lines.
Before passing a flag you are unsure about, read that command’s help:
cai --helpcai run flow --helpcai agent add-file --helpFile forms and wait units differ from command to command. run flow --inputs accepts inline JSON, a file, or - for stdin. Its --timeout is in milliseconds and defaults to 300000. connect --timeout is in seconds. agent add-file --file reads a local UTF-8 file. The CLI reference lists each contract.
Keep an execution’s identity
Section titled “Keep an execution’s identity”Before you run the Check invoice example, look at the flow and the inputs it accepts. In the app, open the flow and use Test current flow. With an assistant, use the workflow pinned above and list its flows:
cai flow list --jsonFind Check invoice in data.items and note its id as <flowId>. Then read back the inputs that flow accepts:
cai run inputs <flowId> --flow --jsonThe readback gives you the accepted IDs and display names. Check that the example’s Invoice ID and Amount inputs exist before using those values.
For MCP, run_inputs takes nodeIdOrFlowId, flow: true, and workflowId.
Use the pure flow from the first-workflow guide. If you have added provider actions, work out their real destinations before you test. Development mode does not suppress them. Once the inputs check out, run the example:
cai run flow <flowId> --target dev \ --inputs '{"Invoice ID":"INV-104","Amount":120}' --jsonIn the result, read data.workflowExecutionId, data.status, data.nodeExecutions, and data.output. Under the example’s rule, expect invoice INV-104 without a review requirement. For MCP, run_flow takes flowId, workflowId, and parsed inputs. Remote MCP covers its shorter wait contract.
Only completed counts as success in the CLI. A paused run, another terminal status, or a timeout exits 1. WORKFLOW_EXECUTION_PAUSED, WORKFLOW_EXECUTION_FAILED, and WORKFLOW_EXECUTION_TIMEOUT carry error.detail.workflowExecutionId and lastSnapshot. Note that ID as <workflowExecutionId>, then read the execution you already have instead of dispatching another one:
cai exec get <workflowExecutionId> --jsonFor MCP, execution_get takes workflowExecutionId and workflowId.
Fetch the page you need
Section titled “Fetch the page you need”Pull the docs index or one page into the session as Markdown:
cai docscai docs --listcai docs for-ai-agents/cli --jsonWithout a path, cai docs fetches the assistant hub. --list fetches llms.txt, and a page path fetches that page’s .md representation. JSON output includes path, url, and markdown. Pass a docs path, not a full URL or an anchor. A path and --list cannot be combined.
Decide whether to retry
Section titled “Decide whether to retry”| Exit | Meaning | Next action |
|---|---|---|
0 | Command succeeded. | Inspect the returned data. |
1 | User, action, validation, or unexpected local error. | Inspect error.code; follow a dispatched execution by its ID. |
2 | Write conflict. | Read current state before retrying the edit. |
3 | Authentication or authorization error. | Check the returned authentication guidance. |
4 | Transport, server, protocol-response, or approval-poll error. | Inspect the existing resource before retrying a write. |
A lost response does not prove that a create failed. Read back the returned ID or the inventory before creating the object again. Development runs can send real messages and change provider records, so a retry can repeat those effects.
If a managed browser approval is interrupted or times out, keep error.detail.approvalId. Use it as <id> in cai approval resume <id> --json rather than rerunning the original command. Security explains the separate approval mechanisms.
Update the executable and skills separately
Section titled “Update the executable and skills separately”cai upgrade --json refreshes skills for the assistants it detects, and prints the CLI installation command. It reports selfModified: false, because it does not replace its own running executable. Run the printed command yourself, then check cai --version and cai doctor --json. For skill versions, retained copies, and plugin updates, continue to Skills and updates.
In the app, Settings → Connected sessions manages the CLI sessions for this Controller AI account. Local logout and server revocation do different things. Follow the security guide.