lua workflows manages pushed workflow definitions and their runs. deploy changes what runs for every end user; every other verb reads or steers one workflow, one run, one schedule or one goal.
Requires lua-cli 3.36.0 or later.
Synopsis
Description
A workflow version is uploaded withlua push workflow and does nothing until lua workflows deploy <name> -v <version|latest> makes it active. That deploy is a scoped promote: it records a new agent version and prints it as agentVersion, so lua version promote <n> is the rollback. A chat-composed (dynamic) workflow cannot be deployed by version; the verb refuses with WORKFLOW_DYNAMIC (exit 1).
Run verbs take a run id. start --follow, watch and logs --follow stream the run’s events and exit when the run ends (0 completed, 4 failed or timed out, 5 canceled) or when it needs a person: an approval, an input, a signal, a billing, budget or exception park (exit 8, with the resuming verb printed) or a gate that holds the run before it starts (exit 6: consent, or a quota slot the organization cannot seat yet). --wait-for-human prints that notice and keeps streaming until the run is terminal; --timeout <s> ends either mode with exit 7 while the run is still live. status --strict answers the same codes for a run that has ended or is gated.
--json prints the raw {success,data} envelope on stdout for every verb; a refused verb prints the server’s error envelope and keeps its exit code. Without an action the command offers a menu (list, run, start, runs). Only delete, delete-run and schedules delete confirm; pass --yes under --ci, where any prompt fails with ✖ error: Interactive prompt required but --ci flag is set. Provide all required flags or arguments. (exit 1). run is the offline driver; its flags are on lua test.
Arguments
Run and deploy actions
A schedule is a workflow’s cadence job (at most 5 trigger slots). A goal runs a workflow repeatedly until a judge says the objective is met; its cadence is a schedule tagged with the goal id:
schedules patch, pause and resume refuse it with goal_schedule (exit 1), and schedules delete refuses it while the goal is active or paused. Schedule sub-verb aliases: ls → list; new, add, set → create; update, edit → patch; hold, stop, disable → pause; unpause, enable, continue → resume; rm, remove, del, unschedule → delete. Goal sub-verb aliases: ls → list; view, show, info → get; new, add, set → create; update, patch, change → edit; bump, increase → raise; hold, stop → pause; unpause, continue → resume; end, finish → close.
Schedule and goal actions
Policy actions
The policy belongs to the organization named in the project configuration, so these verbs run inside a project.
get needs read access to the organization; set needs an organization administrator, and anyone else is refused with forbidden (exit 10). See Author a workflow for what the model policy does to a step and Goals and schedules for what the envelope admits.
Options
Shared options
start
Prints
✅ Run <runId> · <status>; with --json the envelope’s data holds runId and status, plus deduplicated or idempotentReplay when no new run was created. When the platform serves a model plan for the run, start prints it under that line: one row per agent step with the class or code it asked for, the model that resolves to today, its effort and reason, then Estimated cost: at least <n> actions (…) and the fallback promise. A run that starts gated exits 6; with --follow the attached watch reaches the same gate and also exits 6 unless --wait-for-human. A concurrencyPolicy: 'forbid' workflow with a run in flight prints the blocking run id and exits 1. As of lua-cli 3.33.0 and the current platform that refusal is not applied on start: the second run is created, so treat overlapping runs as possible until the fix ships.
runs
status
The header carries a
Budget: line in the run’s own unit, and a parked run says what parks it: ⏸️ Paused — run budget reached, ⏸️ Paused — payment required, ⚠️ Needs a decision for an exception gate, or ⏸️ Paused — a step's model request cannot be resolved under the current policy: with the gate code, the step and the clear-gate command beneath it. A run whose steps carry priced receipts adds a 🧠 By model table of calls and spend per model. Under the --steps table, an approval the platform escalated because the run’s initiator may not decide it prints ⇅ <stepId>: approver escalated creator → org-admins — the initiator is excluded (maker-checker).
status prints a Consent line for a run the organization’s autonomy envelope admitted, quoting the bounds that let it through. A run a person approved prints no such line:
Output
queued run. It adds no exit code, and --strict treats it like any other.
watch and logs
Ctrl-C detaches without touching the run. A boundary the run has already moved past is printed as history and does not end the watch.
logs prints each event as [hh:mm:ss] <type> · <stepId> · <detail>; the two model events read step.model_resolved · <stepId> · model resolved → <model> (<class>) and step.model_policy_warning · <stepId> · model policy warning: <outcome> <message>.
cancel, resume, retry-step
resume on an approval step is refused with APPROVAL_REQUIRES_HUMAN and names the approve command; on a signal wait it is refused with USE_SIGNAL_ROUTE and names the signal command. retry-step refuses with STEP_NOT_PARKED, RUN_TERMINAL or STEP_RETRY_CAP.
resolve-step
With an API key the verb refuses with
APPROVAL_REQUIRES_HUMAN: sign in with a user session instead.
raise-budget
At least one cap is required, every value is an integer of 1 or more, and increases only. A raise that does not cover the next step’s reserve parks the run again (
resumed: false).
approve and approval-payload
signal
A payload member named like a credential (
token, and the other reserved names the warning lists) is stored and shown as [REDACTED] downstream; the CLI warns and sends it anyway.
replay
Exit 4 on a divergence. Needs a compiled project in the current directory.
delete and delete-run
delete is refused while a goal or schedule still references the workflow (409 WORKFLOW_REFERENCED_BY_JOBS, exit 1); the message names each job and the verb that stops it. delete-run refuses a live run: cancel it first.
env-overlay and export
export compiles the written files before it exits 0; a file the compiler refuses is still written and the verb ends with export_not_compilable (exit 1). With --json the files are printed inline and nothing is written.
archive-runs
workspace, jobs, job-logs
schedules create
schedules patch, pause, resume, delete
A schedule the platform turned off after three failed runs in a row stays off when the workflow is activated again;
schedules resume <jobId> turns it back on and gives a declared health watch a fresh silence window.
goals create
One of
--judge-predicate or --judge-agent is required; --schema and --judge-role belong to --judge-agent only.
goals edit and goals raise
policy models set
Only the fields you name change. A value outside a flag’s set is a usage error (exit 2) before any request is made; whether a code is in your organization’s model set and whether a class still resolves to a model are the server’s to judge, and those refusals exit 1 with the code on the line:
MODEL_NOT_ELIGIBLE (a code your organization may not use, with the codes), MODEL_CLASS_EMPTY, MODEL_CLASS_UNREACHABLE (no eligible model at or below --max-class, or a class-map entry above it), MODEL_JOB_PROVIDER_UNSUPPORTED (a class override that leaves no model a Job-tier step can use), and MODEL_POLICY_UNVERIFIABLE (503) when the set cannot be read, in which case nothing is stored. set with no flag is a usage error. Success prints ✅ Workflow model policy updated (<fields>), the same block get prints, and a note that a change reaches a composing agent within 30 seconds.
Output
— with the default it falls back to in brackets; an organization that has set nothing prints one line saying the platform defaults apply.
clear-gate
A step whose model request the organization’s policy cannot resolve parks the run on a
model_policy gate rather than failing it. The platform clears that gate itself once the request resolves; this verb clears it by hand and re-arms the parked step at the same attempt, and the step parks again if the condition still holds. Success prints ✅ Cleared the model_policy gate on <runId> and the watch command. A run that is not on that gate is refused with NOT_GATED (409, exit 1); any other --kind is VALIDATION_FAILED. The verb needs a user session: an API key is refused with APPROVAL_REQUIRES_HUMAN.
recompose
No options. Rewrites the active version of a chat-composed workflow so that every agent step whose stored task class maps to the class its current pin heads asks for model: 'class/<class>' instead, and publishes the result as a new version on the same definition; no model turn runs, and a pin that differs from the class map is left as written. With --json the envelope’s data is the platform’s diff: fromVersion, rewritten[], skipped[], and composed when a version was published. A pushed workflow is refused with RECOMPOSE_NOT_APPLICABLE (409, exit 1), as is a chat-composed one with no active version. Because a chat-composed workflow cannot be deployed by version, the new version is published on the same definition and versions shows which one is active.
policy autonomy set
Each numeric flag is an integer of at least 1, checked before any request; a value above its ceiling is the platform’s refusal (exit 1),
VALIDATION_FAILED naming the field’s range. A flag you omit is left as it is; --clear resets the fields it names so the platform default applies again; naming a field on both sides is a usage error, as is set with no flag. --agent is refused: nothing writes a per-agent envelope yet. Success prints ✅ Workflow autonomy policy updated (<fields>) and the envelope as get prints it, with a reminder that the envelope turns an ask into a start, never a refusal into either.
policy autonomy get prints the organization’s stored envelope, each unset field reading — with the default it falls back to, and beneath it the effective envelope the platform resolves for the organization — the stored values narrowed by any agent-level narrowing, defaults filled and ceilings applied — or a note that the server served no resolution. Both verbs act on the organization: an envelope is set once for the organization, and the per-agent narrowing the platform honors has no public way to set it yet.
Examples
Deploy the newest pushed version and start a run that follows to completion, exiting 8 if a person is needed.Output
Exit codes
Which 4xx is which: a 401 or 403 never reaches the verb, because the HTTP client raises it as
auth (9) or forbidden (10) before the verb sees a response, while every other 4xx the server answers with (400, 409, 422, 424) is the verb’s own refusal and exits 1 with the server’s code on the line. Every escaped error is one line, ✖ <code>: <message>, plus a hint; LUA_DEBUG=1 prints the stack.
See also
- Operate runs — the how-to behind the run verbs
- Goals and schedules — cadences and judges
- Test workflows offline and
lua test— therunflags lua push— uploading a workflow version- Errors and exit codes

