> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.runtype.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.runtype.com/_mcp/server.

# Agent versioning and publishing

Use Agent versioning to keep an immutable record of an Agent's configuration at a point in time, and to return the Agent to one of those snapshots.

## How versioning works

When you edit a saved Agent, you work on a draft. Saving records a version snapshot of the Agent's configuration. Publishing marks a version as the Agent's published version and deploys it to the Agent's `live` release alias. Later edits create another draft.

The following table compares draft and published versions:

| Draft                                              | Published                                    |
| -------------------------------------------------- | -------------------------------------------- |
| Content that you can edit before publishing        | Immutable content that you can return to     |
| Created when you save changes to an existing Agent | Created when you publish                     |
| Can become the published version                   | Remains in version history after replacement |

Runtype assigns an increasing number to each version snapshot, and the dashboard displays labels such as `v1` and `v2`. Saving creates a draft before you publish, so the first published version is not necessarily `v1`. A version entry can include a label, notes, a configuration summary, and a creation time.

Whether a save or a publish changes production traffic depends on your organization's live-default setting. Read [What runs when you do not name a version](#what-runs-when-you-do-not-name-a-version) before you rely on either.

## Save and publish from the dashboard

The Agent editor has a save button with an attached arrow, **Save options**, that opens the save menu.

* **Save version** saves your changes and records a draft version. After a save, the button reads **Saved**.
* **Save & publish** saves your changes and publishes the new version. It's in the **Save options** menu.
* **Publish to live** publishes changes you already saved. When that version is already live, it reads **Published** and is unavailable.

To make **Save & publish** the primary button, open **Save options** and turn on **Publish on save**. The setting is off by default. Runtype remembers it for this Agent in this browser, and changing it doesn't save or publish anything. With **Publish on save** on, **Save version only** in the menu saves without publishing.

Publishing uses the exact version that the save created. If publishing fails, **Retry publish** retries that version without creating another one. The message stays in the editor after the notification closes. If someone else deployed to `live` while you were publishing, click **Review deployment** before you try again. An Agent managed in code asks you to confirm the overwrite first. For details, see [Deploying an Agent managed in code](#deploying-an-agent-managed-in-code).

## What runs when you do not name a version

A request that names no `agent.alias` and no `agent.versionId` follows your organization's live-default setting, which can differ between organizations. To find out which one applies, use either of these checks:

* In the dashboard, open the Agent page. When the Agent has saved edits that `live` doesn't run, the **Live** line reads **Saved edits are not deployed to live** with the setting on, and **Unpublished edits are serving traffic** with it off.
* From code, read `liveDefault` on `GET /v1/agents/{id}/aliases`. `true` means `live` decides what runs. `false` means a save still changes what runs.

For background, see the changelog entry [Running an agent without a version selector will follow its live alias](https://runtype.com/changelog/agent-live-release-default).

**With the live default off**, a selector-less request runs the Agent's saved configuration. A save reaches production immediately, whether or not you publish afterward.

**With the live default on**, a selector-less request runs the exact version that the `live` alias points at:

* Saving stops changing what runs. A save records a candidate version, and `live` keeps serving until you deploy. The Agent page marks an Agent whose saved edits are not deployed.
* **Publish to live** and **Rollback** move production, and each writes a deployment receipt.
* An Agent that was never published doesn't refuse. Its first selector-less run deploys its current configuration as its first version.
* A conversation bound to a preview alias refuses a turn that names no selector, with `409` and `code: "session_pointer_mismatch"`. A selector-less turn claims `live`.

Agents created from the dashboard, from a template, from quick start, or as part of a Product are deployed to `live` when they're created. An Agent created by `runtype ensure` without publishing stays undeployed on purpose.

Three cases run their saved configuration under either setting: `external` Agents, Claude Managed Agents, and Agents in a personal account. Explicit selectors resolve the version they name under either setting.

If an Agent's `live` alias has nothing runnable, a selector-less request refuses with `404` and `code: "AGENT_NOT_DEPLOYED"` instead of running a draft. Runtype reports this before a run, too. The create, read, and update responses of an eval suite that targets the Agent include a `warnings` entry with `code: "AGENT_NOT_DEPLOYED"`, and a Flow whose `execute-agent` step names it reports [`EXECUTE_AGENT_TARGET_NOT_DEPLOYED`](/user-guide/flows/flow-validation-warnings) at save time. To fix it, deploy a version to `live`.

## View version history

To view version history, follow these steps:

1. Open the Agent.
2. Click the arrow beside the save button (**Save options**).
3. Click **View versions**.

The **Version History** panel lists version labels, status badges, alias badges, configuration summaries, creation times, and notes. The current published version has a **live** badge. A superseded published version has a **previously published** badge. A version that a preview alias points at shows that alias's name.

When you have unsaved changes, the panel shows a **Current draft** entry with an **unsaved** badge. Its note says that loading or publishing another version discards those changes, but neither does. **Load** leaves the editor as it is, and publishing another version keeps your unsaved edits in the editor.

## Publish an earlier version

Each version in the **Version History** panel has these actions:

* **Load** fetches the version and confirms it in a notification. It doesn't change the Agent or the editor. To see what a version contains, use **Compare to live**.
* **Compare to live** opens a read-only comparison against the version that `live` points at. It isn't offered on the version that's already live.
* **Publish to live** deploys the version to `live` and marks it as published. It's unavailable on the version that's already live.

To return an Agent to an earlier version, follow these steps:

1. In the Agent editor, click **Save options**, then click **View versions**.
2. Find the version that you want to return to.
3. Click **Publish to live** beside it. On an organization Agent, click **Publish** in the confirmation dialog.

On an organization Agent, the confirmation names the version that `live` runs now and the version it switches to. The version changes for everything that runs this Agent.

The **Deployments** tab offers the same actions from the alias side. **Rollback** on the **Deployment history** card moves `live` back one deployment. **Publish to live** beside a preview alias deploys the version that preview runs.

The dashboard sends the alias revision it read. If someone else deployed in the meantime, the deploy is refused and a notification offers **Reload**. **Reload** reads the alias again and reopens the confirmation, and nothing changes until you confirm.

Publishing writes the version's configuration back to the Agent, marks the version as published, and moves `live` in one step. The editor then reloads the saved Agent and keeps any unsaved edits you had open.

For Runtype and external Agents, the write covers the Agent's name, description, icon, runtime configuration, capabilities, and external connection configuration recorded in the snapshot. Runtime configuration is replaced, not merged, so settings added after the version was saved don't stay active.

Publishing also clears tool attachments that the version didn't record: tools, MCP servers, runtime tools, subagent and code mode blocks, and approval settings. A tool that you attached after the version was saved doesn't survive publishing that version.

A version without a stored configuration can't be published. The dashboard reports this when you click **Publish to live**.

### What publishing cannot restore

Publishing keeps these fields as they are and reports them in `applied` and `warnings`:

* **Claude Managed runtime settings and capabilities.** Publishing an older version doesn't change a Claude Managed Agent's runtime configuration, hosted settings, credentials, or capabilities. To apply an older hosted definition, edit the Agent to match it and save.
* **Capabilities whose backing resource was deleted.** If an older capability refers to a Flow, Agent, or tool that no longer exists, Runtype keeps the current capability set and names the missing capability in a warning.
* **Fields missing from older snapshots.** An older snapshot without runtime configuration or capabilities keeps the current value and reports the gap.

## Deploying an Agent managed in code

When `ensure` manages an Agent, the editor shows a **Managed in code** badge. Publishing a version from the dashboard is refused by default, so it can't silently detach the Agent from code management. The dashboard opens a confirmation dialog. Clients that can't show a dialog must select overwrite explicitly. The next `ensure` run then reports the change as an external modification. For the conflict options, see [Manage agents as code](/user-guide/agents/manage-agents-as-code).

When the deployment that put the current version on `live` came from code, the **Live** line on the Agent page offers **Copy definition**. Code means an `ensure` run, the CLI, or an SDK call. **Copy definition** copies the Agent's definition to your clipboard, so you can add a dashboard edit to your repository before the next `ensure` run overwrites it.

## Release aliases

A **release alias** is a named, movable pointer from an Agent to one of its immutable versions. Deploying moves the pointer and never rewrites the version. After the first mention, this page calls it an alias.

`live` is the built-in alias that production traffic follows. It can't be archived and never expires. You can't create an alias named `live`, `latest`, `publish`, or `none`. Every other name matches `^[a-z0-9][a-z0-9-]{0,62}$`: up to 63 lowercase letters, digits, and hyphens, starting with a letter or digit.

Aliases are an organization feature. An Agent in a personal account has no release aliases. A request to deploy one is refused with `400` and `code: "alias_requires_organization"`.

### Preview aliases

Any alias other than `live` is a preview. You can create one in two ways:

* Run `ensure` from code with a preview alias as the deploy target. See [Deploy a preview](/user-guide/agents/manage-agents-as-code#deploy-a-preview).
* Deploy an existing version to it, as described in [Deploy a version to an alias](#deploy-a-version-to-an-alias).

A typical name is the pull request that produced it, such as `pr-482`.

A preview selects configuration. It isn't a sandbox: it shares the organization's connections, Records, and secrets with `live`. To point one preview's tools at its pull request's own environment, use [per-alias secret bindings](#per-alias-secret-bindings).

A preview expires 14 days after the deploy that last touched it. Every successful deploy renews that expiry, including an `ensure` run that changed nothing, so a pull request that keeps building keeps its preview.

There is no limit on how many previews an organization or an Agent holds. Archive a preview when you no longer need it, for example when its pull request closes. A preview that nothing renews expires on its own.

### Find a version ID

To deploy or run a specific version, you need its version ID. Use one of these reads:

| Read                      | API                                            | CLI                                              | MCP tool                      |
| ------------------------- | ---------------------------------------------- | ------------------------------------------------ | ----------------------------- |
| List an Agent's versions  | `GET /v1/agent-versions/{agentId}`             | `runtype agent-versions list AGENT_ID`           | `list_agent_versions`         |
| Get one version           | `GET /v1/agent-versions/{agentId}/{versionId}` | `runtype agent-versions get AGENT_ID VERSION_ID` | `get_agent_version`           |
| Get the published version | `GET /v1/agent-versions/{agentId}/published`   | `runtype agent-versions published AGENT_ID`      | `get_published_agent_version` |

The **Aliases** card on the **Deployments** tab also shows the version each alias points at.

### Inspect aliases

`GET /v1/agents/{id}/aliases` lists an Agent's aliases, with `live` first. `GET /v1/agents/{id}/aliases/{alias}` reads one. Archived aliases are left out unless you pass `includeArchived=true`. The CLI equivalents are `runtype agents aliases list AGENT_ID` and `runtype agents aliases get AGENT_ID ALIAS`, which take `--include-archived`.

Each alias carries these fields:

* `versionId` and `versionNumber`: the version the alias points at.
* `revision`: the number to send as `If-Match` when you deploy to the alias.
* `expiresAt`: when a preview expires. It's `null` for `live`.
* `archivedAt`: when the alias was archived, or `null`.
* `bindingNames`: the names of its [per-alias secret bindings](#per-alias-secret-bindings).

### Deploy a version to an alias

Once `live` exists, a deploy to it must send the `revision` that you read as an `If-Match` header, so a deploy based on an old read can't overwrite someone else's. The first deploy to `live` has no revision to send. Previews accept the same header and don't require it.

To deploy a version to `live`, follow these steps:

1. Read the alias and note its `revision`:

   ```bash
   curl https://api.runtype.com/v1/agents/AGENT_ID/aliases/live \
     -H "Authorization: Bearer YOUR_API_KEY"
   ```

2. Send the version with that revision in `If-Match`:

   ```bash
   curl -X PUT https://api.runtype.com/v1/agents/AGENT_ID/aliases/live \
     -H "Authorization: Bearer YOUR_API_KEY" \
     -H "Content-Type: application/json" \
     -H "If-Match: REVISION" \
     -H "Idempotency-Key: IDEMPOTENCY_KEY" \
     -d '{"versionId": "VERSION_ID", "reason": "Fix refund wording"}'
   ```

Replace the following:

* `AGENT_ID`: the Agent's ID
* `YOUR_API_KEY`: your Runtype API key
* `REVISION`: the `revision` from step 1
* `IDEMPOTENCY_KEY`: a unique string for this deploy, so a network retry doesn't deploy twice
* `VERSION_ID`: the version to deploy
* `reason`: optional text recorded on the deployment receipt

The same deploy is available in the other clients:

* CLI: `runtype agents aliases activate AGENT_ID live --version-id VERSION_ID --revision REVISION --reason "Fix refund wording"`
* TypeScript SDK: `client.agents.aliases.activate(agentId, 'live', { versionId, revision, idempotencyKey, reason })`
* MCP: `activate_agent_alias`

The deploy can fail with these responses:

* `412` with `code: "alias_revision_mismatch"`: someone deployed since you read the alias. `actual` holds the current revision. Read the alias again, check what changed, and retry.
* `428`: you omitted `If-Match` on a `live` alias that already exists.
* `409` with `code: "idempotency_key_reused"`: you reused an `Idempotency-Key` for a different deploy.
* `422` with `code: "alias_dependency_unresolved"`: the version references a saved tool, Flow, or Agent by a name that no longer exists or was renamed. `refs` lists the names. Restore or rename the dependency, then deploy again.

API keys carry two deploy scopes:

* `AGENTS:DEPLOY:PREVIEW` deploys to and archives preview aliases. It can't move `live`.
* `AGENTS:DEPLOY:LIVE` deploys to and rolls back `live`.

A CI credential with only the preview scope can't reach production, whatever the workflow asks it to do.

### Archive a preview

Archive a preview when its pull request closes. See [A pull-request workflow](/user-guide/agents/manage-agents-as-code#a-pull-request-workflow) for the CI job. Expiry cleans up previews that nobody archived.

To archive one preview, use one of these:

* Dashboard: on the **Deployments** tab, click the **Archive** button beside the alias, then confirm.
* API: `DELETE /v1/agents/{id}/aliases/{alias}`
* CLI: `runtype agents aliases archive AGENT_ID ALIAS`
* MCP: `archive_agent_alias`

Archiving isn't a delete. The alias keeps its deployment history, runs that already started finish, and a later deploy revives the same alias. New requests that name an archived alias are refused and don't fall back to `live`. No request can archive `live`: the attempt answers `409` with `code: "alias_archive_forbidden"`.

A request that names an alias or version that Runtype can't run answers `404` with one of these codes: `alias_not_found`, `alias_archived`, `alias_expired`, `version_not_found`, or `agent_not_found`. None of them falls back to another version.

## Deployment history

Every deploy appends an immutable **deployment receipt**. A receipt records the following:

* The alias and its new revision.
* The action: `activate`, `rollback`, `archive`, `bind`, or `materialize`.
* The version deployed and the version it replaced.
* Who deployed it.
* Where the deploy came from: an `ensure` run, the dashboard, the CLI, an SDK, an MCP tool, an API call, or Runtype itself.
* Any label, notes, commit, and reason sent with it.
* Fingerprints of the named references the version used at that moment.

Receipts never record a secret value. Per-alias bindings appear on them as names only.

Read the history with `GET /v1/agents/{id}/deployments`, filtered to one alias with `?alias=`, or with `runtype agents deployments list AGENT_ID --alias live`. In the dashboard, open the Agent and select the **Deployments** tab:

* The **Aliases** card lists every alias with the version and revision it carries. Each alias offers **Test this version**, which runs a conversation against that alias without loading it into the editor. A preview also offers **Compare to live**, **Publish to live**, and an archive button.
* The **Deployment history** card lists receipts newest first, marked **Deployed**, **Rolled back**, **Archived**, or **Materialized**.

A **Materialized** receipt is one Runtype wrote itself so that `live` names a runnable version. Its version carries a label such as `agent-created`, `live-materialization`, or `live-default-cutover`, and a note that explains why. A `live-materialization` version holds the configuration the Agent was already running when Runtype gave it a `live` alias, so behavior didn't change.

### Roll back an alias

**Rollback** moves an alias back to the version recorded before its most recent deploy and writes another receipt. Nothing is deleted and no version is rewritten. In the dashboard, **Rollback** moves `live` back one deploy.

From code, you can walk further back with `steps` (1 to 50, default 1). Only deploys, rollbacks, and materializations count as steps. Binding changes and archives don't.

* API: `POST /v1/agents/{id}/aliases/{alias}/rollback` with body `{"steps": 2, "reason": "..."}` and `If-Match` on `live`
* CLI: `runtype agents aliases rollback AGENT_ID live --steps 2 --revision REVISION`
* TypeScript SDK: `client.agents.aliases.rollback(agentId, 'live', { steps, revision, reason })`
* MCP: `rollback_agent_alias`

Rollback follows the same scope, `If-Match`, and dependency rules as a deploy. It restores configuration only. It doesn't undo external side effects, data written by the version you're leaving, or edits made since to the tools and Flows that the version references by name.

## Run a specific version

A request can name the version it wants instead of taking the saved configuration. On `POST /v1/dispatch` and `POST /v1/agents/{agentId}/execute`, supply exactly one selector beside the Agent identity:

* `agent.versionId` runs that immutable version snapshot.
* `agent.alias` runs the version that the release alias points at.

A selector runs a stored snapshot, so you can't combine it with inline definition fields such as `model`, `systemPrompt`, or `tools`. Naming both `alias` and `versionId` is rejected. An alias that doesn't exist answers `404` instead of falling back to the saved configuration. Selectors aren't available for `external` or Claude Managed Agents.

A conversation binds to the first alias or version it runs. A later turn on the same `conversationId` that names a different version or alias is refused with `409` and `code: "session_pointer_mismatch"`. Start a new conversation for the other alias or version.

## Evaluate a version before deploying it

An eval run can name the version it evaluates, so the version you grade is the version you deploy. Supply the same selector on the eval request:

```bash
curl -X POST https://api.runtype.com/v1/eval/suites/YOUR_SUITE_ID/run \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"agent": {"alias": "pr-482"}}'
```

Replace the following:

* `YOUR_SUITE_ID`: the eval suite you want to run
* `YOUR_API_KEY`: your Runtype API key
* `pr-482`: the release alias you want to evaluate

`POST /v1/eval/suites/{suiteId}/run`, `POST /v1/eval/run`, and `POST /v1/eval/submit`
all accept `agent.alias` or `agent.versionId`. The MCP `run_eval_suite` and
`submit_eval` tools expose them as `agent_alias` and `agent_version_id`. The CLI's
`runtype eval run` takes `--alias ALIAS` or `--version-id VERSION_ID`.

The run resolves the selector **once**, before its first case. Deploying to the alias
while the run is in progress doesn't change what its later cases run, and a
retry runs the same version again. The selector belongs to the run, not to the
suite. A suite is a fixed case set, and you choose the version when you run it.

Every run records what it evaluated, and the eval read surfaces return it:

* `agentVersionId`: the exact version every case ran.
* `agentTargetResolution`: `alias`, `version`, or `legacy-live-row`. `legacy-live-row` means the
  run named no selector and ran the Agent's saved configuration.
* `agentTargetAlias`: the release alias the run resolved through.
* `caseManifestHash`: SHA-256 over the case set the run used, so you can tell an edited or
  reordered suite from the one that produced the evidence.
* `evaluatorFingerprint`: SHA-256 over the judges and grading configuration the
  run scored with.

Runtype records that evidence but doesn't enforce it. You don't need a passing run
to deploy a version, and a failing run doesn't block or reverse a deploy.
Decide with the evidence, then deploy. A run that resolved a single target gives
you the exact version ID to deploy.

Selectors aren't available for `external` or Claude Managed Agents on evals either.
An eval request that names one answers `422` with
`code: "selector_unsupported_agent_type"`. A suite that targets a Flow has no version
selector and answers `400`.

## Per-alias secret bindings

A preview alias shares its organization's credentials and configuration by
default. That doesn't work when a preview needs to call its own environment. For
example, an Agent whose tools make HTTP calls into your application has to call
the environment that its pull request deployed, not the one `live` calls.

Bind the value to the alias instead of putting it in the definition. A binding
is a `{{secret:NAME}}` value that runs reaching this Agent through this
alias use **ahead of** the organization secret of the same name. The
version's content stays identical to what `live` runs, so any evaluation
evidence on that version still applies.

```ts
await client.agents.ensure(definition, {
  deploy: {
    alias: `pr-${pullRequest}`,
    bindings: { RRX_TOOLS_BASE_URL: `https://pr-${pullRequest}.example.com` },
  },
})
```

To set bindings on an alias that already exists, send the complete set:

```bash
curl -X PUT https://api.runtype.com/v1/agents/$AGENT_ID/aliases/pr-482/bindings \
  -H "Authorization: Bearer $RUNTYPE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"bindings": {"RRX_TOOLS_BASE_URL": "https://pr-482.example.com"}}'
```

Bindings behave as follows:

* **Whole-set replacement.** Each write states the complete set the alias
  carries, so a name you stop sending stops resolving. `DELETE` on the same
  path clears every binding.
* **Write-only values.** Values are encrypted at rest, and no read returns one.
  `GET .../bindings`, the alias itself (`bindingNames`), the deployment receipt,
  and the audit log carry names only.
* **Bindings belong to the alias, not the version.** Changing them increases the alias
  revision and appends a `bind` deployment receipt without changing the version.
  Archiving or expiring the alias removes them with it.
* **Limits.** An alias carries at most 25 bindings, and each value is at most 4096
  characters. Each name uses uppercase letters, digits, and underscores, starts
  with a letter, ends with a letter or digit, and is 2 to 100 characters long.
* **Provider and platform names are refused.** Runtype resolves these names itself,
  so a binding would have no effect. A name that starts with `RUNTYPE_`, `PLATFORM_`,
  `CLOUDFLARE_`, or `INTERNAL_` is rejected with `code: "alias_binding_invalid"`.
  So are provider credential names such as `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`,
  and `AWS_ACCESS_KEY_ID`.
* **Bindings apply to the Agent the request named.** A nested sub-Agent, a
  Claude Managed session, and a detached sub-Agent run resolve their own
  aliases, so they read organization secrets instead of the parent's bindings.

Bindings override configuration for one preview. They don't isolate it:
everything else about a preview, including its data, credentials, and memory,
still comes from the organization.

## Memory namespaces and release pointers

Agent memory is keyed by the **subject** it's about, never by the Agent's configuration version. A new version, a preview alias, and a request pinned to a `versionId` all read and write the same memory the Agent already had. Sharing is the default, and it works until a preview alias starts writing memory that live traffic shouldn't see.

You choose the isolation. Three read-only variables pass the alias or version that a run resolved through into the memory profile template:

| Variable               | Value                                                                                                                          | Present when                                            |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------- |
| `{{_agent.alias}}`     | The release alias the request named, including `live`                                                                          | The request supplied `agent.alias`                      |
| `{{_agent.versionId}}` | The immutable version the run is pinned to                                                                                     | The request supplied `agent.alias` or `agent.versionId` |
| `{{_agent.version}}`   | That version's human label, when the version carries one. Display only: free text, not unique, absent on an unlabelled version | The pinned version has a label                          |

All three are **absent** when the request named no selector. `{{_agent.alias}}` is also absent when the request pinned a bare `agent.versionId`, because a version ID belongs to no particular alias. A template variable that Runtype can't resolve turns memory off for that run instead of falling back to a shared bucket. Write a fallback (`{{_agent.alias || "live"}}`) unless you want memory off on those runs.

### The namespace ladder

Climb one rung only when the product needs it. Each rung shows the value the template resolves to for an end user `dana` on an Agent whose `live` alias and `pr-482` preview both run. Runtype then prefixes that value with the owning organization to form the stored profile ID, so the values shown are the part you control.

**1. Shared.** Omit `profileTemplate`. Every version, alias, and pinned request shares one bucket per Agent.

```text
profileTemplate: (unset, defaults to {{_agent.id}})
live      -> agent_01j...
pr-482    -> agent_01j...      (the same bucket)
```

Move on when the Agent serves more than one end user.

**2. Per end user.** Required on any Product Surface that serves many end users. Runtype turns memory off when a multi-end-user Surface resolves a template with no end-user identity.

```text
profileTemplate: {{_endUser.id}}
live      -> dana
pr-482    -> dana              (the same bucket)
```

Move on when a preview alias starts writing memory.

**3. Previews isolated, live shared.** Each preview alias gets its own bucket. `live` keeps the one it already had, so preview traffic doesn't touch production memory.

```text
profileTemplate: {{_endUser.id}}/{{_agent.alias || "live"}}
live               -> dana/live
pr-482             -> dana/pr-482
no selector        -> dana/live
agent.versionId    -> dana/live
```

Changing the template changes the bucket. The memory an Agent already built on rung 2 stays under the old profile, and `live` starts empty at `dana/live`. Move up the ladder before the Agent has memory you care about, or copy the old bucket forward with the memory tools.

The `|| "live"` fallback keeps ordinary traffic on one bucket: a request with no selector and a request pinned to a bare `agent.versionId` both resolve the fallback. To keep production traffic that's pinned to an exact version on the shared bucket, deploy that version to an alias and select the alias instead of sending a raw `versionId`.

Move on when behavior has to be reproducible per version.

**4. Per version.** Every version starts empty. Use this for regulated or evaluation-driven setups where a version's behavior must not depend on memory another version wrote.

```text
profileTemplate: {{_endUser.id}}/{{_agent.versionId || "live"}}
live               -> dana/agentver_01j...
pr-482             -> dana/agentver_01k...
no selector        -> dana/live
agent.versionId    -> dana/agentver_01j...
```

Keep the fallback unless you mean it. Written as a bare `{{_endUser.id}}/{{_agent.versionId}}`, this rung turns memory off for every request that selects no version, which is most ordinary traffic. Validation reports [`MEMORY_POINTER_TEMPLATE_UNGUARDED`](/user-guide/flows/flow-validation-warnings#pointer-keyed-memory-template-has-no-fallback) when a pointer variable has no fallback.

Key on `{{_agent.versionId}}`, never `{{_agent.version}}`. The label is free text, isn't unique across versions, and is absent on a version nobody labeled, so it makes a poor bucket key.

**5. Environment-mapped.** When one Agent serves several environments, map the alias to the namespace you want instead of adding a rung. `{{_endUser.id}}/{{_agent.alias || "live"}}` already does this when each environment has its own alias. A per-dispatch `agentInput.memory.profileTemplate` override lets a CI run choose its own bucket without editing the Agent. Two separate Agents give the strongest separation, because they share nothing.

Runtype doesn't copy live memory into a preview bucket. Copy it yourself with the memory tools.

### What happens on rollback and alias changes

The bucket follows the template:

* **Rollback** (moving `live` back to an earlier version) keeps the same bucket on rungs 1 to 3. On rung 4 it moves back to that version's own bucket, where the earlier version reads what it wrote before.
* **Deploying a newer version to an alias** (for example, to `pr-482`) keeps the alias's bucket on rungs 1 to 3 and starts a fresh bucket on rung 4.
* **Archiving or expiring a preview alias** doesn't delete what it wrote. The bucket stays until you remove it.

### Agents with a Tenancy Strategy

When an Agent sets a `tenancyStrategy`, Runtype builds the namespace from the resolved tenant and end user and ignores `profileTemplate`. The template variables have no effect. Set `memory.pointerScope` instead:

* `"shared"` (the default) keeps one bucket across every version and alias.
* `"alias"` gives each release alias its own bucket.
* `"version"` gives each version its own bucket.

`pointerScope` applies **only** to an Agent that sets a `tenancyStrategy`. On any other Agent the field has no effect, because memory there uses the template. Runtype reports [`MEMORY_POINTER_SCOPE_IGNORED`](/user-guide/flows/flow-validation-warnings#memory-pointer-scope-has-no-effect) so the field doesn't look like isolation. A run that resolved no alias or version, such as a request with no selector, uses the shared bucket.

The pointer scope separates memory. It doesn't restrict access: preview aliases still share the organization's credentials, Records, and integration connections.

The validators report [`MEMORY_SHARED_ACROSS_POINTERS`](/user-guide/flows/flow-validation-warnings#memory-is-shared-across-every-version-and-alias) as a recommendation when an Agent turns on memory and keys it on neither the variables nor `pointerScope`.

## Publish from the API

`POST /v1/agent-versions/{agentId}/publish` applies the stored snapshot to the Agent and marks that version as published, in one step. Send `versionId` in the request body. The TypeScript SDK exposes the same operation:

```typescript
const result = await client.agentVersions.publish(agentId, versionId)
console.log(result.applied, result.warnings, result.lastModifiedSource)
```

For an Agent managed in code, the default returns `409` with `code: "managed_by_code_conflict"`. After explicit confirmation, use the option for your client:

* REST and TypeScript SDK: `onConflict: "overwrite"`
* CLI: `runtype agent-versions publish AGENT_ID --version VERSION_ID --overwrite-managed`
* MCP: `publish_agent_version` with `on_conflict: "overwrite"`
* Code Mode: `{ onConflict: "overwrite" }`

Inspect `applied` and `warnings` to see which parts of the snapshot were restored.

`POST /v1/agents/{id}/publish` snapshots the Agent's current saved configuration as a new published version.

On an organization Agent, both routes also deploy the published version to `live` in the same step and append a deployment receipt. An Agent in a personal account has no release aliases, so those routes only record the published version. To deploy to a preview alias, see [Deploy a version to an alias](#deploy-a-version-to-an-alias).

## Best practices

Use these practices to manage Agent changes:

* Save small, incremental changes so each version snapshot is a short step back.
* Know which step reaches production for your organization, from [What runs when you do not name a version](#what-runs-when-you-do-not-name-a-version). Test the Agent first either way. Try a change on a non-production Product before you put it on an Agent that production traffic uses.
* Review conversations and activity after you deploy.
* Give the version a label when you deploy from CI, so the deployment history shows which commit produced what is running.
* To go back to an earlier configuration, click **Publish to live** beside that version in **Version History**. Then read the notification for anything the deploy couldn't restore.

## Next steps

Continue with these Agent guides:

* [Creating and configuring Agents](/user-guide/agents/creating-and-configuring-agents): create and configure Agents
* [Manage agents as code](/user-guide/agents/manage-agents-as-code): keep Agent definitions in your repository, deploy previews from CI, and promote across organizations
* [Agent tools](/user-guide/agents/agent-tools): configure tool types and delegation
* [Client tokens and domain restrictions](/user-guide/products-surfaces/client-tokens-and-domain-restrictions): aim a browser client token at a specific version or release alias