Skip to content

Support immutable distro install layouts #24

@Staphylococcus

Description

@Staphylococcus

Problem statement

LG Buddy currently installs like a traditional mutable-root Linux application. The installer writes the runtime and support files into /usr/bin and /usr/lib/lg-buddy, installs the Python TV-control virtualenv under /usr/bin/LG_Buddy_PIP, and places system integration files under /etc/systemd/system, /etc/tmpfiles.d, /etc/NetworkManager/dispatcher.d, and /usr/share/applications.

That works on ordinary mutable distributions, but it is not a good fit for immutable or image-based desktop systems such as Bazzite, Fedora Atomic desktops, and SteamOS. On those systems, /usr is read-only or update-managed, and users should not need to disable read-only protection or layer packages just to install LG Buddy.

The runtime architecture should not need major changes. The issue is mostly installer, service wiring, and path ownership.

Dependency

Blocked by #20.

First-class immutable distro support should build on native webOS TV control rather than carrying the current Python bscpylgtvcommand bridge forward. Removing the Python runtime dependency makes the immutable payload materially simpler: one Rust binary plus host integration files, not a Rust binary plus Python venv plus pip-installed TV helper.

Current constraints

  • The installed systemd units hardcode /usr/bin/lg-buddy.
  • The NetworkManager pre-down hook hardcodes /usr/bin/lg-buddy.
  • The runtime default config pointer is /usr/lib/lg-buddy/config-path.
  • The default bscpylgtvcommand path is /usr/bin/LG_Buddy_PIP/bin/bscpylgtvcommand.
  • The release smoke test currently validates a mutable-root-style install layout.
  • System lifecycle integration still genuinely needs host-level systemd and NetworkManager files, so a pure Flatpak/container model is not sufficient for the default lifecycle feature.

Preliminary target model

Add a host-local install layout for immutable/image-based systems after #20 removes the Python bridge.

Preferred payload layout where supported:

/opt/lg-buddy/
  bin/lg-buddy
  docs/

Machine integration and state:

/etc/lg-buddy/
  config-path

/etc/systemd/system/
  LG_Buddy.service
  LG_Buddy_lifecycle.service
  LG_Buddy.service.d/config.conf
  LG_Buddy_lifecycle.service.d/config.conf

/etc/NetworkManager/dispatcher.d/pre-down.d/
  LG_Buddy_lifecycle

/run/lg_buddy/
  transient runtime markers

User-owned configuration and native TV auth should remain in:

~/.config/lg-buddy/config.env
~/.config/lg-buddy/webos-client-key.json

Distribution-specific notes

Fedora Atomic / Bazzite

/opt/lg-buddy appears to be the right preferred payload prefix. Fedora Atomic/OSTree layouts make /usr read-only and keep /etc and /var writable; /opt is commonly mapped to /var/opt, which gives us a conventional application prefix backed by persistent host storage.

Bazzite documentation also recommends avoiding rpm-ostree package layering except for system-level cases where other approaches do not fit. Since LG Buddy has host-level lifecycle hooks, we should still install host integration files, but avoid package layering for our own payload when possible.

SteamOS

SteamOS needs separate validation. It has an immutable root model, but it is not the same as Fedora Atomic. SteamOS 3.6 also tightened which /etc changes survive OS updates through an allow-list mechanism.

For SteamOS, we should verify on real SteamOS before assuming /opt is writable and update-persistent. If /etc files used by LG Buddy do not survive updates by default, the installer may need to add a keep-list entry under /etc/atomic-update.conf.d/ for LG Buddy's systemd, NetworkManager, and /etc/lg-buddy files.

Installer direction

The installer should select a layout rather than hardcoding /usr everywhere.

Possible behavior:

  1. Complete Replace Python TV bridge with native webOS client #20 first so the immutable payload does not include Python or bscpylgtv.
  2. Keep the existing traditional layout for mutable distributions unless we decide to migrate everyone.
  3. Add an immutable/host-local install mode that avoids /usr writes.
  4. Prefer /opt/lg-buddy when /opt is writable or clearly backed by persistent /var/opt.
  5. Fall back to /var/lib/lg-buddy or /var/opt/lg-buddy when /opt is not viable.
  6. Render systemd units and NetworkManager hooks with the selected runtime path.
  7. Move the machine config pointer to /etc/lg-buddy/config-path, with compatibility fallback to the legacy /usr/lib/lg-buddy/config-path.
  8. In immutable mode, do not prompt to install dependencies through apt, dnf, pacman, or package layering. Detect and document missing prerequisites instead.

Testing scope

Add release-bundle smoke coverage for an immutable-style install root:

  • install into an alternate payload prefix such as /opt/lg-buddy
  • assert no /usr/bin or /usr/lib/lg-buddy payload writes are required
  • assert systemd units call the selected binary path
  • assert NetworkManager hook calls the selected binary path
  • assert config pointer is under /etc/lg-buddy
  • assert no Python virtual environment or bscpylgtvcommand installation is required
  • assert uninstall removes payload, systemd units, hooks, pointer, and transient state
  • assert disabled lifecycle policy still avoids installing the lifecycle service and NetworkManager hook

Manual validation targets:

  • Bazzite desktop install
  • Fedora Silverblue/Kinoite or another Fedora Atomic desktop
  • SteamOS, including whether /opt and /etc changes survive OS updates

References

  • Native webOS TV client prerequisite: Replace Python TV bridge with native webOS client #20
  • Fedora Silverblue technical information: /usr is read-only; /etc and /var are writable; /opt maps to /var/opt.
  • rpm-ostree administrator handbook: only /etc and /var are writable, /usr is read-only, and /var is shared across upgrades.
  • OSTree adapting existing distributions: recommends /opt -> /var/opt for writable top-level directories.
  • Bazzite software installation docs: rpm-ostree layering is a last-resort system-level mechanism.
  • SteamOS notes: SteamOS uses an immutable root; SteamOS 3.6 has additional /etc preservation behavior via /etc/atomic-update.conf.d/.

Migrated from #25 before repository ownership transfer.
Original issue: #25
Original author: @Staphylococcus
Original created: 2026-04-30T17:13:43Z
Original comments at migration time: none.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions