> ## Documentation Index
> Fetch the complete documentation index at: https://docs.heylua.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Release an agent to production

> Push a version, record it as an agent version, promote it, verify it, and roll back with one command

After this guide, a change you tested locally is live for every end user, recorded as a numbered [agent version](/concepts/releases-and-versions) you can diff and roll back to. `lua push` uploads a version and changes nothing for end users; `lua version create` snapshots the agent; `lua version promote <n>` makes that snapshot live and is also the rollback path. For one primitive on its own, use the `lua deploy` shortcut under [Options you may need](#options-you-may-need).

*Verified against lua-cli 3.33.0.*

**Before you begin**

* A compiled project: `lua compile --ci` exits 0. Tests pass per [Test an agent before you release](/ship/testing).
* No server drift: `lua status --json --ci` shows every `primitives[].diffs[].status` as `synced`, `ahead`, or `not deployed`, and no `orphans[]` entry with `critical: true`. For a `behind` entry, see [If it isn't working](#if-it-isnt-working). `lua sync --check` reports the same drift and exits 1.
* A `model` on your `LuaAgent` if the server has one: `lua push all` and `lua push agent` push the agent configuration, and a `LuaAgent` with neither `model` nor a model resolver clears the server's model. `lua sync --check` prints `Model drift detected` when they differ ([About models](/concepts/models)).
* Workflows pushed separately, since `lua push all` skips them: run `lua push workflow --ci --force --name <workflow-name>` first ([Workflows](/concepts/workflows)).

<Steps>
  <Step title="Push every primitive">
    `lua push all` compiles, bumps the patch version of every versioned primitive (skills, webhooks, triggers, jobs, preprocessors, postprocessors, devices, device triggers, voices), upserts [MCP servers](/concepts/mcp-servers), pushes the agent configuration (a new [persona](/concepts/persona) version, model, model settings), and uploads a source backup. Nothing goes live except the agent configuration: a pushed persona and model are served from the agent's next message.

    ```bash theme={null}
    lua push all --ci --force
    ```

    `--force` is required for `all`, and `--auto-deploy` is a no-op on `push all`. A failed primitive does not change the exit code: the command exits 0 and lists it on stderr under `⚠️  <n> component(s) failed to push:`. In a script, fail on that line.

    ```bash theme={null}
    lua push all --ci --force 2>&1 | tee push.log
    ! grep -q "component(s) failed to push" push.log
    ```

    The push first rewrites `version` in `lua.skill.yaml` from the server's active version, so a hand edit does not survive; to pick a number, push that primitive alone with `lua push <type> --ci --force --name <name> --set-version 1.2.0` ([`lua push` reference](/reference/cli/push)).
  </Step>

  <Step title="Create an agent version">
    An agent version records every primitive's pushed version plus the persona and model; it starts as `staged`.

    ```bash theme={null}
    lua version create --ci -m "Add ticket lookup tool"
    ```

    The command prints ``✓ Created v<n> (staged). Run `lua version promote v<n>` to deploy.`` and, with nothing new since the last version, `No changes since the latest version, so there is nothing to snapshot.` `--auto-push` pushes first; `--commit-hash <sha>` records the commit.
  </Step>

  <Step title="Review what will change">
    Compare the staged version with the active one.

    ```bash theme={null}
    lua version list --limit 5
    lua version diff 8 9
    ```

    ```text Output theme={null}
    Diff v8 → v9
    Skills: (no changes)
    Webhooks: (no changes)
    Jobs:
      - harden-tpl-sched schedule@1.0.0 (removed)
    Preprocessors: (no changes)
    Postprocessors: (no changes)
    Triggers: (no changes)
    MCP servers: (no changes)
    Persona: (unchanged)
    Model: (unchanged)
    Voice: (unchanged)
    ```

    `lua version show <n>` prints one version in full; `--json` gives machine-readable output ([`lua version` reference](/reference/cli/version)).
  </Step>

  <Step title="Promote the version">
    Promotion swaps the live version atomically, without a confirmation prompt, and prints `✓ Promoted v<n>. Previous active: v<m>.`

    ```bash theme={null}
    lua version promote 9
    ```

    <Warning>
      Every end user gets the promoted version on their next message, while a workflow run already in flight finishes on the version it started on. Promote only a version you reviewed with `lua version diff`.
    </Warning>
  </Step>

  <Step title="Verify">
    Confirm the active marker moved, note the time, send one production message on a fresh thread, and check that nothing was logged since under `agent_error` or as an `error` under `skill`, where a throwing tool lands. `lua logs` has no time or environment filter, so the check bounds both types by `timestamp`.

    ```bash theme={null}
    lua version list --limit 3
    since=$(date -u +%Y-%m-%dT%H:%M:%SZ)
    lua chat -e production -m "What is the status of my tickets? My email is user@example.com" -t --clear
    lua logs --type agent_error --limit 50 --json --ci | jq -e --arg s "$since" '[.logs[] | select(.timestamp > $s)] | length == 0'
    lua logs --type skill --limit 50 --json --ci | jq -e --arg s "$since" '[.logs[] | select(.timestamp > $s and .subType == "error")] | length == 0'
    ```

    ```text Output theme={null}
    VERSION  STATUS      CREATED           BY                MESSAGE
    v9*      active      2026-09-09 17:52  stefan@heylua.ai  Removed template Harden TPL 5
    v8       superseded  2026-09-09 17:51  stefan@heylua.ai  deploy workflows/hitl-edit 1.0.0
    v7       superseded  2026-09-09 17:49  stefan@heylua.ai  delete jobs/goal:wfg_a22a484c3e8012b0b9fc1dee
    ```

    The `*` marks the active version; both `jq -e` lines exit 0 when nothing was logged after `$since` ([Read logs and debug an agent](/ship/logs-and-debugging)).
  </Step>
</Steps>

## Options you may need

### Roll back to the previous version

Promote the version that was active before; `lua version list` shows it as `superseded`. A promote restores every code primitive version and the model, and touches nothing else: not the persona, environment variables, knowledge, features, channels, MCP activation, governance and model settings, devices, data the bad version wrote, or runs in flight ([what an agent version snapshots](/concepts/releases-and-versions#what-an-agent-version-snapshots)).

```bash theme={null}
lua version promote 8
```

A workflow rolls back with `lua workflows deploy <workflow-name> -v <previous-version>`, and the persona with `lua deploy persona --set-version <n> --force`.

### Ship one webhook, job, processor, or trigger

`lua deploy <type>` with `webhook`, `job`, `preprocessor`, `postprocessor`, or `trigger` makes one pushed version live at once: on an agent under versioning it creates and promotes a new agent version that differs from the active one only in that primitive, prints its number, and writes the deployed version into `lua.skill.yaml`.

```bash theme={null}
lua deploy webhook --ci --name ticket-status-webhook --set-version latest --force
```

`--set-version` takes a semver or `latest`. `lua workflows deploy <workflow-name> -v latest` does the same for a workflow. MCP servers have no versions; activate or deactivate one with `lua mcp activate <server-name>` and `lua mcp deactivate <server-name>` ([`lua mcp` reference](/reference/cli/mcp)).

### Deploy a skill or the persona

`lua deploy skill --name <skill> --set-version <v>` serves that version from the agent's next turn, on any agent, but the next `lua version promote` resets every skill to the version pinned in the promoted agent version. For a durable change, push, `lua version create`, `lua version promote`; for an immediate rollback of one skill, `lua deploy skill --set-version <old>`. A pushed persona is already live; `lua deploy persona --set-version <n> --force` switches the served persona to an earlier version at once, versioned agent or not, and a promote does not change it. An agent with no agent version yet is not under versioning, so every `lua deploy <type>` goes live at once, as `lua version status` says. `lua deploy all --force` (newest version of everything; `--name` and `--set-version` ignored) behaves the same per type and exits 0 even when it lists `⚠️  <n> deployments failed:` ([`lua deploy` reference](/reference/cli/deploy)).

## If it isn't working

<Accordion title="A primitive shows status &#x22;behind&#x22; in lua status --json">
  The server's active version is newer than the version in `lua.skill.yaml`, after a release from another machine or the admin dashboard. Run `lua sync --pull` to update local files from the server's source backup (it refuses if you changed files since your last backup; `--force` overwrites them), then start again. `lua version status` prints the same warning with the affected rows.
</Accordion>

<Accordion title="orphans[] lists a primitive with critical: true">
  The server has an active preprocessor or postprocessor that no longer exists in your code, and it keeps running on every message. Run the `cleanupCommand` from the same entry, for example `lua preprocessors delete --preprocessor-name "<name>"`, then push again.
</Accordion>

<Accordion title="lua deploy skill succeeded but production still answers with the old skill">
  Either a later `lua version promote` reset the skill to the version pinned in that agent version, or `--set-version latest` picked the most recently created version rather than the one you meant; `lua version status` shows the active version per skill. Push, `lua version create`, and `lua version promote <n>` make the change durable. Exit codes 9, 10, and 11 on any release command are credential and network problems, listed on [Errors and exit codes](/reference/cli/errors-and-exit-codes).
</Accordion>

## Next steps

<Columns cols={3}>
  <Card title="Go-live checklist" href="/ship/go-live-checklist">What to check before you promote.</Card>
  <Card title="About releases and versions" href="/concepts/releases-and-versions">Primitive versions, agent versions, statuses, and where `lua deploy` fits.</Card>
  <Card title="Automate releases in CI" href="/ship/ci-and-automation">The same commands in GitHub Actions with an approval gate.</Card>
</Columns>

<Columns cols={2}>
  <Card title="Back up and restore agent source" href="/ship/backups-and-restore">What a push backs up and how to restore.</Card>
  <Card title="lua version reference" href="/reference/cli/version">create, list, show, diff, promote, status, delete.</Card>
</Columns>
