Skip to content

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.

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:

Terminal window
npm install -g @controllerai/cli@0.2.24
cai --version

A 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.

With an assistant, connect, then read the account and the local setup back:

Terminal window
cai connect --json
cai auth status --json
cai doctor --json

connect 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.

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:

Terminal window
cai workflow list --json

The 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:

Terminal window
cai workflow get --workflow <workflowId> --json
cai use <workflowId> --json
cai doctor --json

cai 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.

PrioritySelection sourceWhere it applies
1--workflowThis command.
2CAI_WORKFLOWCommands inheriting that environment variable.
3.cai.jsonThe exact current directory; parent directories are not searched.
4Global configThe 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.

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:

Terminal window
cai --help
cai run flow --help
cai agent add-file --help

File 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.

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:

Terminal window
cai flow list --json

Find Check invoice in data.items and note its id as <flowId>. Then read back the inputs that flow accepts:

Terminal window
cai run inputs <flowId> --flow --json

The 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:

Terminal window
cai run flow <flowId> --target dev \
--inputs '{"Invoice ID":"INV-104","Amount":120}' --json

In 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:

Terminal window
cai exec get <workflowExecutionId> --json

For MCP, execution_get takes workflowExecutionId and workflowId.

Pull the docs index or one page into the session as Markdown:

Terminal window
cai docs
cai docs --list
cai docs for-ai-agents/cli --json

Without 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.

ExitMeaningNext action
0Command succeeded.Inspect the returned data.
1User, action, validation, or unexpected local error.Inspect error.code; follow a dispatched execution by its ID.
2Write conflict.Read current state before retrying the edit.
3Authentication or authorization error.Check the returned authentication guidance.
4Transport, 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.