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.
Is the saved definition ready?
Section titled “Is the saved definition ready?”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.
cai workflow list --limit 100 --jsonNote 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.
cai use <workflowId> --jsoncai workflow status --jsoncai workflow validate --jsoncai deps --jsoncai workflow releases --jsonIn 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.
Are triggers and live records ready?
Section titled “Are triggers and live records ready?”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.
cai trigger list --jsoncai trigger audit --jsonFor 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.
cai trigger test-events <triggerId> --disallow --jsoncai trigger audit --jsonMCP 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.
Make the reviewed version live
Section titled “Make the reviewed version live”| Situation | App | CLI/MCP |
|---|---|---|
| Validation errors | Publish disabled for invalid frontend validation | Rejects deep-validation errors unless --acknowledge-validation-errors / acknowledgeValidationErrors:true. |
| Enabled trigger permits incoming development events | Publishes with warning | Rejects 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.
cai workflow publish --name "Daily invoice digest: verified schedule" --jsoncai workflow status --jsoncai workflow releases --jsonCheck 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.
cai approval resume <id> --jsonMCP 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.
cai trigger get <triggerId> --jsonNote data.backendTriggerId as <backendTriggerId>. MCP trigger_get takes the canvas triggerId.
List captured events and choose one for replay.
cai trigger events --trigger <backendTriggerId> --limit 50 --jsonNote 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.
cai trigger replay --trigger <backendTriggerId> --event <eventId> --target live --confirm-live --jsonKeep 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.
cai exec get <workflowExecutionId> --jsonPoll 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.
cai exec tree <workflowExecutionId> --jsonNote 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.
cai exec node <nodeExecutionId> --full --jsonVerify 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.