# swb approve-release

Approves a release: the channel it moves moves to its version, in one write,
and each install following that channel takes the version.

## Synopsis

```
usage: swb approve-release <id> [--json]
```

## Arguments and flags

| Argument or flag | Takes | Default |
|---|---|---|
| `<id>` | The release's **id**, as [`swb releases`](/command-line/releases) prints it. Required. | — |
| `--json` | Nothing. Prints the release as the API answered it instead of the summary. | off |
| `--help`, `-h` | Prints the command's help and exits. | off |

## What it does

Calls `Mutation.approveRelease` with a client token minted once for the run.
The approval is one write: the release reads `approved`, by you, now, its
move's channel head moves to its version, carrying the head it replaced, you
as the mover and the release's id, and the installs the move reaches are
recorded under the release. Either all of it is written or none of it is.

Within a minute, every install whose subscription follows a moved channel has
a deploy of the new version, started by `RELEASE` and naming the release, as
its subscription says: offered under `manual`, deployed at once under `auto`,
and waiting for its approver under a gate. The approval itself deploys
nothing and changes no subscription.

Only a version that came through `beta` is approved: one `beta` was or had
been at when the release was assembled. A branch build, whose version
carries a prerelease identifier (`1.9.0-my-branch.3`), is refused as one; a
version `beta` takes later is released by assembling again. Where you
assembled the release yourself, the approval asks each environment the moved
channel reaches whether its owner may approve their own release, and is
refused where one says no.

## What it prints

The release as the control plane answered it:

```
Closer 1.9 (01JRELEASE): approved
assembled by Maria Ruiz at 2026-10-20 09:00; approved by Ana Ortiz at 2026-10-20 10:30
  closer stable 1.8.2 → 1.9.0
```

`--json` prints it as [`swb releases`](/command-line/releases) does.

## The operation and the permission

`Mutation.approveRelease`. The caller needs `swb.releases.approve` on the
tenant, which the `release-manager` role carries.

## The same act in the console

A release's page, Approve.

## Refusals and exit status

Exit status is 0 once the release is approved, and 1 on every refusal below.

| Refusal | When |
|---|---|
| `swb approve-release takes <id>` | The id is missing. |
| `not signed in or token expired — run swb login` | There is no usable credential. |
| `NotFound: Release <id> not found` | The tenant has no release with that id. |
| `ValidationFailed: …` naming a branch build | The move's version carries a prerelease identifier, and `beta` had not held it. |
| `ValidationFailed: …` naming the version | `beta` had not held the version when the release was assembled; where the newest page of the app's history was not the whole of it, the refusal says older entries were not read. |
| `Conflict: …` naming the state | The release is no longer `assembling` or `testing` — already approved, or `abandoned` because a later release of the app superseded it. |
| `Conflict: …` naming the head as it stands | The channel moved after the release was assembled; nothing moved, and the release still reads `assembling`. |
| `Conflict: …` naming the open release | Another release of the app was assembled while this approval was made. |
| `NotAuthorized: …` naming the environment and the app | You assembled the release, and an environment a moved channel reaches does not let an owner approve their own release. |
| `NotAuthorized: …` naming `swb.releases.approve` | The caller lacks the permission. |

## Example

```console
$ swb approve-release 01JRELEASE
Closer 1.9 (01JRELEASE): approved
assembled by Maria Ruiz at 2026-10-20 09:00; approved by Ana Ortiz at 2026-10-20 10:30
  closer stable 1.8.2 → 1.9.0
```
