The bitspire-env activation seeds .env only when ABSENT (never refreshes on
redeploy), and env WINS over the pairing seed — so any value written at first
boot is frozen for the disk's life and silently masks the seed's source. That's
how a dead relay.aiolabs.dev and a provisioned VITE_OPERATOR_PUBKEYS made stale
installs "work" while a fresh machine broke.
Seed ONLY image-baked, non-maskable values (model, fiat, ELECTRON_FORCE_PROD,
DISPLAY, empty VITE_SPIRE_SEED placeholder). Relay + server pubkey come from the
seed; operator pubkey + fee config come from LNbits over the transport — so those
keys are no longer pre-seeded at all. VITE_RELAY_URL / VITE_LNBITS_SERVER_PUBKEY
are emitted only when the operator deliberately pins them via the Nix options (an
explicit override). Also drops the inert RELAY_URL/LNBITS_SERVER_PUBKEY lines from
/etc/bitspire/config.env (never loaded — EnvironmentFile is forced to .env).
Verified: built sintra-installed .env template is 5 lines, 0 maskable vars.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The sintra live ISO (live.nix) had no serial support — ftdi_sio and the
ttyJ5/ttyJ7 udev symlinks were only in hardware/upboard.nix (installed), so
booting iso-sintra on real hardware failed on the validator + F56 dispenser
while the disk image worked. The two definitions had already drifted (live's
tejo block lacked ttyS4).
Extract the UP Board serial peripherals (usbserial/ftdi_sio/cp210x, the
ttyJ4/ttyJ5/ttyJ7 udev symlinks + permissions, console=tty0) into
hardware/upboard-serial.nix and import it from both upboard.nix (installed
tejo + sintra) and live.nix (sintra only). Single source of truth — the two
artifacts can't drift again. Named upboard-serial (not sintra-serial) since
upboard.nix serves both tejo-installed and sintra-installed.
Camera + LED/SPI rules stay inline in upboard.nix (installed-specific; the
pairing camera works via getUserMedia without the scanner symlink). Verified
by eval: live sintra now carries ftdi_sio + console=tty0 + ttyJ7; installed
sintra/tejo unchanged (serial present, camera present, no console dupe).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Fresh live boots hit a cascade of activation/unit failures because live.nix
shared installed-system config that assumes persistent state:
- bitspire-env chowned /var/lib/bitspire/.env to bitspire:bitspire in the
default activation order, before `users` runs, so on a fresh boot (no .env
yet) it failed with 'invalid user'. Move to the attrset form with
deps=["users"]. (Installed systems skip the block since .env exists.)
- swapDevices=/var/swapfile lives in the live tmpfs and fails to init —
replace with zramSwap for the low-RAM models' OOM cushion.
- wg0 needs a provisioned key the live boot lacks; it failed and dragged
network-setup down. Drop the interface on live.
- display-reset runs `xrandr --output eDP-1`, but the Sintra drives HDMI-1
(no eDP-1) — gate the service off for sintra.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The live ISO config set makeEfiBootable + makeBiosBootable but omitted
makeUsbBootable, so the image got BIOS+UEFI El Torito boot catalogs but
no isohybrid MBR/GPT — i.e. no partition table. dd'd to a USB stick it
shows iso9660 on the whole device with no ESP, and picky firmware (the
Sintra's Aaeon UP Board) won't recognise it as bootable, falling back to
its android-ia entry. Enabling makeUsbBootable applies the isohybrid MBR
(isohdpfx.bin) + GPT/ESP. Fixes USB boot for every model's live ISO.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
provision-atm.sh now writes VITE_SPIRE_SEED (the spire-seed:v1: pairing seed
from spirekeeper) as the production identity, validating the scheme prefix;
the generated nsec path is kept only as a dev fallback when SPIRE_SEED is
unset. Relay default moved to the LNbits bundled nostrrelay
(ws://$HOST_IP:5001/nostrrelay/test). .env templates (live.nix + the flake's
installed-default) swap VITE_ATM_PRIVATE_KEY → VITE_SPIRE_SEED and drop the
dead LP-era vars. README notes state.db now also holds the bunker binding
(keep it or re-pair).
Part of Phase E, aiolabs/bitspire#52. Unblocks the Sintra live-pairing smoke.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
isoImage.isoName was renamed to image.fileName in 25.11 (unified
image module). Split the rename out — the rest of isoImage.* stays
put (makeEfiBootable, makeBiosBootable, squashfsCompression).
All 8 nixosConfigurations evaluate clean on 25.11 with zero
deprecation warnings.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three breakages handled:
- hardware.opengl → hardware.graphics (renamed in 24.11). Touches
upboard.nix, douro.nix, batm3.nix, live.nix.
- vaapiIntel dropped — legacy pre-Broadwell driver, removed in
nixpkgs. UP Board (Cherry Trail) and OptiPlex 9030 (Haswell) both
use intel-media-driver, which stays.
- vaapiVdpau renamed → libva-vdpau-driver.
system.stateVersion stays 24.05 — convention is to never bump after
install. Existing Sintra and fresh flashes keep the 24.05 state
semantics; that's correct.
All 8 nixosConfigurations (4 models × {live,installed}) evaluate
clean with zero deprecation warnings on 24.11.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
System-level half of the lamassu → bitspire rebrand the rest of dev
already did at the path / service / package layers. Touches user/group
declarations, every systemd `User=` block, the udev rules filename, all
chown calls in flake.nix + live.nix, the displayManager autoLogin user,
the trusted-users nix entry, provision-atm.sh's ATM_USER, plus README +
CLAUDE.md doc references.
In-place migration for the Sintra dev unit (which auto-pulls dev at
04:00) lives in `system.activationScripts.bitspire-user-migration` and:
- copies `/home/lamassu/.ssh/authorized_keys` → `/home/bitspire/` once,
so SSH access survives the rename
- recursively chowns `/var/lib/bitspire` to the new bitspire UID on
every boot — cheap no-op once done, but covers the case where the
data dir was written by the now-removed lamassu UID
- leaves `/home/lamassu/` in place as evidence; operator can `rm -rf`
after confirming bitspire login works
Recovery path if the migration breaks SSH access: root key is still in
configuration.nix:142-144 (padreug@gizmo), so ssh root@<host> works.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Five-file coordinated rename to give the dev-branch deploy a clean
`bitspire` namespace at the NixOS level:
deploy/nixos/lamassu-atm.nix → deploy/nixos/bitspire-atm.nix
- `services.lamassu-atm` → `services.bitspire`
- `systemd.services.lamassu-atm` → `systemd.services.bitspire`
- `/var/lib/lamassu-atm` → `/var/lib/bitspire`
- `/opt/lamassu-atm` → `/opt/bitspire`
- `/etc/lamassu-atm/config.env` → `/etc/bitspire/config.env`
flake.nix
- module import path updated
- `nixosModules.lamassu-atm` → `nixosModules.bitspire`
- `system.activationScripts.lamassu-env` → `bitspire-env`
- all activation-script paths point at /var/lib/bitspire
deploy/nixos/configuration.nix
- `networking.hostName = "lamassu-atm"` → `"bitspire"`
deploy/nixos/live.nix
- module import path updated
- ISO name template: `lamassu-atm-<model>-live.iso` → `bitspire-<model>-live.iso`
- activation-script name updated
deploy/nixos/provision-atm.sh
- data-dir paths: /var/lib/lamassu-atm → /var/lib/bitspire
- systemctl + journalctl unit names updated
DELIBERATELY kept as `lamassu` (for now):
- The `lamassu` UNIX user and group account. Renaming would
require file-ownership migration scripts; the Sintra is a
fresh flash so no existing data, but the internal user
namespace inconsistency is acceptable.
- LP-specific bits in provision-atm.sh (admin token, the
`docker logs lamassu-lightning-pub` extractor) — those
get ripped out in 3c when the script switches to LNbits.
NO migration activation script added — the Sintra flash is fresh,
production batm3/douro stay on `main` and never see this branch.
A future dev→main cutover will need a separate migration story
(rename UNIX user, move /var/lib/lamassu-atm → /var/lib/bitspire,
SSH key relocation, etc.).
Verified:
nix eval .#nixosConfigurations.batm3-installed.config.systemd.services.bitspire.enable
→ true
nix eval .#nixosConfigurations.bitSpire-live-sintra.config.networking.hostName
→ "bitspire"
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Removes the mkForce override that enabled password auth for initial
setup. Machines are now provisioned with SSH keys, so the base
config's PasswordAuthentication=false takes effect.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add batm3 to flake.nix NixOS configs, live.nix (CDC ACM kernel modules,
MEI udev rules), and build-iso.sh. Default fiat: USD.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add tejo-specific udev rules for both UP Board and UP4000 variants
(serial symlinks ttyJ4/J5/J7, camera, LED SPI, I2C, USB autosuspend)
- Add USB serial kernel modules (usbserial, ftdi_sio, cp210x) for tejo
- Add tejo serial console kernel params (ttyS4 debug UART)
- Fix upboard.nix: hardware.graphics → hardware.opengl (NixOS 24.05)
- Add tejo-installed nixosConfiguration with model-specific auto-upgrade
- Parameterize auto-upgrade flake URL per machine model
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add --disable-software-rasterizer to kill SwiftShader GPU process
- Restore MemoryMax=1G so systemd OOM-kills Electron before system locks
- Add 1GB swap file so kernel can page out under pressure
- Clean /tmp on boot to prevent stale build artifacts filling disk
Douro (1.8GB RAM, 15GB disk) was freezing from memory exhaustion with
no swap and no memory limit on the Electron process.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move deploy/nixos/flake.nix into the root flake.nix, adding mkAtmApp
for pure Nix builds of the Electron app (no local pnpm needed). Simplify
build-iso.sh to a thin wrapper around `nix build .#iso-<model>`. Add
douro hardware configuration. Streamline live.nix to consume the
Nix-built app package.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add all 10 @serialport/parser-* packages to live.nix atm-app derivation
(serialport@12 barrel import eagerly requires all of them)
- Add DevicePolicy=auto + DeviceAllow=char-* rw for serial port access
- Make envTemplate model-aware (machineModel + fiatCodeForModel)
- Add sintra model (EUR) to flake.nix and build-iso.sh
- Fix tejo fiat code from USD to GTQ
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Parameterize live.nix by machineModel (douro/tejo) passed via specialArgs
- Douro: kernel 5.15 LTS for Bay Trail i915 eDP fix, vt.handoff=7
- Fix HAL packaging: copy dist/ into subdirectory (not flattened)
- Add display-reset systemd service for kexec GPU reinitialization
- Add --disable-gpu flag for Electron on headless/GPU-less boots
- flake.nix: mkLiveConfig helper, per-model ISO outputs (iso-douro/iso-tejo)
- build-iso.sh: require model param, write model-specific .env for Vite
- flash-douro-usb.sh: GPT+FAT32 ESP layout for Bay Trail UEFI boot
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Align dispenser error handling with lamassu-machine's proven approach:
close port on error, set error name, let caller decide when to re-init.
Also configure live ISO for Douro/GTQ with serialport native modules.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Enable debugMode by default (simulated bill buttons) until real
hardware validator is connected. Fix live.nix to include native
node_modules (better-sqlite3, bindings) from pnpm virtual store,
add LD_LIBRARY_PATH for NixOS, bake aiolabs.dev endpoints into
env template, and enable Electron renderer logging in journalctl.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Switch Electron window to landscape (1920x1080) with fullscreen fallback
- Rearrange IdleView for horizontal layout (logo+badges left, action cards right)
- Fix hostname command in provision/build scripts (use ip route instead of hostname -I)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add NixOS configuration to build a bootable live USB ISO that runs the
ATM Electron app in kiosk mode on physical hardware (UpBoard). The ISO
boots from squashfs, auto-starts X11/openbox, and launches Electron in
production mode.
Key changes:
- deploy/nixos/live.nix: Live USB module (squashfs+tmpfs, no disk install)
- deploy/nixos/flake.nix: Nix flake with ISO build output
- deploy/nixos/provision-atm.sh: Auto-provision LP credentials via API
- deploy/nixos/build-iso.sh: End-to-end build workflow script
- apps/machine: Fix Electron production mode (ELECTRON_FORCE_PROD),
Vue Router hash mode for file:// protocol, relative asset paths
Build: cd deploy/nixos && bash build-iso.sh
Test: qemu-system-x86_64 -enable-kvm -m 2G -cdrom result/iso/*.iso
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>