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:
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 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.
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
livedoesn’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
liveDefaultonGET /v1/agents/{id}/aliases.truemeanslivedecides what runs.falsemeans a save still changes what runs.
For background, see the changelog entry Running an agent without a version selector will follow its live alias.
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
livekeeps 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
409andcode: "session_pointer_mismatch". A selector-less turn claimslive.
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 at save time. To fix it, deploy a version to live.
View version history
To view version history, follow these steps:
- Open the Agent.
- Click the arrow beside the save button (Save options).
- 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
livepoints at. It isn’t offered on the version that’s already live. - Publish to live deploys the version to
liveand 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:
- In the Agent editor, click Save options, then click View versions.
- Find the version that you want to return to.
- 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.
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
ensurefrom code with a preview alias as the deploy target. See Deploy a preview. - Deploy an existing version to it, as described in 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.
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:
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:
versionIdandversionNumber: the version the alias points at.revision: the number to send asIf-Matchwhen you deploy to the alias.expiresAt: when a preview expires. It’snullforlive.archivedAt: when the alias was archived, ornull.bindingNames: the names of its 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:
-
Read the alias and note its
revision: -
Send the version with that revision in
If-Match:
Replace the following:
AGENT_ID: the Agent’s IDYOUR_API_KEY: your Runtype API keyREVISION: therevisionfrom step 1IDEMPOTENCY_KEY: a unique string for this deploy, so a network retry doesn’t deploy twiceVERSION_ID: the version to deployreason: 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:
412withcode: "alias_revision_mismatch": someone deployed since you read the alias.actualholds the current revision. Read the alias again, check what changed, and retry.428: you omittedIf-Matchon alivealias that already exists.409withcode: "idempotency_key_reused": you reused anIdempotency-Keyfor a different deploy.422withcode: "alias_dependency_unresolved": the version references a saved tool, Flow, or Agent by a name that no longer exists or was renamed.refslists the names. Restore or rename the dependency, then deploy again.
API keys carry two deploy scopes:
AGENTS:DEPLOY:PREVIEWdeploys to and archives preview aliases. It can’t movelive.AGENTS:DEPLOY:LIVEdeploys to and rolls backlive.
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 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, ormaterialize. - The version deployed and the version it replaced.
- Who deployed it.
- Where the deploy came from: an
ensurerun, 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}/rollbackwith body{"steps": 2, "reason": "..."}andIf-Matchonlive - 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.versionIdruns that immutable version snapshot.agent.aliasruns 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:
Replace the following:
YOUR_SUITE_ID: the eval suite you want to runYOUR_API_KEY: your Runtype API keypr-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, orlegacy-live-row.legacy-live-rowmeans 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.
To set bindings on an alias that already exists, send the complete set:
Bindings behave as follows:
- Whole-set replacement. Each write states the complete set the alias
carries, so a name you stop sending stops resolving.
DELETEon 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
binddeployment 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_, orINTERNAL_is rejected withcode: "alias_binding_invalid". So are provider credential names such asANTHROPIC_API_KEY,OPENAI_API_KEY, andAWS_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:
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.
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.
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.
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.
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 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
liveback 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 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 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:
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_versionwithon_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.
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. 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: create and configure Agents
- Manage agents as code: keep Agent definitions in your repository, deploy previews from CI, and promote across organizations
- Agent tools: configure tool types and delegation
- Client tokens and domain restrictions: aim a browser client token at a specific version or release alias