- A workflow pushed with
lua push workflow --name <name>and made live withlua workflows deploy <name> -v latest. - A user session (
lua auth configure):approve,resolve-step, anddelete-runrefuse an API key.
1
Start a run
start validates the input against the workflow’s inputSchema, creates the run, and returns at once. An idempotency key makes a retried script return the same run instead of a second one.✅ Run <runId> · queued. When the platform serves a model plan for the run, start prints it next: one row per agent step with the class or code it asked for, the model that resolves to today, its effort and reason, then one cost line in actions and the fallback promise — the same card a person is asked to consent to when the run is gated. --follow attaches watch, so --timeout and --wait-for-human apply. A run the organization cannot seat yet is gated and exits 6; a workflow with concurrencyPolicy: 'forbid' and a run in flight is meant to print the blocking run id and exit 1, but as of lua-cli 3.33.0 and the current platform the second run is created instead, so treat overlapping runs as possible until the fix ships. --correlation-key labels the run for Workflows.signalByKey and runs --correlation-key.2
Follow it to a human boundary
watch streams the run’s events and ends when the run ends or when a person is needed.Output
approve, resume for a step parked on ctx.suspend(), signal for a signal wait, raise-budget for a budget park, retry-step for a billing hold; an exception park prints ⚠️ run parked on an exception gate — a human decides next. A completed run exits 0, failed or timed_out 4, cancelled or abandoned 5, a consent gate 6.--wait-for-human keeps streaming through every boundary until the run is terminal or --timeout <s> fires with exit 7 and ⏱️ watch: --timeout 3s reached (run still live); Ctrl-C detaches with exit 0 and changes nothing.3
Read the run and its steps
status prints the run header; --steps adds a table of every step with its kind, status, attempt, and error.Output
--steps prints one line per step that has something to add: the classified cause of a failure, what an attempt burned, its priced receipt, and, for an approval the platform re-addressed, ⇅ reviewDrafts: approver escalated creator → org-admins — the initiator is excluded (maker-checker). That line appears when your organization’s approval policy excludes the person who started the run and the step’s approver is the creator: rather than failing the step with nobody to ask, the platform asks the organization’s admins, minus the initiator, and records the escalation on the step; see Approvals and signals.The Budget: line says which unit that run is counting and what the unit buys, because both differ by organization:Only the third row leaves tokens out of the reckoning. On the first two the run is charged the way a chat turn is, which is why the same 40-step workflow can spend very different amounts on two different model choices — see choose a model per step. A Job-tier step is charged per model reply, so one long coding turn can be worth many units; see What a Job step costs. When the run’s steps carry priced receipts,
--steps also prints a 🧠 By model table of calls and spend per model, with each model’s class beside it and a count of the fallback hops it served.Under the Budget: line, a run whose steps were priced per call also prints Tokens: — for example 4,812 uncached in · 261,004 cache read · 1,024 cache write · 3,190 out — the four figures the run’s own usage rows add up to. A figure the run recorded nothing for is left out rather than printed as zero. --steps gains Uncached, Cached (reads and writes together) and Output columns per step. Cached prompt tokens count toward a call’s price band at the fraction of a fresh token the provider charges Lua, and where Lua has no published fraction for a provider its calls are sized exactly as they were before; a cache read is a subset of the prompt, never an addition to it, which is why the columns are shown apart rather than summed.--json prints the platform’s run document: status; suspendedFor and suspensions[], whose suspend.approvalId is the wfa_… id approve needs; gate (kind, code, stepId) on a gated run; nextAction (none, cancel_again, force, raise_budget, top_up); budget (maxCredits, spent, remaining, reserved, exceeded); usage.tokens (inputTokens uncached, cacheReadTokens, cacheCreationTokens, outputTokens) on a run priced per call; and steps[] with preview.input, preview.output and the same tokens block per step. An agent step carries its model choice too: taskClass, modelRequested (the code or class/… the definition asked for), modelResolved (the model that answered), modelReason, effortApplied (the effort that reached the model, or null when the step’s effort was recorded and dropped), and modelFallback[] when a leg failed and another model took the turn. modelResolved is the only field that says what ran. A Job-tier step carries job (model, modelSource — whether the step pinned it, the platform default supplied it, or your organization’s default did — and multiplier), which is what that step’s replies are priced on. An approval step the platform re-addressed carries suspend.approverFallback { from, to, reason }.--strict maps a terminal status, and gated, to the watch exit codes for scripts that poll: 4, 5, or 6 instead of 0, so a loop never reads a run that is waiting for consent as still running.4
Answer or repair the run
Each park names its verb. All take the run id first and refuse with a typed code when the step is not in the state they expect.
A re-armed step runs under the same occurrence, so a
once() effect that settled is not repeated. Nothing re-runs a terminal run: retry-step answers RUN_TERMINAL, so start a new run.A run that reaches its budget cap stops and parks — it does not fail, and nothing is half-charged: an attempt that crosses the cap mid-flight stops at the next tool boundary rather than in the middle of a model reply, and the run waits on the budget gate. raise-budget resumes it from where it stopped. The one case that ends rather than parks is a run whose last step finished having gone past the cap: there is nothing left to hold, so the run completes and is marked budget.exceeded. status reads finished past the cap, and lua workflows logs prints one run.budget_exceeded event naming the spend, the cap, the step and the plan. Treat it as a bill to look at, not a failure to repair — the run’s output is good.The model park is the one that clears itself. status prints ⏸️ Paused — a step's model request cannot be resolved under the current policy: with the gate code and step beneath it; the step is waiting, never failed, and the platform sweeps the gate once the request resolves again. Clear it by hand only when you would rather not wait: clear-gate re-arms the step at the same attempt, and the step parks again if the condition still holds.The
Workflows members behind these actions (resume, signal, signalByKey, startBatch, setGoal, goals.*) work in deployed code and under lua test alike; only Workflows.raiseBudget works in neither runtime, so raise a budget with lua workflows raise-budget or the REST route.5
Cancel a run
A cancel is a request: running steps stop at their next boundary and the run moves to The reply is
cancellation_requested.✅ cancel accepted · run <runId> is <status> plus what to do next: next: cancel again to escalate, or next: force available at <time> — lua workflows cancel <runId> --force. A forced cancel abandons the run; a run that already ended answers ℹ️ run <runId> was already <status> — nothing to cancel.6
Verify
List the workflow’s runs, then read one run’s progress and lifecycle events.
Output
runs filters by --workflow, --status, --correlation-key, and --tag, sorts with --sort, and prints the next page’s command. logs returns the latest 500 progress and lifecycle events, --step <id> narrows to one step, and --follow switches to watch; --since is accepted but has no effect. The budget events read in plain language — run.budget_parked as paused on its run budget, run.budget_raised, and run.budget_exceeded as finished past the cap, each with the spend against the cap — and a Job-tier step emits step.job_model_resolved when it claims, naming the model it will run on, how that model was chosen, and its multiplier.Two of those lines are about model choice. step.model_resolved names the model a step resolved to and, in brackets, the class or task class it asked for. step.model_policy_warning says a step pinned a model your organization’s effective model set excludes; the step still runs, and the line carries the outcome (model_excluded, effective_model_set_unavailable, or model_pin_not_allowed), the pin the definition asked for, and a message. That warning is written before the turn is dispatched, so it never names what answered — read modelResolved off the step for that.Options you may need
Activate, deactivate, and deploy
lua workflows activate <name> turns the workflow’s schedules and triggers on and deactivate pauses them; neither changes the live version. activate -v <version> is the same as deploy <name> -v <version>: it makes that version live for new runs and records an agent version, so lua version promote <n> is the rollback. A run keeps the version it started on; neither a deploy nor a promote moves a run in flight. From lua-cli 3.36.0, lua push all pushes workflows and makes each pushed version live at once (earlier releases skip them); lua deploy has no workflow type; see Release an agent.
Run statuses and exit codes
Other refusals follow the
lua workflows table: 1 API refusal, 2 usage, 3 not found, 9 not signed in, 10 forbidden, 11 unavailable. --json prints the platform’s { success, data } or { success: false, error } envelope and keeps the exit code.
If it isn’t working
STEP_NOT_PARKED
STEP_NOT_PARKED
The step is not in a state
retry-step or resolve-step can act on. status --steps names it: a running step needs time, a suspended one needs approve, resume, or signal.RUN_TERMINAL
RUN_TERMINAL
The run has ended, so no step can be retried or resolved. Start a new run.
BUDGET_NOT_RAISABLE
BUDGET_NOT_RAISABLE
Only a run parked on its budget takes a raise, and only above its current cap. A run at its raise cap must be canceled and started again with a larger
--budget-credits.Next steps
Approvals and signals
Approver kinds, editable payloads, and delivering signals from code.
lua workflows reference
Every verb, flag, and refusal code.
Workflows runtime API
Start, signal, resume, and cancel runs from tools and webhooks.
REST API
The routes behind each verb.

