feat(genebean): extract chromium-kiosk service module#694
Merged
Conversation
kiosk-gene-desk and kiosk-entryway each ran an identical cage + chromium
kiosk pattern (a writeShellScript "kiosk.sh" doing wlr-randr then
exec'ing chromium, plus a systemd.services.cage-tty1.wants block), and
each host's home-gene.nix carried a near-identical
programs.chromium.commandLineArgs list - differing only in the
dashboard URL, whether the screen is rotated, one extra chromium flag
(--hide-scrollbars, kiosk-entryway only), and the wifi interface name
used in the cage-tty1 dependency (wlan0 vs wlp3s0).
Adds genebean.services.chromium-kiosk under services/ (not programs/) on
both the home-manager and NixOS sides, matching this repo's existing
split - services/ is for things that manage a services.*/systemd-unit-
backed daemon on both sides (flatpak, tailscale), which is what this
module's NixOS half does (services.cage, systemd.services.cage-tty1).
Following the same tailscale.nix/flatpak.nix convention, the
home-manager module owns the options (dashboardUrl, extraCommandLineArgs,
wlrRandrOutput, rotate) and the NixOS module reads them back via
config.home-manager.users.${username}.genebean.services.chromium-kiosk -
so a host only specifies these values once, in its home-<user>.nix, not
duplicated across two files. The wifi interface for cage-tty1.wants is
read from the already-declared networking.wireless.interfaces list
rather than becoming a third option naming the same thing.
fbcon console rotation (kiosk-gene-desk's boot.kernelParams, Pi-specific
and independent of cage's own GUI rotation per its existing comment) and
the zramSwap/users.users.${username} blocks stay host-specific - genuinely
separate concerns, not chromium/cage-specific ones this module should own.
Pure refactor, not a behavior change: verified both hosts' evaluated
services.cage.program script content and systemd.services.cage-tty1.wants
are byte-for-byte identical to before (kiosk-gene-desk built locally;
kiosk-entryway's derivation inspected directly, since it's x86_64-linux
and this workstation's linux-builder VM is aarch64-linux only).
genebean
force-pushed
the
feat/kiosk-entryway-shared-module
branch
from
July 19, 2026 12:06
d1b83c4 to
ad21005
Compare
Two things needed fixing together, both found on hardware (kiosk-entryway) while validating this actually works: Upstream's cage module sets restartIfChanged = false, presumably to avoid yanking an interactive desktop session out from under someone mid `nixos-rebuild switch`. That caution doesn't apply to a kiosk - without this override, a config change (e.g. a new dashboard URL) requires a manual `systemctl restart cage-tty1` or a reboot to actually take effect, since the switch itself silently leaves the old chromium/cage instance running. But turning restartIfChanged on alone made things worse, not better: NixOS's activation reactivates TTY-related units on every `switch` regardless of whether anything relevant changed, and (re)starts getty@tty1.service even though it shows "disabled" - cage-tty1's existing Conflicts=getty@tty1.service (set by upstream's cage module) then kills it as a side effect, and nothing re-triggers it afterward (WantedBy=graphical.target doesn't get re-evaluated once that target's already reached), leaving the kiosk dark until a manual restart. This happens independently of restartIfChanged and made the failure mode worse once enabled, since now there were two competing stop/start cycles racing in the same transaction. Masking getty@tty1 outright - the standard practice for a TTY a compositor owns exclusively - removes the conflict at its source instead of just reacting to it, except getty@.service's own upstream unit carries Alias=autovt@%i.service, so masking the getty@tty1 name alone doesn't stop systemd resolving the same underlying unit via its autovt@tty1 alias instead - confirmed on hardware, masking only getty@tty1 still left autovt@tty1.service starting at the exact moment cage-tty1 died. Both names need masking. Validated with two consecutive `nixos-rebuild switch` runs against kiosk-entryway (one that actually changed cage-tty1's unit, one no-op) - cage-tty1 restarted cleanly on the first and was left completely untouched on the second, matching expected behavior both times.
genebean
force-pushed
the
feat/kiosk-entryway-shared-module
branch
from
July 19, 2026 12:45
8b24b31 to
786481c
Compare
4 tasks
genebean
added a commit
that referenced
this pull request
Jul 20, 2026
Both kiosks were ~95% duplicated below the chromium/cage layer already extracted in PR #694. Adds two new genebean modules following established patterns: - genebean.kiosk-hardware (top-level meta-module, same tier as genebean.plasma/genebean.ports - not a program or service): the byte-identical hardware/networking/user/zram boilerplate both hosts shared, parametrized by a single wirelessInterface option. - genebean.services.kiosk-backups: the restic disaster-recovery policy (paths, pre-reinstall-cleanup, kiosk-restic-full-restore wiring) kiosk-gene-desk already had, now shared - kiosk-gene-desk migrates to it, kiosk-entryway gains it for the first time. Paths are host-agnostic (no /persist prefix); the NixOS side detects impermanence (environment.persistence."/persist".enable) and prefixes automatically, enforced by an assertion against passing an already-prefixed path. genebean.services.chromium-kiosk gains its own wirelessInterface option (explicitly wired from kiosk-hardware's value at each call site) instead of implicitly deriving from networking.wireless.interfaces, avoiding two places setting the same value. Also closes a real gap: kiosk-gene-desk had no fonts configured at all despite rendering the same CJK/emoji-heavy Home Assistant dashboards as kiosk-entryway - added to chromium-kiosk.nix itself so it applies to any host enabling the kiosk service, not just these two. nixpkgs.overlays (the makeModulesClosure allowMissing fix) stays per-host rather than moving into kiosk-hardware - it helps construct `pkgs` itself, so gating it behind a home-manager-sourced cfg.enable check creates a genuine circular dependency (confirmed via a real "infinite recursion" eval error when first tried). Verified via deploy-rs on both hosts: dry-activate, real deploy, and post-deploy health checks (system running, cage-tty1/dbus healthy, restic timers scheduled, backup paths unchanged on kiosk-gene-desk). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018iUoDbZzHLBGu7jD3pVGz2
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
kiosk-gene-deskandkiosk-entrywayinto a reusablegenebean.services.chromium-kioskmodule (home-manager side owns the options - dashboard URL, GUI rotation, wlr-randr output, extra chromium flags; the NixOS side reads them back to configureservices.cageandsystemd.services.cage-tty1.wants), following the same dual-module convention already used fortailscale/flatpak.home-<user>.nix, not a copy-pasted cage/chromium block.Test plan
nix flake checkpasses for both hostsservices.cage.programscript content andsystemd.services.cage-tty1.wantsconfirmed byte-for-byte identical to pre-refactor for bothkiosk-gene-desk(built locally) andkiosk-entryway(derivation inspected directly - x86_64-linux, no local builder for it)nixosConfigurations.kiosk-gene-desktoplevel build succeedspre-commit run -apasses