Updates & rollback
hal0 updates itself in one atomic symlink swap, backed by cosign-verified release tarballs. If an update goes wrong, one command rolls back to the previous version.
The current release (as of 2026-05-22) is v0.1.0-alpha.1.
The layout
Section titled “The layout”The filesystem layout (PLAN §2) is FHS-aligned and deliberately separates the code from the data:
/usr/lib/hal0/current/ # symlink → /usr/lib/hal0-<version>//usr/lib/hal0-0.1.0-alpha.1/ # versioned install/usr/lib/hal0-0.1.0-alpha.2/ # versioned install (next)/etc/hal0/ # config, preserved across updates/var/lib/hal0/ # models, registry, OpenWebUI statehal0 update unpacks the new version next to the current one, then
swaps the current symlink in a single rename(2) call. The systemd
units point at /usr/lib/hal0/current/, so a systemctl restart
picks up the new version atomically. No partial state on disk, ever.
Check for an update
Section titled “Check for an update”hal0 update --checkHits https://releases.hal0.dev/stable.json and prints the latest
version on the channel without applying it. Same manifest the
curl hal0.dev/install.sh | bash bootstrap consumes.
Apply an update
Section titled “Apply an update”hal0 update # stable channelhal0 update --channel stable # explicitThe flow:
- Fetch the release manifest from
https://releases.hal0.dev/stable.json. - Verify the manifest signature (cosign keyless against the
cert_urlfrom the manifest; cosign 3.x requires--certificate). - Download the version tarball.
- Verify the tarball against
signer_identity+signer_issuer(GitHub OIDC, cosign). - Unpack to
/usr/lib/hal0-<new-version>/. - Swap
/usr/lib/hal0/current/to the new version (atomic). - Restart
hal0-api.service. - Slot units survive the restart — they keep serving traffic throughout.
releases.hal0.dev/stable.json is a Cloudflare Pages middleware proxy
that auto-syncs from the GitHub release: cut a v* tag on the hal0
repo, release.yml publishes the GH release, and the manifest URL
reflects it within ~60s. No hal0-web deploy needed.
Rollback
Section titled “Rollback”hal0 update --rollbackPoints current back at the previous versioned directory and
restarts. The data dirs (/etc/hal0, /var/lib/hal0) are untouched,
so your config, models, and registry are preserved.
Channels
Section titled “Channels”| Channel | What you get |
|---|---|
stable | Cut releases. The default and the only channel with a live publish pipeline today. |
nightly | Schema-reserved for every green main build. No publishing workflow yet. |
dev | Schema-reserved for ad-hoc dev cuts. No publishing workflow yet. |
Channels are configured in hal0.toml. Switch with
hal0 config edit or via the dashboard’s Settings view. Selecting
anything other than stable will currently fall back to stable —
the schema is in place, the cron-scheduled workflow that would
populate nightly.json / dev.json is not.
systemd does the lifecycle work
Section titled “systemd does the lifecycle work”Because every hal0 process is a systemd unit, the rest of the update mechanics are boring on purpose:
hal0-api.servicerestarts on the symlink swap.systemctl status hal0-apishows what version is now active.hal0-slot@*.serviceinstances survive the API restart; they keep serving traffic throughout.hal0-openwebui.servicerestarts alongside the API.- Every unit logs into journald under its unit name, so a failed
update shows up in
journalctl -u hal0-api -n 100without ceremony.
systemctl is-active hal0-api is the single binary check a homelab
monitor (uptime-kuma, Prometheus blackbox, whatever) should hit after
an update.
Why atomic
Section titled “Why atomic”The naive approach (tar xf … && systemctl restart) has two failure
modes that bite at 2am:
- Partial unpack. Disk fills mid-tar; you have half a new version overlaid on the old one. Nothing works.
- Restart loop. New binary crashes on start; systemd retries; no
obvious way back without a second SSH session and a working
mv.
Atomic symlink swap solves both: the new version is fully unpacked
before the swap, and the previous version is still on disk for
--rollback to point back at.