Skip to content

Publish a Workflow

Publish to make the saved development definition the new live release. Publication synchronizes schemas without copying development records. It activates the workflow, allowing enabled published triggers to run.

For Daily invoice digest, verify the trigger guide’s fixtures with three invoices including one needing review. Then test an empty queue. Each test should post exactly one summary to docs-digest-test. The empty queue produces a zero-item digest. The schedule is 09:00 America/Chicago.

In the app: open Workflows → Daily invoice digest → Dev. Publish appears on the Dev flow canvas. It is disabled when validation is missing or invalid, editing is read-only, a run or save is underway, or development already matches Live with no pending edits.

With an assistant: pin the workflow with cai use so later commands omit --workflow. Scoped MCP calls always require workflowId.

Find the workflow’s ID.

Terminal window
cai workflow list --limit 100 --json

Note Daily invoice digest’s data.items[].id as <workflowId>. If absent while data.hasMore is true, get its ID from the app. This list has no continuation token.

Pin the workflow and inspect its status, validation, dependencies, and releases.

Terminal window
cai use <workflowId> --json
cai workflow status --json
cai workflow validate --json
cai deps --json
cai workflow releases --json

In data, check hasLiveVersion, liveMatchesDev, needsPublish and active. Record the current release before publishing. validation contains {errors,warnings,redNodes} or {unavailable:true}. Unavailable validation is not a successful check.

MCP uses dependency_map for cai deps and workflow_release_list for releases, both with workflowId.

After contract changes, review dependencies. Live agent tools follow the latest workflow release without agent republishing.

In the app: review triggers across every flow. Set Allow test events in dev mode Off wherever incoming development runs are unintended. Enable trigger and Disable trigger change the development definition.

With an assistant: list and audit triggers for their deployment and capture settings.

Terminal window
cai trigger list --json
cai trigger audit --json

For each trigger, inspect deployment.liveCanvasEnabled, inLiveVersion, allowTestEvents, devDispatchArmed, dualDispatchLive and workflowActive under deployment. Check capture.sourcePresent, capture.sourceEnabled, readiness.nextAction and every issues[] entry. liveCanvasEnabled:null means no live canvas exists.

Until publication, disabling development leaves the published trigger running. Development event permission remains. Source capture keeps running. When a live path would also run, CLI/MCP refuses to re-enable an armed development trigger. Disallow test events first. Note data.items[].triggerId as <triggerId>. Turn off unintended permission and audit again for updated settings.

Terminal window
cai trigger test-events <triggerId> --disallow --json
cai trigger audit --json

MCP uses trigger_test_events_set with triggerId, allowed:false and workflowId.

Inspect the live invoice collection before enabling the schedule. If the schema needs publication before copying records, first publish with the trigger disabled, prepare live rows, then enable and publish again. Publication removes deleted fields from live reads, returns null for missing or incompatible values, and deactivates omitted collections.

SituationAppCLI/MCP
Validation errorsPublish disabled for invalid frontend validationRejects deep-validation errors unless --acknowledge-validation-errors / acknowledgeValidationErrors:true.
Enabled trigger permits incoming development eventsPublishes with warningRejects unless --acknowledge-dual-dispatch / acknowledgeDualDispatch:true.

Accept either exception only after reviewing its consequence. Dual dispatch can send twice and bill both runs. Validation acknowledgement bypasses only reported deep-validation errors. Checks for ownership, plan capacity, a missing development state, executable If/Else validation, trigger ownership and dual-dispatch remain. A validator crash does not itself block backend publication.

Publishing reactivates an inactive workflow. If your active-workflow allowance is full, publishing an inactive workflow is rejected before a release is created. Deactivate another workflow or upgrade.

In the app: choose Publish → Publish Workflow → Version Name → Publish. The app saves pending edits before opening the dialog. After publication, it switches to Live.

With an assistant: publish the definition and inspect its status and releases.

Terminal window
cai workflow publish --name "Daily invoice digest: verified schedule" --json
cai workflow status --json
cai workflow releases --json

Check published, active, flowCount, enabledTriggerCount and warnings in the publish result. Get the release number from data.releases[], which contains versionNumber, workflowVersionStateId, createdAt.

MCP uses workflow_publish with workflowId and name, then workflow_status and workflow_release_list.

The hosted Build for me assistant can present Publish this workflow for approval. If approval polling is interrupted, note approvalId from the builder_approval event (or error.detail.approvalId) as <id>. Resume polling to get the existing operation’s result.

Terminal window
cai approval resume <id> --json

MCP uses approval_resume with approvalId. It polls the existing operation without publishing again. After any uncertain error or timeout, inspect status and releases before retrying. The live change can precede a later failure. Another publish creates another release. Retry only if no new release exists.

Prove the release produced one live result

Section titled “Prove the release produced one live result”

Read the warnings:

  • agent_workflow_interface_changed: check dependent agent prompts.
  • agent_session_refresh_failed: publication succeeded. Verify in a fresh Live conversation instead of republishing to retry cleanup.
  • trigger_test_events_active: incoming development dispatch remains armed. A real event can run in both environments.

In the app: inspect the next scheduled event in Live → Run history, then verify exactly one message with the expected count in docs-digest-test. Test (tooltip “Test current flow”) runs the open flow on the selected version. It does not replay capture.

With an assistant: an intentional live replay performs real actions and spends usage. Inspect the trigger to get its backend ID.

Terminal window
cai trigger get <triggerId> --json

Note data.backendTriggerId as <backendTriggerId>. MCP trigger_get takes the canvas triggerId.

List captured events and choose one for replay.

Terminal window
cai trigger events --trigger <backendTriggerId> --limit 50 --json

Note data.events[].id as <eventId>. MCP trigger_event_list takes the backend ID as numeric-string triggerId and workflowId.

Replay the event against live to get an execution ID.

Terminal window
cai trigger replay --trigger <backendTriggerId> --event <eventId> --target live --confirm-live --json

Keep the original ID and note returned data.workflowExecutionId as <workflowExecutionId>. Replay creates another captured event.

MCP trigger_replay takes numeric-string triggerId and eventId, target:"live", confirmLive:true, and workflowId.

Inspect that execution for its status.

Terminal window
cai exec get <workflowExecutionId> --json

Poll the same execution until it reaches completed, completed_with_error, failed or cancelled. Handle paused separately. Pending is not a reason to replay again.

Inspect the execution tree to find the send.

Terminal window
cai exec tree <workflowExecutionId> --json

Note the send’s data.items[].id as <nodeExecutionId>. If results are paginated, repeat the tree command with --cursor <opaque> from data.nextCursor.

Read the send’s details to verify its inputs and destination.

Terminal window
cai exec node <nodeExecutionId> --full --json

Verify resolved inputs, destination and exactly one send. Replay proves the live path. The next scheduled event proves automatic dispatch. If counts are wrong, inspect live records and the published mapping before rerunning.

MCP uses execution_get and execution_tree with workflowExecutionId, then execution_node_get with nodeExecutionId and full:true, all scoped by workflowId.