Skip to main content
An SDK version is immutable. That is the point: code that shipped last quarter keeps calling exactly what it was built against, while you publish something new alongside it.

Immutable means immutable

Re-applying identical content to the same version is a no-op — no regeneration, no token rotation. Change the services, operations, auth, injections, or language under an existing version and apply returns app_version_immutable. The fix is always the same: bump the version and publish that. The guided path updates the existing YAML rather than creating a second file:
extend reads the existing YAML to infer SDK mode and adds the listed Slack operations. Use --service 'slack' to add all Slack operations, or group services in one quoted value such as --service 'slack=chatPostMessage;linear=issueUpdate'. Omitted provider versions inherit existing App pins. Existing services and operations remain in the file, and the app keeps its stable SDK ID. When the requested merge changes a stable SemVer version, Fused infers the next minor version: 1.0.0 becomes 1.1.0. A terminal shows that successor in the combined confirmation before writing. The same deterministic inference works with --no-input. An idempotent extension keeps its current version. Pass --version when you want a different successor. A prerelease or non-SemVer version such as 2026-09-01 cannot be advanced safely and always requires an explicit successor. For the explicit lifecycle, edit the version in the existing file yourself:
Plan validates the local config before contacting Fused. Use app validate separately only when you need an offline-only check.

When the Registry moves under you

app_version_immutable is about something you changed. Its sibling is about something Fused changed: when the Registry advances the selection schema your published versions were built against, applying an older plan returns app_selection_schema_version_mismatch (HTTP 409), and fused-cli app sync refuses a version whose schema is newer than the CLI understands. Neither is a data loss. Re-plan so the selections are rebuilt against the current schema, then apply. If sync is the one complaining, upgrade fused-cli first — it is telling you Fused is ahead of it.
Do not edit a generated package to impersonate another version. Fused authorizes the opaque app_id embedded in the package, not a version number the client reports.

What carries across versions

Because tokens belong to the SDK rather than a version, a new version that expands capability expands what unrestricted tokens can reach. Tokens with an explicit operation allowlist remain limited to that list. Each call must satisfy both the token policy and the selected version’s scope. Use separate apps when teams need independent ownership and version lifecycles; see execution token policies for restricting callers within one app. There is no implicit “latest.” Every command that resolves a version wants name@version or a Version ID.

Inspect what shipped

app list shows one row per app with NAME, TYPE, the stable APP_ID, a version count, and the latest and stable version labels. app versions list support-sdk shows the app’s immutable versions with their VERSION_ID, status, and stable-target metadata. Use APP_ID for app-wide access and tokens; use an exact name@version or VERSION_ID for version-specific operations. Omit the name from app versions list to list versions across visible apps. For apps with hosted MCP delivery, the version listing also includes stable and version-pinned transport URLs.

Flags

app download

app list

app versions list

Pass an app name or its stable APP_ID to select one app. Use the ID when names are ambiguous. --limit and --offset page through versions; --json returns version records with pagination metadata. The --type filter belongs to app list.

app openapi

app openapi always writes a file and never prints the document to stdout. It needs your ordinary control credential and app.read — an execution token cannot authorize the export.

Pull Fused’s state back down

Sync full-mirrors the exact Fused app version your local file declares. Anything Fused no longer selects is removed locally rather than flagged, and Fused values win on conflict. There is no implicit latest lookup and no sync-time upgrade — change version yourself, then plan and apply it deliberately. Sync preserves the remote selection intent, including select_all: true. Explicit operation selections return as sorted operation lists. Auth references, connection scopes, and injections also come from that exact version’s saved definition.

Retiring a version

Permanently deactivate one exact immutable version by name and version or by Version ID:
Deactivation immediately removes that version’s runtime and package and leaves a tombstone, so the same SDK version cannot be recreated. Sibling versions and SDK-wide execution tokens remain intact. Fused App UI exposes the same action for one version or a selected group. There is no SDK deprecate or restore command in the CLI; use the App UI/API for those advisory lifecycle transitions.

Issue execution tokens

A new version does not need a new token. It may need you to review the old ones.