Versions and rails
Controller AI has two version rails, one for workflows and one for agents. They use different words on purpose, because they behave differently. This page is the single source of truth for what runs where.
The two rails
Section titled “The two rails”| You edit… | Production runs… | The word for production | |
|---|---|---|---|
| Workflow | the development version | the latest published live release | “live” |
| Agent | the draft | the latest published version | “published” / “Live” |
“Test” belongs to the agent rail only: a Test conversation runs the agent draft; a Live conversation runs the latest published version. For workflows, say “dev run”, not “test run” — a dev run is a real run against the development version, not a rehearsal (Safety).
The rails compose. A Test conversation resolves the agent’s workflow tools against each workflow’s current development head. A Live conversation resolves them against each workflow’s latest live release (or a pinned release — see below).
What runs which rail
Section titled “What runs which rail”| Caller | Rail |
|---|---|
Builder and CLI runs (cai run node, cai run flow) | Development |
| Agent Test conversations | Development heads |
API call with mode: "dev" | Development |
| Trigger replay targeted at dev | Development |
| A real trigger event (webhook, schedule, email, app event) | Live — plus dev, if test events are armed (see hazard below) |
API call (default mode: "live") | Live |
| Agent Live and shared conversations | Live releases |
Inside a run, the Is live version data source tells the flow which rail it is on — the standard way to build a safe-audience harness (dev branch targets you, live branch targets the real audience).
Publishing a workflow
Section titled “Publishing a workflow”Publishing copies the current development state to the live rail as a numbered, immutable release. Old releases remain queryable; the development version is untouched and keeps moving.
What publish does not copy: data records. The development and live stores are physically separate — a workflow that tested green against dev records goes live against the live store, which may be empty. Move records deliberately (cai data copy-to-live).
Publish is not unconditional. The server refuses when:
- validation fails structurally (for example, an If/Else node with no Else branch),
- the organization has reached its plan’s active-workflow limit,
- the development head moved since you last read it (stale base state — re-read and retry),
- an enabled trigger still has test events armed and you did not explicitly acknowledge dual dispatch.
Triggers: enable first, then publish
Section titled “Triggers: enable first, then publish”A trigger’s enabled/disabled flag lives inside the workflow definition. Toggling it edits the development state; live dispatch reads the flags frozen into the published state. So the order is: enable the trigger, then publish. Toggling after publishing changes nothing live until the next publish.
The dual-dispatch hazard
Section titled “The dual-dispatch hazard”“Allow test events” on a trigger is a temporary capture aid for development. If you publish while it is still armed, one real event runs both rails — the live release and the development version, both real, both metered. A schedule armed this way fires twice forever. Publish warns and requires explicit acknowledgment; the right move is almost always to disarm first.
Workflow version history is your undo
Section titled “Workflow version history is your undo”Every save of the development version is a restorable state:
cai workflow historycai workflow restore <stateId>Restore is non-destructive: it appends a new development state containing the old content, so the pre-restore draft stays in history and is itself restorable. Edit boldly — nothing inside the graph is unrecoverable. What restore does not roll back: data records (unversioned) and anything that already happened externally.
Publishing an agent
Section titled “Publishing an agent”Publishing an agent snapshots the draft — name, instructions, tool identities and approval policies, knowledge files — into an immutable version, and performs a hard cutover:
- Existing live conversations are restamped onto the new version. Conversations mid-turn are interrupted; in-flight answers never arrive.
- Every unexecuted approval request expires.
- Each conversation reopens on its own next message, running the new version.
There is no rollback for published agent versions: recovery is forward — fix the draft, publish again. Run the preflight before committing:
cai agent publish-preflightcai agent publishTime agent publishes with the cutover in mind, especially if a live conversation might be mid-approval with a customer.
What bypasses the publish gate
Section titled “What bypasses the publish gate”Three live bindings change production behavior without any publish — covered in Safety and blast radius: publishing an attached workflow (for latest-policy tools), rebinding or revoking an integration action’s connection, and detaching an integration action.
Workflow tools always follow the latest release
Section titled “Workflow tools always follow the latest release”An agent’s workflow tool is never pinned to a specific release: Live conversations always resolve the workflow’s newest published release, and Test conversations always use its development head. That is why publishing a workflow is a live change for every agent that uses it — if a shared workflow must not change a live agent’s behavior, coordinate the workflow publish like the production change it is (cai deps shows who is affected).