Consolidates 8 closures to only 4 by using a git branch selector that sets the values for -dev variants of each closure. Reference the 'Verifying KioskConfig builds are in the right branch' note in Obsidian for more reference.
117 lines
7.4 KiB
Markdown
117 lines
7.4 KiB
Markdown
# AGENTS.md
|
|
|
|
## What this repo is
|
|
|
|
NixOS flake that defines kiosk systems running the RadiantWave app. Not application code — this is the OS image and deployment configuration. The actual app lives in the `radiantwave` flake inputs (from gitea.radiantwavetech.com).
|
|
|
|
Hosted on Gitea: `https://gitea.radiantwavetech.com/RadiantWaveTech/KioskConfig`
|
|
|
|
## Prod/dev split
|
|
|
|
Two branches — `main` (prod) and `dev`. There are **no `-dev` configs**: each hardware target has exactly one config, and the branch selects its channel via the single `channel` block at the top of `flake.nix`:
|
|
|
|
- `main`: `channel.appInput = radiantwave` (main), `atticRepo = "radiantwave"`, `gitRef = ""` (default branch).
|
|
- `dev`: `channel.appInput = radiantwave-dev`, `atticRepo = "radiantwave-dev"`, `gitRef = "?ref=dev"`.
|
|
|
|
Everything downstream (the configs, ISOs, updater module, autoUpgrade refs) reads from `channel`, so a `dev`→`main` merge carries your changes automatically — no copying between sibling configs. To flip a channel, change only those three `channel` values. When merging, reconcile just this one block.
|
|
|
|
Both gitea repos are public: all git access is plain HTTPS (`git+https://...`), no SSH keys or access tokens on the kiosks. Don't reintroduce `git+ssh` URLs in flake/upgrade refs.
|
|
|
|
## Key commands
|
|
|
|
```bash
|
|
# Build a system closure (any config name from flake.nix)
|
|
nix build .#nixosConfigurations.<name>.config.system.build.toplevel
|
|
|
|
# Build a bootable ISO
|
|
nix build .#nixosConfigurations.<name>.config.system.build.isoImage
|
|
|
|
# Deploy to a remote kiosk over SSH
|
|
nixos-rebuild switch --flake .#<name> --target-host root@<host>
|
|
|
|
# Push build result to Attic cache (not currently wired into any config)
|
|
attic push kiosk ./result
|
|
|
|
# Evaluate available config names
|
|
nix eval .#nixosConfigurations --apply builtins.attrNames
|
|
```
|
|
|
|
## Config variants
|
|
|
|
One config per hardware target. Dev/prod is the branch, not the config — see `channel` in `flake.nix`:
|
|
|
|
| Name | Target hardware | Disk device | App input |
|
|
|---|---|---|---|
|
|
| `radiantwavekiosk` | Intel NUC 14 (NVMe) | `/dev/nvme0n1` | `radiantwave` (main) |
|
|
| `radiantwavekiosk-commercial` | Commercial HW (SATA) | `/dev/sda` | `radiantwave` (main) |
|
|
| `radiantwavekiosk-android` | Intel NUC 14, rotated display | `/dev/nvme0n1` | `radiantwave` (main) |
|
|
| `radiantwavekiosk-rpi` | Raspberry Pi 5 (SD image) | — | `radiantwave` (main) |
|
|
|
|
On the `dev` branch, the same four configs use `radiantwave-dev` and track `?ref=dev`.
|
|
|
|
Every variant sets its own `networking.hostName` (same as the config name) and `system.configurationRevision`, so `tools/find_systems.zsh` can identify fleet members.
|
|
|
|
### USB images (zero-touch installers)
|
|
|
|
Each ISO installs exactly one closure using that closure's disk layout (`mkIso` in `flake.nix` derives both from the target config name):
|
|
|
|
| ISO | Installs | Disk layout |
|
|
|---|---|---|
|
|
| `kiosk-iso` | `radiantwavekiosk` | NVMe (`disk-config.nix`) |
|
|
| `commercial-iso` | `radiantwavekiosk-commercial` | SATA (`commercial-disk-config.nix`) |
|
|
| `android-iso` | `radiantwavekiosk-android` | NVMe |
|
|
|
|
These same names build **dev-flavored** images when the flake is checked out on the `dev` branch (the channel block selects the dev app, attic repo, and upgrade ref), so there are no separate `-dev` ISOs.
|
|
|
|
The installer lives once in `zero-touch-installer.nix` and is parameterized by `targetConfig`. Adding a new variant = add the `nixosConfigurations.*` entry, a matching `packages.x86_64-linux.*` line, and an ISO if needed.
|
|
|
|
Raspberry Pi systems are built as SD images, not ISOs:
|
|
`nix build .#nixosConfigurations.radiantwavekiosk-rpi.config.system.build.sdImage` (see `build-rpi.sh`).
|
|
|
|
## Hardware facter reports
|
|
|
|
`facter.json` is a hardware report captured on a **NUC 14**. It is currently applied to **every x86 variant**, including the commercial SATA hardware — acceptable until per-model reports exist.
|
|
|
|
To generate a report for a hardware model:
|
|
|
|
1. Boot that hardware from any NixOS live image (the kiosk installers work).
|
|
2. With real peripherals attached (display(s), audio), run:
|
|
```bash
|
|
sudo nix shell nixpkgs#nixos-facter -c nixos-facter -o facter-<model>.json
|
|
```
|
|
3. Commit `facter-<model>.json` to the repo root.
|
|
4. Wire it up at the marked spot in `flake.nix` (`facter.reportPath` inside `mkKioskSystem`) by selecting the right file per variant.
|
|
|
|
Regenerate when major hardware changes, not on a schedule — reports are snapshots. RPi configs don't use the facter module, so no report is needed there.
|
|
|
|
## CI (Gitea)
|
|
|
|
`.gitea/workflows/build-*.yml` — all triggered by `workflow_dispatch` on the `build-server` runner. They only **build and publish** what is committed. `flake.lock` is updated manually: commit an updated lock (e.g. after `nix flake update radiantwave-dev`) and dispatching the workflow is the release trigger.
|
|
|
|
## Important gotchas
|
|
|
|
- **Disk device differs by variant**: `disk-config.nix` uses `/dev/nvme0n1`, `commercial-disk-config.nix` uses `/dev/sda`. `mkIso` pairs each ISO with the correct layout automatically — keep new ISOs paired correctly.
|
|
- **Changing a config name** requires updating that config's `upgradeFlakeRef` in `flake.nix` (it embeds the name).
|
|
- **The `channel` block is the dev/prod toggle** in `flake.nix` — `appInput`, `atticRepo`, `gitRef`. When merging `dev`→`main`, keep this block's values for the target branch; only this block differs between branches.
|
|
- **`rotated_display.nix` uses `mkForce`** on `loginShellInit` — it replaces the entire kiosk startup script from `configuration.nix`; don't edit both.
|
|
- **Auto-update**: `system.autoUpgrade` runs every 10 min (`*:00/10`) with `--refresh`, operation `switch`, no auto-reboot. A `radiantwave-backup` rsync runs before each attempt. The health-check/rollback service is written but commented out in `configuration.nix`.
|
|
- **No binary cache**: kiosks fetch from cache.nixos.org only and compile RadiantWave itself from source during upgrades. Attic integration was planned (see `PLAN-update-system.md`) but never wired; the old netrc/JWT setup has been removed.
|
|
- **Secrets**: none in-tree anymore (gitea repos are public). If either repo goes private, re-add auth via `nix.settings.access-tokens` in `configuration.nix`.
|
|
- **Flake inputs**: `radiantwave` tracks main, `radiantwave-dev` tracks `?ref=dev`. The `channel` block picks which one the configs consume. Updating them independently is intentional.
|
|
- **SSH keys on machines are inbound-only** (`authorizedKeys` for admin access); outbound git is HTTPS. The root key in `zero-touch-installer.nix` must stay in sync with `myKey` in `configuration.nix`.
|
|
|
|
## File map
|
|
|
|
- `flake.nix` — entry point: inputs, the `channel` dev/prod selector, builders (`mkKioskSystem`, `mkRpiKioskSystem`, `mkIso`), all system definitions, facter report wiring
|
|
- `configuration.nix` — shared NixOS config (packages, services, kiosk user, auto-upgrade, health check, VM variant)
|
|
- `zero-touch-installer.nix` — parameterized USB installer module used by all three ISOs
|
|
- `disk-config.nix` — NVMe disk layout (NUC)
|
|
- `commercial-disk-config.nix` — SATA disk layout (commercial HW)
|
|
- `rotated_display.nix` — portrait display override for Android variant
|
|
- `facter.json` — hardware facter report (NUC 14)
|
|
- `assets/` — logo and splash image
|
|
- `plymouth-theme/` — boot splash theme
|
|
- `tools/find_systems.zsh` — subnet sweep for fleet inventory over SSH
|
|
- `build-rpi.sh` — containerized RPi SD-image build helper
|
|
- `PLAN-*.md`, `report.md`, `timeline.csv`, `kiosk-url-changes.csv` — planning/history notes, not configuration
|