Upgrade
Check for upgrades
Section titled “Check for upgrades”Each node shows its update status in the MOTD when you SSH in:

The notice lists the overall version bump and the roles whose version actually changed. If nothing changed, the notice is absent.
A systemd user timer (odio-check-upgrade.timer) reruns the check daily. Run it on demand to see the result on stdout:
odio@raspodio:~ $ odio-upgrade checkUpgrades available: dev-8e978895 → 2026.5.0b1Or trigger the user unit, with the result landing in the user journal:
systemctl --user start odio-check-upgrade.serviceApply an upgrade
Section titled “Apply an upgrade”Trigger the systemd user unit:
systemctl --user start odio-upgrade.serviceIt re-runs the installer with the feature selection from the previous run. Since 2026.5.0b1, it only re-runs the roles that actually changed in the target release (smart upgrade), bringing most upgrades down to a handful of roles.
For flags, call the script directly:
odio-upgrade apply # same as the unitodio-upgrade apply --version 2026.5.0b1 # pin a release tagodio-upgrade apply --dry-run --force # print the derived env, no changesOpen PRs are published as pr-<N> pre-releases (see CI/CD), so testing a PR before merge is the same call:
odio-upgrade apply --version pr-52The installer is idempotent and safe to re-run. When a config file has been locally modified, it creates a <config>.bak before applying changes; if the file ends up identical, no backup is kept (Bluetooth, MPD, mpd-discplayer, odio-api, PipeWire, shairport-sync, spotifyd, upmpdcli).
Bootstrap (cold install)
Section titled “Bootstrap (cold install)”Fresh install:
curl -fsSL https://beta.odio.love/install | bashPin a release tag:
curl -fsSL https://github.com/b0bbywan/odios/releases/download/2026.5.0b1/install.sh | ODIOS_VERSION=2026.5.0b1 bashIf the node was installed before 2026.4.2b1, it lacks the odio-upgrade helper. Each release ships it as a standalone asset, so it can run before being installed:
curl -fsSL https://odio.love/upgrade -o /tmp/odio-upgradechmod +x /tmp/odio-upgrade/tmp/odio-upgradeThe next run finds the helper installed in /usr/local/bin and the state file at /var/lib/odio/state.json.
Opt out of a role or feature
Section titled “Opt out of a role or feature”odio-upgrade is opt-out: only entries listed in state.json map to INSTALL_*=N. Everything else, including roles or features added in a later release, is installed.
Edit /var/lib/odio/state.json and add the entry to the matching _excluded list, for example to keep branding and upnpwebradios off:
"roles_excluded": [ "snapclient", "spotifyd" "snapclient", "spotifyd", "branding"],"features_excluded": [ "tidal" "tidal", "upnpwebradios"]Verify and apply:
odio-upgrade apply --dry-run --force # print the derived INSTALL_* flagsodio-upgrade applyRemoving an entry opts back in.
State files behind the upgrade flow
Three files back the detection and upgrade flow:
-
Local state —
/var/lib/odio/state.json, written by the installer after each successful run and read byodio-upgrade apply. Tracks the odios version, install mode, target user, per-role versions, opt-in features, explicit opt-outs, and arelease_historyof the last odios versions installed on this node. The file is0640 root:odio:{"features": ["tidal","qobuz","upnpwebradios","mympd"],"features_excluded": [],"install_mode": "live","odios": "2026.5.0b1","release_history": ["2026.4.2b2","2026.5.0b1"],"roles": {"bluetooth": "2026.5.0b1","branding": "2026.5.0b1","common": "2026.5.0b1","mpd": "2026.5.0b1","mpd_discplayer": "2026.5.0b1","odio_api": "2026.5.0b1","pulseaudio": "2026.4.2b1","shairport_sync": "2026.4.1rc1","snapclient": "2026.4.0rc5","spotifyd": "2026.5.0b1","upgrade": "2026.5.0b1","upmpdcli": "2026.4.2b2"},"roles_excluded": [],"target_user": "odio"} -
Published manifest — odio.love/manifest.json, generated by CI on each release with the same shape. Each role version is the last odios release that touched that role.
-
Check result —
/var/cache/odio/upgrades.json, written byodio-upgrade check(the daily timer’s job) and read by the MOTD:{"current": "2026.4.2b2","latest": "2026.4.2b2","upgrade_available": false,"roles": [],"manifest": {"odios": "2026.4.2b2","roles": {"bluetooth": "2026.4.0rc5","branding": "2026.4.2b1","common": "2026.4.2b2","mpd": "2026.4.2b2","mpd_discplayer": "2026.4.2b1","odio_api": "2026.4.2b2","pipewire": "2026.4.0rc6","pulseaudio": "2026.4.2b1","shairport_sync": "2026.4.1rc1","snapclient": "2026.4.0rc5","spotifyd": "2026.4.2b1","upgrade": "2026.4.2b2","upmpdcli": "2026.4.2b2"}},"checked_at": "2026-05-07T19:32:34Z"}