Apus ships four update channels:

Stable builds usually ship to beta first, get vetted there, then get promoted to latest without a version bump. Maintainers can also publish directly to latest. Dist-tags are the source of truth for npm installs.

Switching channels

apus update --channel stable
apus update --channel extended-stable
apus update --channel beta
apus update --channel dev

--channel drives the update and persists the choice to update.channel in config after core update success. A refused or failed core update keeps the previous channel. The selected channel drives both install paths:

Channel npm/package installs git installs
stable dist-tag latest switches to the npm package at latest
extended-stable resolves the public npm extended-stable selector, verifies the exact selected package, and installs that exact version. Fails closed with no fallback to latest, beta, or dev. unsupported: Apus leaves the checkout unchanged and asks you to use a package installation
beta dist-tag beta, falling back to latest when beta is missing or older switches to the npm package at beta, falling back to latest when beta is missing or older
dev switches to a Git checkout, builds it, and reinstalls the global CLI fetches, rebases the checkout on the upstream main branch, builds, and reinstalls the global CLI

An explicit --channel stable or --channel beta switches a Git installation to a package installation. A bare apus update in a Git checkout with a previously stored stable or beta channel instead selects the corresponding Git tag. For these Git tag updates, Apus refreshes branches without adding force to their configured refspecs, then force-refreshes tags only from the release remote. The retained branch.main.remote setting takes precedence, followed by origin or the only configured remote. With multiple remotes and neither choice, set branch.main.remote to the remote that publishes releases before retrying. Recreated release tags replace their old copies; local-only tags are preserved. Tag pruning is disabled even when Git's fetch.pruneTags setting is enabled. These guarantees assume standard branch fetch mappings; custom remote.*.fetch mappings that explicitly include tags still follow Git's configured behavior. The normal CLI inspects these refs in a private repository before admitting an update, so a refused update leaves the installed checkout's refs unchanged.

For managed Gateways, successful switches refresh the service to the verified installation before checking readiness. A refused switch or verified rollback recovers the previous service; unverified recovery leaves it stopped for inspection.

For dev git installs, the default checkout is ~/apus (or $APUS_HOME/apus when APUS_HOME is set); override with APUS_GIT_DIR. Automatic update campaigns pin the upstream commit they announce, so the displayed list previews up to five commits from the exact target installed even if main advances during the countdown. A manual apus update --channel dev still targets the current upstream main.

To keep stable and dev in parallel, use two separate checkouts and point each gateway at its own.

One-off version or tag targeting

Use --tag to target a specific dist-tag, version, or package spec for a single update without changing the persisted channel:

# Install a specific version
apus update --tag 2026.4.1-beta.1

# Install from the beta dist-tag (one-off, does not persist)
apus update --tag beta

# Switch to the moving GitHub main checkout (persistent)
apus update --channel dev

# Install a specific npm package spec
apus update --tag apus@2026.4.1-beta.1

Notes:

Dry run

Preview what apus update would do without making changes:

apus update --dry-run
apus update --channel beta --dry-run
apus update --tag 2026.4.1-beta.1 --dry-run
apus update --dry-run --json

The dry run reports the effective channel, target version, planned actions, and whether a downgrade confirmation would be required.

Plugins and channels

Switching channels with apus update also syncs plugin sources:

Checking current status

apus update status

Shows the active channel (with the source that decided it: config, git tag, git branch, installed version, or default), install kind (git or package), current version, and update availability. It also shows the last recorded update run, including a failed fetch. Plain apus status uses cached Git refs without fetching. If the latest recorded update fetch in the current state directory failed, it shows update check stale: last update fetch failed with the failure's age and a short reason instead of up to date. Ahead/behind counts are labeled cached. A later update run with a completed fetch clears the warning, even if the rest of the update is skipped, fails, or rolls back. A manual git fetch does not clear the recorded warning. Use apus update status for a fresh availability check or run apus update again. apus status --deep also fetches for that check, without changing the ledger.

Tagging best practices

macOS app availability

Beta and dev builds may not include a macOS app release. That is fine:

Related