Skip to content

Update and roll back

hal0 updates itself. The hal0 update CLI is a thin client over the daemon’s /api/updates/* surface, so the same code path runs whether you trigger an update from the shell or the dashboard. The actual swap is a cosign-verified, atomic symlink swap of /usr/lib/hal0/current — your config (/etc/hal0) and state (/var/lib/hal0) are untouched by the swap itself.

Terminal window
hal0 update --check

Fetches the release manifest for your channel and diffs it against the running version. It shows current → latest (channel) plus whether an update is available, and (when present) the release date, notes URL, digest, and signer identity. A revoked (yanked) release is never reported as available even if it’s newer.

Terminal window
hal0 update

Checks, then stages the update, shows you the release notes (highlights, breaking changes, migrations — pulled from the release manifest), asks for confirmation, and applies. Skip the confirmation prompt for scripted runs:

Terminal window
hal0 update --yes

The CLI polls the apply job until it reaches applied or failed. After a successful apply the daemon try-restarts hal0-api itself — the CLI never touches systemd.

To pin a specific version instead of the latest:

Terminal window
hal0 update --target v1.0.0

Three release channels are available: stable, preview, and nightly. Set your channel (it persists in hal0.toml), which also runs a check:

Terminal window
hal0 update --channel preview

The Settings → Updates panel showing current version, available update, and channel selector Settings → Updates: current version, available release, and channel selector.

  1. Fetch the release manifest for the channel.

  2. Download the release tarball plus its detached cosign signature into a per-version cache under /var/lib/hal0.

  3. Verify the SHA-256 digest against the manifest, then the signature with cosign verify-blob against the exact GitHub Actions OIDC identity declared in the manifest. A missing cosign binary or a failed verification aborts the update — nothing is swapped.

  4. Extract the tarball and run any forward config migrations the release needs — including, on a pre-v1.0 box, the one-time profiles.toml reseed described below.

  5. Swap the /usr/lib/hal0/current symlink atomically, then reinstall the code into the venv. A failed re-install rolls the symlink back so current and the venv never diverge.

  6. Re-render every slot’s systemd unit through the newly installed code. This step never bounces a running slot — the CLI shows a “N slots need restart” banner post-apply; pass --restart-slots to bounce only the slots left running the pre-update launch command.

  7. Record the prior symlink target in /var/lib/hal0/hal0.previous for rollback.

The profiles.toml reseed (a pre-v1.0 one-time wipe)

Section titled “The profiles.toml reseed (a pre-v1.0 one-time wipe)”

hal0’s seed profile catalogue is baked into code, not into /etc/hal0/profiles.toml — the file only ever holds your own custom entries. Older (pre-v1.0) installs could accumulate stale materialized seed rows in that file alongside your custom ones. As part of crossing the v1.0 schema boundary (any config still at schema_version < 2), hal0 update runs a one-time reset: it deletes profiles.toml outright, so the next config load serves the catalogue purely from code.

This is a real, destructive delete — not a merge — and it takes your custom profiles with it.

  1. Automatic backup, every time. Before the file is touched, hal0 copies it to /var/lib/hal0/backups/profiles-<UTC-timestamp>.toml (e.g. profiles-20260731T120000Z.toml). This backup is unconditional — it happens whether or not you have custom profiles.

  2. Consent, if you have custom profiles. If the file contains only materialized seed rows, the reset proceeds silently. If it contains profiles that aren’t part of the built-in catalogue, hal0 update stops and lists the exact custom profile names at risk, asking you to confirm before it deletes them.

  3. Headless runs default to skip, never wipe. Running non-interactively without --yes skips the reset entirely rather than deleting anything without a human present to confirm.

  4. No restore command. There is no hal0 profile restore or similar — recovering a wiped custom profile means manually copying the relevant [[profile]] block back out of the timestamped backup file into /etc/hal0/profiles.toml yourself.

Preserve your custom profiles before updating

Section titled “Preserve your custom profiles before updating”

Belt-and-suspenders beyond the automatic backup — do this before your first update past the v1.0 boundary if you have any hand-written entries in profiles.toml:

Terminal window
sudo cp /etc/hal0/profiles.toml ~/profiles.toml.bak

Note the names and settings of anything custom in there. After the update, if the reset ran, restore what you need by hand — either from your own copy, or from /var/lib/hal0/backups/profiles-<timestamp>.toml, which hal0 wrote for you automatically:

Terminal window
sudo cat /var/lib/hal0/backups/profiles-*.toml

Then re-add the custom [[profile]] blocks you want back into /etc/hal0/profiles.toml with hal0 config edit profiles (or hand-edit and hal0 config validate before reloading).

If an update misbehaves, revert to the previously installed tree:

Terminal window
hal0 update --rollback

Rollback reads /var/lib/hal0/hal0.previous, atomically swaps the current symlink back to it, then reinstalls that prior tree into the venv and re-renders every slot unit. Unlike an apply, a rollback does not try-restart hal0-api for you — the running process keeps serving the newer code until you restart it yourself. It warns (without erroring) if the previous tree is gone on disk, or if the current config’s schema version is ahead of what the previous tree understands — migrations are forward-only, so the older tree just parses what it can. If no previous-version record exists, there’s nothing to roll back to.

As covered above, rollback never restores profiles.toml — that’s a config-state change, not a code-tree change, and the two are deliberately decoupled.

Terminal window
hal0 update owui --check
hal0 update owui --target <digest>
hal0 update owui --yes --force

Independent of the main hal0 update flow — repins the bundled OpenWebUI container by SHA-256 digest.