# Layer WizardA GUI installer wizard for permanently layering an RPM package onto abootc/image-based (read-only root) Linux system via `rpm-ostree install`,with a guided reboot step and a one-click rollback if the result looks wrong.Built for Universal Blue / Fedora bootc systems, where plain `dnf install`refuses to run (the root filesystem is read-only) and the persistentmechanism is `rpm-ostree install <pkg>`, which stages a new deployment thatonly takes effect after a reboot.## What it does1. **Welcome** — shows the currently booted version/image.2. **Package** — enter a package name; "Check" confirms it resolves(`dnf repoquery`) before anything privileged happens.3. **Confirm** — review the package and what's about to happen.4. **Apply** — runs `pkexec rpm-ostree install -y <package>`, with thePolicyKit password prompt and a live streamed log. On success, offers**Reboot Now** / **Reboot Later**.5. After rebooting, the app **launches itself automatically** and asks:"Is everything working correctly?" — **Yes, keep this update**, or**No, something's wrong — roll back**, which runs`pkexec bootc rollback --apply` (reboots immediately into the previousdeployment).## How the post-reboot check worksThis system has no `greenboot` and no automated bad-boot detection(`systemd-bless-boot.service` exists but isn't wired up to anything here) —so the rollback offer is **self-reported**, not automatic. Two pieces makethat work:- **Autostart entry.** Right after a successful install,`ConfirmationMarker.installAutostart()` (`lib/confirmation_marker.dart`)writes `~/.config/autostart/com.ironmagma.layer_wizard.desktop`, with`Exec=` pointing at the currently-running binary(`Platform.resolvedExecutable`). KDE's session runs everything in`~/.config/autostart/` on login, which is what makes the app reappear onits own right after the reboot — you don't have to remember to open it.- **The check itself runs on every launch, not just via autostart.**`lib/main.dart`'s `_StartupRouter` calls `ConfirmationMarker.read()` beforedeciding what to show:```dartfuture: ConfirmationMarker.read(),builder: (context, snapshot) {final pending = snapshot.data;if (pending != null) return ConfirmationPage(pending: pending);return const WizardHomePage();}````read()` just checks whether`~/.local/state/layer_wizard/pending_confirmation.json` exists and parsesit. That file is written by the wizard right after a successful install(`ConfirmationMarker.write(...)` in `lib/wizard_page.dart`), and deleted —along with the autostart entry — as soon as you click **Keep** or**Roll back** in `lib/confirmation_page.dart`.Running the check unconditionally at startup (rather than only whenlaunched via autostart) is deliberate: if autostart doesn't fire for somereason, or you dismiss it and reopen the app later, you still land on theconfirmation screen instead of that pending state getting silentlydropped.## Project layout- `lib/ostree_service.dart` — all privileged/unprivileged shelling out:`rpm-ostree status --json`, `dnf repoquery`, `pkexec rpm-ostree install`,`pkexec bootc rollback --apply`, `pkexec systemctl reboot`.- `lib/confirmation_marker.dart` — the pending-confirmation marker file andautostart `.desktop` entry (write/read/clear, install/remove).- `lib/wizard_page.dart` — the install wizard (`Stepper`-based).- `lib/confirmation_page.dart` — the post-reboot "did this work?" screen.- `lib/main.dart` — startup routing between the two.Privilege escalation follows the same pattern as the sibling[`dnf-package-store`](https://github.com/quine-global-labs/dnf-package-store)app: `pkexec` through the desktop PolicyKit agent, with stdout/stderrstreamed line-by-line into the UI.## Building```flutter build linux```Produces `build/linux/x64/release/bundle/layer_wizard`.