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

# Ship a new version

> Change what an SDK exposes without rewriting the contract of software already in production.

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:

```bash theme={null}
fused-cli extend support-sdk --service slack
```

`extend` reads the existing YAML to infer SDK mode, then opens the same operation selector as init. Existing services and operations remain in that 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:

```yaml theme={null}
name: support-sdk
version: "1.1.0"   # was 1.0.0
```

```bash theme={null}
fused-cli sdk plan
fused-cli sdk apply --download
```

Plan validates the local config before contacting the Engine. Use `sdk 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 sdk 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 the Engine is ahead of it.

<Note>
  Do not edit a generated package to impersonate another version. The Engine authorizes the opaque `app_id` embedded in the package, not a version number the client reports.
</Note>

## What carries across versions

| Thing            | Scope                                            |
| ---------------- | ------------------------------------------------ |
| SDK ID           | One per name, shared by every version            |
| Version ID       | One per explicit version, immutable              |
| Execution tokens | Shared across every active or deprecated version |
| Operation scope  | Enforced per version                             |

Because tokens belong to the SDK rather than a version, a new version that expands capability expands what existing tokens can reach. The plan reports which tokens are affected. If two teams must not share capability, give them different SDK names rather than different versions of one.

There is no implicit "latest." Every command that resolves a version wants `name@version` or a Version ID.

## Inspect what shipped

```bash theme={null}
fused-cli sdk list
fused-cli sdk show support-sdk@1.1.0
fused-cli sdk services support-sdk@1.1.0
fused-cli sdk buckets support-sdk
```

`sdk list` shows `SDK_ID`, stable across versions, and `VERSION_ID`, identifying one exact immutable version.

## Flags

### `sdk download`

| Flag     | What it does                                    | Example                                                      |
| -------- | ----------------------------------------------- | ------------------------------------------------------------ |
| `--out`  | Output directory                                | `fused-cli sdk download support-sdk@1.1.0 --out ./vendor`    |
| `--json` | Prints SDK, Version ID, status, and output path | `fused-cli sdk download support-sdk@1.1.0 --no-input --json` |

### `sdk list`

| Flag       | What it does | Example                          |
| ---------- | ------------ | -------------------------------- |
| `--limit`  | Rows to read | `fused-cli sdk list --limit 50`  |
| `--offset` | Rows to skip | `fused-cli sdk list --offset 50` |

### `sdk openapi`

| Flag          | What it does                                                   | Example                                                           |
| ------------- | -------------------------------------------------------------- | ----------------------------------------------------------------- |
| `--operation` | Exports one exact physical or Unified operation                | `fused-cli sdk openapi support-sdk@1.1.0 --operation issueUpdate` |
| `--out`       | Output file path                                               | `fused-cli sdk openapi support-sdk@1.1.0 --out ./support.yaml`    |
| `--format`    | `yaml` or `json`                                               | `fused-cli sdk openapi support-sdk@1.1.0 --format json`           |
| `--json`      | Prints export metadata only, including a `sha256:` of the file | `fused-cli sdk openapi support-sdk@1.1.0 --no-input --json`       |

`sdk 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 the Engine's state back down

```bash theme={null}
fused-cli sdk sync support-sdk -f .fused/sdks/support-sdk.yaml
```

Sync full-mirrors the exact Engine app version your local file declares. Anything the Engine no longer selects is removed locally rather than flagged, and Engine values win on conflict. There is no implicit latest lookup and no sync-time upgrade — change `version` yourself, then plan and apply it deliberately.

One quirk worth expecting: sync freezes the current selection into an explicit sorted operation list, so a service configured with `select_all: true` does not come back as `select_all: true`.

## Retiring a version

Permanently deactivate one exact immutable version by name and version or by Version ID:

```bash theme={null}
fused-cli sdk deactivate support-sdk@1.0.0
```

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. The Engine 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.

<Card title="Issue execution tokens" icon="ticket" href="/docs/app/issue-tokens">
  A new version does not need a new token. It may need you to review the old ones.
</Card>
