Skip to content

CLI reference

The complete cai command surface — 23 command groups, 162 subcommands (@controllerai/cli, requires Node 20+). The CLI is in beta: releases are frequent, and this reference tracks the latest. cai <group> --help is always current for your installed version, and cai doctor tells you when a newer CLI exists.

These apply to every command in the tree and are not repeated in the per-command tables.

FlagWhat it does
--jsonMachine-readable output on stdout. Declared on every command, so it works before or after the subcommand (cai --json flow list and cai flow list --json are equivalent).
--workflow <id>Workflow id; overrides cai use and CAI_WORKFLOW. Declared on every command.
--id <value>Positional id, for ids that begin with -. Root-level only, but applies to any command that takes a positional id — the value is lifted out of argv and re-appended after a -- terminator, so it reaches the action as the positional it always was. Ids are 12 chars from a URL-safe 64-symbol alphabet that includes -, so roughly 1 id in 64 needs this. A bare --leading token that has id shape and is not a declared flag is also rescued automatically.
-V, --versionPrint the CLI version.
-h, --helpPrint help. --showHelpAfterError is on, so usage errors print help.

JSON envelope. All commands print through a single emit() helper (src/output.ts), so --json is supported everywhere with a stable shape:

{ "ok": true, "command": "cai flow list", "data": { }, "warnings": [""] }
{ "ok": false, "command": "cai flow list", "error": { "code": "", "message": "", "scrubbed": true, "detail": {} } }

warnings is present only when the command emitted warnings (warnings also go to stderr, so --json stdout stays pipeable).

NDJSON progress events. Only the browser-authorization path emits them — cai auth login and cai connect (both call runDeviceLogin). In --json mode they write one NDJSON line before the envelope:

{"event":"authorization_required","url":"","userCode":"","expiresInSeconds":600,"instruction":""}

Consumers parse the last stdout line as the result; event lines always carry an event key. When events were emitted the envelope itself is printed as a single unindented line.

Exit codes (part of the contract, src/errors.ts): 0 ok, 1 user/validation, 2 conflict (OCC), 3 auth, 4 network.


One-shot onboarding: install skills, authorize the machine, then verify the whole setup and fail if any required check is red.

CommandArgumentsKey flagsWhat it does
cai connect--target <target> (default auto; auto, agents, codex, claude, cursor, copilot, all, or project), --project-dir <path>, --force (default false), --no-open, --timeout <seconds>Runs skills update, then device-login if the stored credential is missing or rejected, then doctor, and hard-fails unless Node.js, Credential, Controller AI API, and Credential file all pass (CONNECT_VERIFICATION_FAILED). Emits NDJSON authorization_required in --json mode when it has to authorize. Warns when run transiently via npx. Returns skill inventory, entry skill paths, and the doctor checks. ⚠ --force replaces existing unmanaged Controller AI skill folders on disk.

Authenticate this machine with Controller AI; the credential is stored locally and can be revoked.

CommandArgumentsKey flagsWhat it does
cai auth login--no-open, --timeout <seconds>Opens a browser and authorizes a revocable CLI credential via the device-code flow, then persists it. Prints the URL + verification code on stderr and, in --json mode, as an NDJSON authorization_required event. The terminal never handles the password.
cai auth password--email <email> (required), --password <password> (required)Development fallback: exchanges explicit email/password flags for a JWT.
cai auth token--token <token> (required)Persists a credential you already hold (cai_, JWT, or sk- API key). Kind is detected from the prefix.
cai auth key--name <name> (default cai)Migration/dev only: mints a legacy API key using a browser JWT.
cai auth logout--revoke (default false)Removes the locally stored credential. ⚠ --revoke also revokes the CLI credential server-side before removing it locally — other machines using the same credential lose access.
cai auth statusShows the current account, backend, credential kind, and pinned workflow.

Single health check for the local setup.

CommandArgumentsKey flagsWhat it does
cai doctorVerifies Node.js >= 20, a stored credential, live API access (/user/me), installed skills per target, the CLI version against the release feed (advisory only, never fails), and that the credential file is mode 0600. Exits non-zero (DOCTOR_FAILED) if Node.js, Credential, or Controller AI API fail.

Install and update the Controller AI guidance skill set that coding agents read.

CommandArgumentsKey flagsWhat it does
cai skills install--target <target> (default auto), --project-dir <path>, --force (default false)Installs the verified skill set bundled with this CLI (offline, no network).
cai skills update--target <target> (default auto), --project-dir <path>, --force (default false)Fetches, verifies, and installs the latest hosted skill set; falls back to retaining what is already on disk when the feed is unreachable.
cai skills status--target <target> (default all), --project-dir <path>Verifies installed skills, versions, and digests per target; reports current / drifted / missing.

--target accepts exactly: auto, agents, codex, claude, cursor, copilot, all, project. ⚠ --force on install/update replaces an existing unmanaged skill folder with the same name.

Pin a default workflow so --workflow can be omitted.

CommandArgumentsKey flagsWhat it does
cai use<workflowId>Verifies the workflow exists and is yours, then writes it to the global config and to ./.cai.json in the current directory. The directory pin wins over the global pin, so parallel agent sessions in different project directories cannot steal each other’s target. Also caches the current dev head state id.

Workflow-level lifecycle: create, organize, snapshot, restore, validate, publish.

CommandArgumentsKey flagsWhat it does
cai workflow list--limit <n> (default 25)Lists workflows (POST /workflow/list — a GET here 500s).
cai workflow create--name <name> (required)Creates a workflow and renames it (the create route ignores a name), then pins it as the default.
cai workflow get[workflowId]Fetches one workflow; adds an appUrl when the frontend base can be derived.
cai workflow rename[workflowId]--name <name> (required)Renames a workflow (PATCH /workflow/:id).
cai workflow describe[workflowId]--description <text> (required)Sets the workflow description ("" clears it).
cai workflow move[workflowId]--folder <id|none> (required)Moves the workflow into a folder, or to the root with none.
cai workflow duplicate[workflowId]--use (default false)Copies the workflow, flows and nodes. ⚠ Warns that the copy has empty data stores, is unpublished, and keeps the same flow/node ids as the source — a stale workflow context will silently edit the original.
cai workflow delete<workflowId> (required explicitly, never the pinned default)--yes (required), --force (default false)⚠ Soft-deletes the workflow after undeploying its triggers. Without --force it first checks get_resource_dependencies and refuses (WORKFLOW_HAS_AGENT_DEPENDENTS) when agents attach it as a tool — deleting detaches it from all of them and a LIVE agent changes behavior immediately. Warns that history is retained but the CLI cannot restore a deleted workflow row.
cai workflow versions[workflowId]The dev and live version rails of a workflow.
cai workflow releases[workflowId]Published release checkpoints.
cai workflow history--version <workflowVersionId>, --group <groupId>Version-state history — the ids cai workflow restore takes. Rows are either single (restorable id) or group (collapsed run of edits; expand with --group).
cai workflow restore--state <workflowVersionStateId> (required), --version <workflowVersionId>⚠ Rolls the development rail back to an earlier state — the recovery path. Warns that it does not rewind live; triggers keep running the published version until you publish again. Refreshes the cached head.
cai workflow save--name <name> (required)Saves a named development snapshot you can restore to later. The one preconditioned write in the surface (baseStateId, retry-once on 409).
cai workflow state--fullCurrent development-version head (headStateId + workflowVersionId, update reason, flow/trigger counts). --full includes the whole workflow document JSON.
cai workflow statusPublish state: active, has live version, dev-vs-live match, needs publish, trigger counts.
cai workflow validateValidates the dev workflow: unlinked subflow callers, dangling types, branches, trigger issues; returns severity/code/where/message plus a fix per issue.
cai workflow publish--name <name>, --acknowledge-dual-dispatch⚠ Publishes the dev rail to live — after this, triggers fire the new version. Rejects publish when armed test events could run one real event in both dev and live; --acknowledge-dual-dispatch overrides that, and the rejection is rewritten with concrete cai trigger test-events … --disallow recovery commands. Refreshes the cached head afterwards.

Flows are the canvases inside a workflow; a workflow has many.

CommandArgumentsKey flagsWhat it does
cai flow listLists the flows on this workflow.
cai flow get<flowId>Nodes, edges and inputs of one flow.
cai flow create--name <name> (required)Creates a new flow canvas.
cai flow rename<flowId>--name <name> (required)Renames a flow.
cai flow delete<flowId>⚠ Deletes a flow (and everything on that canvas). No confirmation flag.
cai flow outputs<flowId>Declared outputs of a flow.
cai flow duplicate<flowId>Copies a flow with fresh ids for every node and edge.
cai flow reorder--order <flowIds> (required)Reorders the workflow’s flows — presentation order, not execution order. Takes every flow id, comma-separated.
cai flow output add<flowId>--display <name> (required), --type <ctype> (required), --name <name>, --description <text>Declares an output a flow returns. ⚠ Outputs must exist before a Return response node is added — adding one later does not retro-fit an existing node’s props.
cai flow output update<flowId>--output <id> (required), --name <name>, --display <name>, --type <ctype>, --description <text>Updates a flow output; Return response props are kept in sync.
cai flow output delete<flowId>--output <id> (required)⚠ Removes a flow output; its Return response prop goes too.
cai flow input add<flowId>--type <ctype> (required), --display <name>, --name <displayName> (legacy alias for --display; does not set the JS binding), --list, --optional, --description <text>Adds a flow input. The server derives and deduplicates the frozen JS binding from the display name.
cai flow input update<flowId>--input <id> (required), --display <name>, --name <displayName> (legacy alias), --type <ctype>, --description <text>Updates a flow input. The existing JS binding stays frozen even when the display name changes.
cai flow input delete<flowId>--input <id> (required)⚠ Deletes a flow input; expressions bound to it break.
cai flow for-each--flow <flowId> (required), --from <nodeId> (required), --source-output <outputId> (required), --name <bodyFlowName> (required), --item-type <type> (required), --item-field <id:type[:display]> (repeatable), --list-js <expr>, --js-file <path|->, --list-field <path>, --max-items <n> (1..10000, default 500), --item-name <displayName>, --continue-on-errorBuilds the whole for-each pattern in one call: item flow, list wiring, loop node. The core scaffold is atomic and maxItems is verified afterwards. --source-output must be the exact opaque outputs[].id from cai node get <nodeId> --json, never a label. --list-field is mutually exclusive with --list-js/--js-file.

Nodes — search the catalog, add, configure props, wire edges.

CommandArgumentsKey flagsWhat it does
cai node search<query>--limit <n> (default 10), --actions, --eventsSearches registry + catalog nodes. Ranked by featuredWeight, not relevance.
cai node find<intent>--node <slug>, --limit <n> (default 8)Finds ranked action components and returns exact nodeSlug/nodeKey pairs.
cai node components[query]--node <slug> (required), --limit <n> (default 25)Lists a node’s action components — the --key values node add takes.
cai node add (alias cai node init)--flow <flowId> (required), --key <componentKey> (required), --node <slug>, --name <displayName>, --after <nodeId>, --output <main|error> (default main), --connection <id>, --props <jsonOrFile>, --enable-prop <names...> (variadic)Initializes a node with its known connection, upstream wiring, optional props, and values in one call. Direct values in --props become {value:…}; advanced per-prop writes pass through.
cai node component--node <slug> (required), --key <componentKey> (required)Full static prop schema for a component before adding it — no node needed.
cai node duplicate<nodeId>Copies a node into the same flow (offset position, no incoming edges). ⚠ Warns that props are copied but wiring is not, so expressions referencing an input of the original resolve against nothing on the copy.
cai node set-flow<nodeId>--flow <flowId> (required)Points a subflow node at a flow; its input props are generated from that flow’s current inputs. ⚠ Warns that a flow input added later does not appear until you re-run this.
cai node get<nodeId>Full node record: component, inputs, outputs, connection. The only place opaque outputs[].id values come from.
cai node declare-output<nodeId>--sample-file <file|-> (required; - reads stdin)Declares an unverified dynamic output contract from documented response data.
cai node props<nodeId>Visible + catalog props with current values and decompiled valueJs.
cai node status<nodeId>Deterministic configuration readiness plus the exact blockers.
cai node set<nodeId>--prop <name> (required), --value <literal>, --js <src>, --js-file <path|->, --label <labels...> (variadic), --expression (deprecated)Sets a prop, selecting and verifying the correct storage shape automatically. --value is mutually exclusive with --js/--js-file. --js is compiled server-side before writing. --label supplies live option labels for providers that do not index opaque ids. --expression is a no-op compatibility flag and warns.
cai node set-connection<nodeId>--connection <id> (required)Binds a connection to an action node.
cai node connect--from <nodeId> (required), --to <nodeId> (required), --flow <flowId> (required), --output <main|error> (default main)Wires two nodes; the source output becomes an input on the target.
cai node disconnect--edge <edgeId> (required)⚠ Removes an edge; downstream expressions that referenced the input break.
cai node only-when<nodeId>--js <expr>, --js-file <path|->, --clearSets or clears a node’s conditional-execution rule — the node runs only when the boolean expression is true. --clear is mutually exclusive with --js/--js-file.
cai node optional-props<nodeId>Lists togglable optional props.
cai node enable-prop<nodeId>--prop <name> (required)Enables an optional prop so it becomes settable.
cai node options<nodeId>--prop <name> (required), --query <q>, --page <n>Resolves remote dropdown options for a prop. --query is strongly preferred over paging.
cai node continue-on-error<nodeId>--enable, --disableIdempotently sets continue-on-error after reading the current state. The two flags are mutually exclusive.
cai node rename<nodeId>--name <displayName> (required)Renames a node; also renames its outgoing connection label.
cai node delete<nodeId>⚠ Deletes a node. No confirmation flag; edges and prop expressions that referenced it are affected.

Trigger canvases and captured events. Triggers run the LIVE version only.

CommandArgumentsKey flagsWhat it does
cai trigger listTrigger lifecycle rows: ids, development state, readiness and issues. Warns when a trigger has no recoverable numeric backendTriggerId.
cai trigger auditPre-publish trigger coverage, development dispatch, and double-run risk. ⚠ Emits a DOUBLE-RUN RISK warning per trigger armed for dev dispatch while live-active (one real event runs twice, both real, both billed) with the exact disarm command.
cai trigger get<triggerId>Full lifecycle for one trigger: capture, deployment, verification and issues.
cai trigger test-events<triggerId> (canvas trigger id)--allow, --disallow, --acknowledge-dual-run⚠ Arms or disarms ambient development test-event dispatch. Exactly one of --allow/--disallow is required. --acknowledge-dual-run is only valid with --allow and acknowledges that one real event may execute more than once. Routine tests should use cai trigger replay instead.
cai trigger search[query]--node <slug>, --limit <n> (default 20), --events-per-node <n> (default 6)Nodes that can trigger a flow, and the --event keys each one publishes.
cai trigger props--node <slug> (required), --event <eventKey> (required), --connection <id>, --configured <json|file|->, --dynamic-props-id <id>Configurable props for a trigger event; returns the dynamicPropsId to reuse for dependent dynamic props.
cai trigger options--node <slug> (required), --event <eventKey> (required), --prop <name> (required), --connection <id>, --configured <json|file|->, --dynamic-props-id <id>, --query <text>, --page <n>, --prev-context <json|file|->Resolves exact values for one trigger dropdown prop before trigger creation.
cai trigger create--flow <flowId> (required), --node <slug> (required), --event <eventKey> (required), --source-basis <basis> (required; one of explicit-in-request | user-answer | inferred-from-existing-workflow), --connection <id>, --props <json|file|->, --dynamic-props-id <id>Creates a trigger source and its canvas. A trigger targets exactly one flow. ⚠ Warns that trigger data does not flow into the target flow automatically — follow nextSteps in order — and that the trigger stays inert until cai workflow publish.
cai trigger events--trigger <backendTriggerId> (required; the NUMERIC id, not the canvas id), --limit <n> (default 5, max 50)Captured events for a trigger source, newest first, with compact payload previews.
cai trigger event<eventId>One captured event with its full payload. ⚠ Warns when the payload exceeded 8KB and the backend returned a {_truncated,totalChars,preview} preview instead of the event.
cai trigger select-event--node <triggerNodeId> (required), --event <eventId> (required)Adopts a captured event as the trigger’s sample, defining its output schema. Warns that without a dataTypeName on the event the sample is stored but downstream bindings stay untyped.
cai trigger replay--trigger <backendTriggerId> (required), --event <eventId>, --payload <json|file|->, --target <dev|live> (default dev), --confirm-live⚠ Replays through real ingestion. --event and --payload are mutually exclusive. --target live requires --confirm-live (LIVE_REPLAY_CONFIRMATION_REQUIRED) and executes the published workflow: external actions fire and usage is spent. Even DEV replay executes real external actions and spends usage.
cai trigger toggle<triggerId>⚠ Flips a trigger between enabled and disabled — a toggle, not a setter. There is no set-to-enabled tool; read cai trigger list afterwards to see which way it went.
cai trigger rename<triggerId>--name <name> (required)Renames a trigger.
cai trigger delete<triggerId>⚠ Deletes a trigger and its canvas. No confirmation flag.

The expression surface: what is in scope, whether it compiles, and how to persist it.

CommandArgumentsKey flagsWhat it does
cai expr context<nodeId>--prop <name>, --methodsMandatory before writing any --js. Lists every in-scope binding; --prop adds the destination’s expected type and mode; --methods includes the full method catalog (large).
cai expr validate<nodeId>--js <src>, --js-file <path|->, --prop <name>, --mode <text|expression|onlyWhen>Compiles an expression against the node’s real scope. Side-effect free — nothing is written.
cai expr set<nodeId>--prop <name> (required), --js <src>, --js-file <path|->Context-checks, compiles, persists to the correct channel, and verifies the readback.
cai expr ops--type <ctype> (text|number|date|list|boolean|file|custom)The method catalog: which operations exist per CType.
cai expr decompile<nodeId>--prop <name> (required)Stored AST → readable JS (reads valueJs from node props).

Workflow data store — collections and records. Dev and live stores are separate.

CommandArgumentsKey flagsWhat it does
cai data collections--env <dev|live> (default dev)Collections in one record store, with row counts. Warns when the live store is empty because the workflow was never published (publishing creates collections but never copies records).
cai data fields--type <dataType> (required)Field id ⇄ display mapping. Writes go by id, reads come back by display.
cai data query--type <dataType> (required), --env <dev|live> (default dev), --query <text>, --limit <n> (backend caps at 100), --offset <n>Records in one collection. ⚠ --query is a plain-text search over the record id, timestamps, and the serialized JSON blob — not field-aware filtering.
cai data get<recordId>--type <dataType> (required), --env <dev|live> (default dev)One record by id. A miss returns null with a warning rather than an error.
cai data create--type <dataType> (required), --fields <json|file|-> (required), --env <dev|live> (default dev)Creates a record, validated against the collection schema. Fields are keyed by field id. ⚠ --env live warns: this is the data published, triggered runs read.
cai data update<recordId>--type <dataType> (required), --fields <json|file|-> (required), --env <dev|live> (default dev)Patches a record — omitted fields are left alone. ⚠ Same live-store warning.
cai data delete<recordId>--type <dataType> (required), --env <dev|live> (default dev)⚠ Soft-deletes a record.
cai data delete-many--type <dataType> (required), --records <id,id,…>, --all, --yes, --env <dev|live> (default dev)⚠ Bulk-deletes records (REST-only — no MCP tool does bulk). --all and --records are mutually exclusive; --all requires --yes (ALL_DELETE_CONFIRMATION_REQUIRED) and warns that every record in the collection is going.
cai data import--type <dataType> (required), --file <path> (required), --env <dev|live> (default dev), --mode <dryRun|commit> (default dryRun)Imports records from a CSV (multipart REST — no MCP tool). ⚠ Defaults to dryRun (validate only); --mode commit actually writes. Warns that CSV columns match field display names, not ids — the opposite of cai data create.
cai data copy-to-live--type <dataType> (required)⚠ Copies every dev record of one collection into the live store.
cai data collection create<dataType>--display <label>, --field <id:type[:display]> (repeatable), --from-json <file|->Sugar over cai schema create — there is no create-collection backend route. Collections are synced from the workflow’s custom.* schemas, so creating the type makes the collection appear.

Per-workflow custom data types (custom.*) — the data store’s schemas.

CommandArgumentsKey flagsWhat it does
cai schema list--allEvery data type defined in this workflow. --all includes the engine-derived custom.__* integration schemas.
cai schema get<name>One data type with its field ids, displays and types.
cai schema resolve<typeId>Resolves a type id to its display name, fields, and list-ness.
cai schema create<name>--display <label>, --field <id:type[:display]> (repeatable), --from-json <file|->Creates a custom data type — this is also what creates a data collection.
cai schema update<name>--display <label>, --field <id:type[:display]> (repeatable), --from-json <file|->Replaces the whole definition, not a patch — --field replaces the entire field list. Warns per dropped field (records keep the data but it is no longer addressable) and when the type is integration-derived. Echoes the persisted shape after the write.
cai schema delete<name>--yes (required)⚠ Deletes the type, its data collection, and removes fields that referenced it. Records it held become unreachable through every CLI surface and re-creating the schema does not bring them back; expressions bound to the type resolve to an unknown type.

Router routes and If/Else branches — create, condition, wire, order.

CommandArgumentsKey flagsWhat it does
cai branch list<nodeId>Routes/branches in evaluation order, with conditions and wired targets.
cai branch add<nodeId>--name <displayName>, --js <expr>, --js-file <path|->, --condition-json <json>Adds a Router route or an If/Else condition branch (inserted before Else). --js and --condition-json are mutually exclusive; --condition-json is string[][] — an OR of AND-rows.
cai branch update<nodeId>--route <id> / --branch <id> (alias), --name <displayName>, --js <expr>, --js-file <path|->, --condition-json <json>Renames a route/branch and/or replaces its condition.
cai branch delete<nodeId>--route <id> / --branch <id> (alias)⚠ Deletes a route/branch and its branch edge.
cai branch connect<nodeId>--route <id> / --branch <id> (alias), --to <nodeId> (required), --flow <flowId>Wires a branch output to a target node — the only way to do it headlessly.
cai branch reorder<nodeId>--order <ids> (required)⚠ Reorders If/Else condition branches. First match wins, so order is semantics. Takes every condition branch id, comma-separated.

Dev-version runs. ⚠ These execute REAL external actions against the development data rail — dev isolation covers the data store only.

CommandArgumentsKey flagsWhat it does
cai run node<nodeId>--inputs <file|-> (- reads stdin), --timeout <ms> (default 120000)⚠ Runs one node in isolation on the dev version — messages send, records change. Always surfaces resolvedConfigs. Warns that upstream nodes are not executed, so an upstream-dependent expression is not verified until you run the flow. Adopts the observed output type when the run completes.
cai run flow<flowId>--inputs <file|-> (- reads stdin), --timeout <ms> (default 300000)⚠ Runs one flow end-to-end on the dev version with real external actions. Audits every node’s resolved configs and adopts observed output types.
cai run inputs<nodeIdOrFlowId>--flowThe test inputs a node or flow needs — call before run node. --flow treats the argument as a flow id.
cai run discover--node <slug> (required), --key <componentKey> (required), --connection <id|none> (required), --props <json|file|->, --enable <prop> (repeatable), --keep, --timeout <ms> (backend caps at 55000)⚠ Probes what a component really returns without touching the real graph — it runs in a hidden “Agent Scratch” flow, but it executes the REAL third-party action and spends usage balance. --keep retains the scratch node instead of deleting it. Warns when no observedOutputType came back.
cai run workflowNot implemented. Always throws NOT_IMPLEMENTED — the backend’s manual runner is flow-scoped; use cai run flow <flowId> on the entry flow, or publish and let a trigger fire live.

Read execution history. All read-only.

CommandArgumentsKey flagsWhat it does
cai exec list--limit <n> (default 10)Recent workflow executions.
cai exec get<workflowExecutionId>One workflow execution with its flow executions.
cai exec flow<flowExecutionId>Node-by-node detail of one flow execution, including resolvedConfigs.
cai exec node<nodeExecutionId>--fullOne node execution: status, output, and resolvedConfigs. --full prints the untruncated output blob.
cai exec ports<nodeExecutionId>--fullEvery port of one node execution: inputs, configs, outputs. --full does not truncate values.
cai exec tree<workflowExecutionId>Node-by-node status walk across every flow in an execution.

Account activity feed.

CommandArgumentsKey flagsWhat it does
cai events--type <types> (comma-separated or repeated; accumulates), --since <when> (ISO timestamp or relative 30m/2h/7d), --cursor <cursor>, --for-workflow <id>, --limit <n> (default 50, max 200)Account activity feed, newest first: connections, workflow edits/publishes/runs, agents, org members. Returns nextCursor for strictly older pages.

Dependency map.

CommandArgumentsKey flagsWhat it does
cai deps--accountWhich agents and workflows depend on this workflow — agents attaching it as a tool (draft/LIVE), workflows calling it, connections used, trigger count. --account returns the account-wide resource map instead.

Build and test mutable agent drafts, then publish immutable live versions.

CommandArgumentsKey flagsWhat it does
cai agent list--search <text>, --ownership <mine|shared> (default mine)Lists agents visible to the current account.
cai agent get<agentId>Inspects the agent configuration visible to this account and its version status.
cai agent create--name <name> (required), --instructions <text>, --instructions-file <path>, --disabledCreates a private draft agent; nothing becomes live until publish. --instructions and --instructions-file are mutually exclusive.
cai agent update<agentId>--name <name>, --instructions <text>, --instructions-file <path>Updates only the draft; the live agent remains unchanged.
cai agent visibility<agentId>--value <private|organization> (required)⚠ Changes live agent access. organization shares the published version with active organization members and requires publishing first; private revokes organization access. There is no public mode.
cai agent add-workflow<agentId>--workflow-id <id> (required), --flow <flowId> (required), --description <text>, --require-confirmationAdds a follow-live workflow tool with a backend-generated name to the draft. --require-confirmation pauses every invocation for explicit user approval before the workflow runs.
cai agent add-action<agentId>--integration <slug> (required), --action <key> (required), --connection <id> (required), --description <text>, --require-confirmation⚠ Attaches one ready integration action to the draft. Default is no approval, so decide explicitly for writes or spend. Slug comes from cai integration search, key from cai integration actions.
cai agent update-tool<agentId>--tool <toolId> (required), --description <text>, --connection <id>, --require-confirmation, --no-confirmation⚠ Updates a draft tool. Direct-action connection grants are live-bound before republish. --require-confirmation and --no-confirmation are mutually exclusive; --no-confirmation runs without approval — use only after reviewing writes, messages, deletion, and spend.
cai agent remove-tool<agentId>--tool <toolId> (required)⚠ Removes a draft tool. Direct-action detachment revokes live authorization immediately.
cai agent add-file<agentId>--file <path> (required), --name <fileName>, --type <fileType> (txt, md, json, csv, html, or xml)Adds a knowledge file to the draft; publish later to freeze it into live.
cai agent tools<agentId>Lists owner draft tools, or the published projection visible to a shared user.
cai agent publish-preflight<agentId>Checks the agent draft and every attached tool before publishing.
cai agent publish<agentId>--name <releaseName>⚠ Snapshots the draft and moves every existing live conversation to the new version.
cai agent versions<agentId>Lists immutable published versions.
cai agent conversation list<agentId>--mode <dev|live>Lists verification conversations for an agent, optionally filtered to one rail.
cai agent conversation create<agentId>--draft, --live (default), --title <title>, --model <model>Creates a conversation on an explicit rail. --draft is owner-only Test (current agent draft + workflow development heads); --live is the latest published agent and workflow releases. Mutually exclusive.
cai agent conversation status<conversationId>Reads the conversation rail, adopted version, model, and status.
cai agent conversation history<conversationId>--lastReads persisted messages, events, and pending permission requests. --last returns just the final assistant reply: status, text, tool-call summary, cost.
cai agent conversation approve<conversationId>--request <requestId> (required), --tool <toolName>⚠ Approves one pending tool request and resumes the conversation — the tool then runs for real. Ids must be exact values from conversation history.
cai agent conversation deny<conversationId>--request <requestId> (required), --tool <toolName>, --message <reason>Denies one pending tool request and resumes the conversation; --message is the reason returned to the agent.
cai agent conversation send<conversationId>--message <text> (required), --wait, --timeout <seconds> (default 300)Sends a message, optionally waiting for the next completed persisted assistant reply.
cai agent test<agentId>--message <text> (required), --draft (default), --live, --title <title> (default CLI verification), --model <model>, --timeout <seconds> (default 300)Creates, sends, and verifies one persisted reply on an explicit rail in a single call. ⚠ --live exercises the published agent and its real tools.

Existing user connections. Credentials are only ever entered in the browser.

CommandArgumentsKey flagsWhat it does
cai connection list--integration <slug>, --node <slug> (legacy alias)Lists account connections without requiring workflow context. Passing both flags with different slugs is rejected (CONFLICTING_INPUT).
cai connection connect<nodeSlug>--no-open, --wait, --timeout <seconds> (default 300)Opens the Controller AI browser flow for a missing integration and, with --wait, polls until a new connection for that integration appears (or fails with CONNECTION_WAIT_TIMEOUT and re-prints the still-valid link).

Discover ready integration actions that agents can use directly. No workflow context required.

CommandArgumentsKey flagsWhat it does
cai integration search<query>--limit <n> (default 20, max 100), --after <cursor>Searches integrations that have ready actions; returns slug, action count, auth requirement, metering, and a pagination cursor.
cai integration actions<integration>--search <query>, --limit <n> (default 50, max 100), --after <cursor>Lists ready actions for one integration: exact action key, auth requirement, metering, usage pricing.

Folders for organising workflows.

CommandArgumentsKey flagsWhat it does
cai folder listEvery folder you own, with workflow counts.
cai folder create--name <name> (required)Creates a folder.
cai folder rename<folderId>--name <name> (required)Renames a folder.
cai folder delete<folderId>⚠ Deletes a folder. No confirmation flag — its workflows move to the root, they are not deleted.

Labels applied to workflows.

CommandArgumentsKey flagsWhat it does
cai label listEvery label you own.
cai label create--name <name> (required), --color <color>Creates a label.
cai label rename<labelId>--name <name> (required)Renames a label.
cai label delete<labelId>⚠ Deletes a label everywhere it is applied. No confirmation flag.
cai label add<labelId>--workflow-id <id>Applies a label to a workflow (defaults to the pinned one).
cai label remove<labelId>--workflow-id <id>Removes a label from a workflow (defaults to the pinned one).
cai label create-and-add--name <name> (required), --color <color>, --workflow-id <id>Creates a label and applies it in one call.

Public read-only share links for a workflow.

CommandArgumentsKey flagsWhat it does
cai share listShare links that exist for this workflow, with revoked state.
cai share create--name <name>, --description <text>, --version <workflowVersionId>⚠ Publishes a PUBLIC, unauthenticated link — anyone holding the token can read the whole workflow graph, including prop values baked into it. Only LIVE versions can be shared, so it defaults to the live version and fails with NO_LIVE_VERSION if the workflow was never published. The link pins the version it was created from and does not follow later edits.
cai share revoke<shareId>Revokes a share link.

VariableWhat it does
CAI_TOKENBearer credential used for every request. Overrides the token stored in the config file, and is never written back to disk. The kind is inferred from the prefix: cai_ → CLI credential, sk- → API key, anything else → JWT.
CAI_CONFIGAbsolute path to the config JSON file. Defaults to ~/.config/cai/config.json.

The config file is created with mode 0600 and its parent directory with 0700; cai doctor fails the Credential file check if the mode drifts. Stored fields: apiUrl, appUrl, token, tokenKind, expiresAt, workflowId, headStateId (the last two are caches, not preconditions).

cai auth logout removes token, tokenKind, and expiresAt from the file; --revoke also revokes the credential server-side first.

SourceNotes
--workflow <id>Highest precedence. Available on every command.
CAI_WORKFLOWEnv var; a numeric workflow id. Beats both pins.
./.cai.jsonProject pin in the current working directory: { "workflowId": 123 }. Written by cai use. Beats the machine-global pin.
global config workflowIdMachine-wide default, also written by cai use (and by cai workflow create). Lowest precedence.

Resolution order is exactly: --workflowCAI_WORKFLOW./.cai.json → global config. Missing all four fails with NO_WORKFLOW (“Pass --workflow <id>, set CAI_WORKFLOW, or run cai use <id>”).

Why the project pin exists: the global config is one file per machine, so two coding-agent sessions in different project directories otherwise fight over cai use — a re-pin from one session can redirect another session’s data writes to a different workflow mid-conversation. .cai.json next to the work wins locally; credentials stay global-only.

Commands that never need a workflow: auth *, connect, skills *, doctor, use, workflow list, workflow create, workflow delete, integration *, connection *, folder *, label list/create/rename/delete, share revoke, agent *. workflow get/rename/describe/move/duplicate/versions/releases accept an explicit [workflowId] and fall back to the pin.

VariableWhat it does
CODEX_HOMEStandard Codex CLI variable. cai skills install/update/status reads it to locate the Codex home when installing to the codex target; defaults to ~/.codex.

A few environment overrides exist for Controller AI internal development only; they are unsupported and intentionally undocumented.