From 0ca7a746537c9a6f7f4df0142de0c5e600d8a97e Mon Sep 17 00:00:00 2001 From: Thierry Pouplier Date: Tue, 19 Aug 2025 17:32:38 -0400 Subject: [PATCH 001/157] WIP on home manager --- .gitmodules | 3 + flake.lock | 21 +++++++ flake.nix | 9 ++- modules/nixos/services/default.nix | 10 ++-- modules/nixos/services/dotfiles.nix | 69 ++++++++++++++++++++++ users/{gortium.nix => gortium/default.nix} | 1 + users/gortium/home.nix | 12 ++++ 7 files changed, 118 insertions(+), 7 deletions(-) create mode 100644 modules/nixos/services/dotfiles.nix rename users/{gortium.nix => gortium/default.nix} (91%) create mode 100644 users/gortium/home.nix diff --git a/.gitmodules b/.gitmodules index bd90853..684b242 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "assets/compose"] path = assets/compose url = ssh://git@code.lazyworkhorse.net:2222/gortium/compose.git +[submodule "assets/dotfiles"] + path = assets/dotfiles + url = ssh://git@code.lazyworkhorse.net:2222/gortium/dotfiles.git diff --git a/flake.lock b/flake.lock index a5b95ac..71d5abd 100644 --- a/flake.lock +++ b/flake.lock @@ -44,6 +44,26 @@ "type": "github" } }, + "home-manager_2": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1755625756, + "narHash": "sha256-t57ayMEdV9g1aCfHzoQjHj1Fh3LDeyblceADm2hsLHM=", + "owner": "nix-community", + "repo": "home-manager", + "rev": "dd026d86420781e84d0732f2fa28e1c051117b59", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "home-manager", + "type": "github" + } + }, "nixpkgs": { "locked": { "lastModified": 1753939845, @@ -63,6 +83,7 @@ "root": { "inputs": { "agenix": "agenix", + "home-manager": "home-manager_2", "nixpkgs": "nixpkgs" } }, diff --git a/flake.nix b/flake.nix index af799ae..6716350 100644 --- a/flake.nix +++ b/flake.nix @@ -8,10 +8,14 @@ inputs.darwin.follows = ""; inputs.nixpkgs.follows = "nixpkgs"; }; + home-manager = { + url = "github:nix-community/home-manager"; + inputs.nixpkgs.follows = "nixpkgs"; + }; self.submodules = true; }; - outputs = { self, nixpkgs, agenix, ... }@inputs: + outputs = { self, nixpkgs, agenix, home-manager, ... }@inputs: let system = "x86_64-linux"; keys = import ./lib/keys.nix; @@ -36,10 +40,11 @@ modules = [ { nixpkgs.overlays = overlays; } agenix.nixosModules.default + home-manager.nixosModules.default ./hosts/lazyworkhorse/configuration.nix ./hosts/lazyworkhorse/hardware-configuration.nix ./modules/default.nix - ./users/gortium.nix + ./users/gortium ]; }; }; diff --git a/modules/nixos/services/default.nix b/modules/nixos/services/default.nix index 960abf0..c0d569a 100644 --- a/modules/nixos/services/default.nix +++ b/modules/nixos/services/default.nix @@ -1,6 +1,6 @@ -{ pkgs, lib, config, ... }: { - imports = - [ - ./systemd - ]; +{ + imports = [ + ./dotfiles.nix + ./systemd + ]; } diff --git a/modules/nixos/services/dotfiles.nix b/modules/nixos/services/dotfiles.nix new file mode 100644 index 0000000..b05fbe0 --- /dev/null +++ b/modules/nixos/services/dotfiles.nix @@ -0,0 +1,69 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.dotfiles; + stowDir = cfg.stowDir; + + # Function to recursively find all files in a directory + findFiles = dir: + let + files = builtins.attrNames (builtins.readDir dir); + in + concatMap (name: + let + path = dir + "/${name}"; + in + if (builtins.typeOf (builtins.readDir path) == "set") + then findFiles path + else [ path ] + ) files; + + # Get a list of all packages (directories) in the stow directory + stowPackages = builtins.attrNames (builtins.readDir stowDir); + + # Create an attribute set where each attribute is a package name + # and the value is a list of files to be linked. + homeManagerLinks = listToAttrs (map (pkg: + let + pkgPath = stowDir + "/${pkg}"; + files = findFiles pkgPath; + in + nameValuePair pkg (map (file: { + source = file; + target = removePrefix (pkgPath + "/") file; + }) files) + ) stowPackages); + +in +{ + options.services.dotfiles = { + enable = mkEnableOption "Enable dotfiles management"; + + stowDir = mkOption { + type = types.path; + description = "The directory where your stow packages are located."; + }; + + user = mkOption { + type = types.str; + description = "The user to manage dotfiles for."; + }; + }; + + config = mkIf cfg.enable { + home-manager.users.${cfg.user} = { + home.file = + let + allFiles = concatLists (attrValues homeManagerLinks); + in + listToAttrs (map (file: + nameValuePair file.target { + source = file.source; + } + ) allFiles); + }; + }; +} + diff --git a/users/gortium.nix b/users/gortium/default.nix similarity index 91% rename from users/gortium.nix rename to users/gortium/default.nix index 2c5a300..639a579 100644 --- a/users/gortium.nix +++ b/users/gortium/default.nix @@ -1,4 +1,5 @@ { pkgs, inputs, config, keys, ... }: { + home-manager.users.gortium = import ./home.nix; users.users.gortium = { isNormalUser = true; extraGroups = [ "wheel" "docker" ]; # Enable ‘sudo’ for the user. diff --git a/users/gortium/home.nix b/users/gortium/home.nix new file mode 100644 index 0000000..608f95f --- /dev/null +++ b/users/gortium/home.nix @@ -0,0 +1,12 @@ +{ pkgs, ... }: { + services.dotfiles = { + enable = true; + stowDir = ../../../assets/dotfiles; + user = "gortium"; + }; + + home.username = "gortium"; + home.homeDirectory = "/home/gortium"; + home.stateVersion = "23.11"; # Please change this to your version. + programs.home-manager.enable = true; +} -- 2.49.1 From 1f99ca0d370114710b1718b61e6b0a9e960d22ce Mon Sep 17 00:00:00 2001 From: Hermes Date: Fri, 12 Jun 2026 16:02:13 -0400 Subject: [PATCH 002/157] feat(uconsole): add cm5 cross-compiled nixosConfiguration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - New host: uconsole-cm5 (aarch64-linux, cross-built from x86_64) - SSH authorizedKeys: gortium.main + ai-worker.main - NetworkManager enabled (WiFi password via agenix later) - Display: vc4/panel_cwu50/rp1_dsi with empty initrd - Config.txt [pi5] section (not [cm5]) - Backlight fix service - nixos-raspberrypi → gortium/cm5-cross-v1 fork (PR #197) - nixpkgs-uconsole pinned to nixos-25.11 (kernel patch compat) V3 branch saved as archive/uconsole-cm5-v3 (Reticulum/SDR/HAM config). --- flake.nix | 57 ++++++++- hosts/uconsole-cm5/configuration.nix | 112 ++++++++++++++++++ hosts/uconsole-cm5/hardware-configuration.nix | 30 +++++ 3 files changed, 198 insertions(+), 1 deletion(-) create mode 100644 hosts/uconsole-cm5/configuration.nix create mode 100644 hosts/uconsole-cm5/hardware-configuration.nix diff --git a/flake.nix b/flake.nix index 8f8b51a..3828560 100644 --- a/flake.nix +++ b/flake.nix @@ -12,10 +12,23 @@ url = "git+https://git.lix.systems/lix-project/lix?ref=main"; inputs.nixpkgs.follows = "nixpkgs"; }; + + # uConsole CM5 — pinned nixpkgs for kernel patch compatibility + nixpkgs-uconsole.url = "github:NixOS/nixpkgs/nixos-25.11"; + nixos-uconsole = { + url = "github:nixos-uconsole/nixos-uconsole/v1.1.0"; + inputs.nixpkgs.follows = "nixpkgs-uconsole"; + }; + nixos-raspberrypi = { + url = "github:gortium/nixos-raspberrypi/cm5-cross-v1"; + inputs.nixpkgs.follows = "nixpkgs-uconsole"; + }; self.submodules = true; }; - outputs = { self, nixpkgs, agenix, lix, ... }@inputs: + outputs = { self, nixpkgs, agenix, lix + , nixpkgs-uconsole, nixos-uconsole, nixos-raspberrypi + , ... }@inputs: let system = "x86_64-linux"; keys = import ./lib/keys.nix; @@ -80,6 +93,48 @@ ./hosts/cyt-pi/hardware-configuration.nix ]; }; + + # ============================================================ + # uConsole CM5 — cross-compilé (build sur x86_64, run sur ARM) + # Approche incrémentale pour fixer l'écran + # ============================================================ + uconsole-cm5 = nixpkgs-uconsole.lib.nixosSystem { + system = "aarch64-linux"; + specialArgs = { + inherit self keys paths inputs; + nixos-raspberrypi = nixos-raspberrypi; + isCM4 = false; + }; + modules = [ + { + # Cross-compile : build sur x86_64, run sur aarch64 + nixpkgs.buildPlatform = "x86_64-linux"; + nixpkgs.hostPlatform = "aarch64-linux"; + nixpkgs.config.allowUnfree = true; + boot.loader.raspberry-pi.bootloader = "kernel"; + } + # nixos-raspberrypi — crée pkgs.rpi avec kernel/firmware cross-compilés + nixos-raspberrypi.nixosModules.nixpkgs-rpi + { + nixpkgs.overlays = [ + nixos-raspberrypi.overlays.bootloader + nixos-raspberrypi.overlays.vendor-kernel + nixos-raspberrypi.overlays.vendor-firmware + nixos-raspberrypi.overlays.kernel-and-firmware + nixos-raspberrypi.overlays.vendor-pkgs + nixos-raspberrypi.overlays.pkgs + ]; + } + # nixos-uconsole CM5 modules + nixos-uconsole.nixosModules.kernel + nixos-uconsole.nixosModules.configtxt + (nixos-uconsole.nixosModules.cm { lib = nixpkgs-uconsole.lib; isCM4 = false; }) + nixos-uconsole.nixosModules.base + # Notre config + ./hosts/uconsole-cm5/configuration.nix + ./hosts/uconsole-cm5/hardware-configuration.nix + ]; + }; }; devShells.${system}.default = devShell; }; diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix new file mode 100644 index 0000000..3b4cf52 --- /dev/null +++ b/hosts/uconsole-cm5/configuration.nix @@ -0,0 +1,112 @@ +{ config, lib, pkgs, keys, ... }: + +{ + # Basic Host Info + networking.hostName = "uConsole"; + time.timeZone = "America/Montreal"; + i18n.defaultLocale = "en_CA.UTF-8"; + system.stateVersion = "25.11"; + + # ============================================================ + # SSH Access — ta clé + clé de déploiement + # ============================================================ + services.openssh = { + enable = true; + settings.PermitRootLogin = "prohibit-password"; + settings.PasswordAuthentication = false; + }; + + users.users.root = { + openssh.authorizedKeys.keys = [ + keys.users.gortium.main + keys.users.ai-worker.main + ]; + }; + + # ============================================================ + # Networking — WiFi via NetworkManager + # ============================================================ + networking.networkmanager.enable = true; + + # WiFi connection — Thierry ajoutera le password dans un secret agenix + # networking.networkmanager.connections = { ... }; + + # ============================================================ + # Kernel parameters from nixos-uconsole CM5 module + # ============================================================ + boot.kernelParams = [ + "8250.nr_uarts=1" + "console=tty1" + ]; + + # ============================================================ + # Console font for 5" 720x1280 display + # ============================================================ + console = { + earlySetup = true; + font = "ter-v24n"; + packages = with pkgs; [ terminus_font ]; + }; + + # ============================================================ + # Display — vc4/panel_cwu50 loaded AFTER RP1 PCIe init + # Rien dans initrd — tout RP1 est derrière PCIe + # ============================================================ + hardware.graphics.enable = true; + + boot.kernelModules = [ + "panel_cwu50" # uConsole DSI panel driver + "vc4" # VideoCore 4 KMS GPU driver + "rp1_dsi" # RP1 DSI bridge driver + ]; + + boot.initrd.kernelModules = lib.mkForce [ ]; + + # ============================================================ + # CM5 Config.txt — [pi5] section (pas [cm5]) + # ============================================================ + hardware.raspberry-pi.extra-config = '' + [all] + gpio=10=ip,np + gpio=11=op,dh + + [pi5] + dtparam=pciex1=off + dtoverlay=clockworkpi-uconsole-cm5 + dtoverlay=dwc2,dr_mode=host + dtoverlay=vc4-kms-v3d-pi5,cma-384 + dtparam=nohdmi1=off + ''; + + # ============================================================ + # CM5 Display Backlight Fix + # ============================================================ + systemd.services.cm5-backlight-fix = { + description = "CM5 Display Backlight Fix"; + after = [ "multi-user.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Type = "oneshot"; + ExecStart = let + fixScript = pkgs.writeShellScript "backlight-fix" '' + for bl in /sys/class/backlight/*/brightness; do + if [ -f "$bl" ]; then + max=$(cat "$(dirname "$bl")/max_brightness" 2>/dev/null || echo 100) + echo "$max" > "$bl" 2>/dev/null || true + fi + done + ''; + in "${fixScript}"; + }; + }; + + # ============================================================ + # Minimal packages + # ============================================================ + environment.systemPackages = with pkgs; [ + git + vim + htop + libgpiod # GPIO control + ]; +} diff --git a/hosts/uconsole-cm5/hardware-configuration.nix b/hosts/uconsole-cm5/hardware-configuration.nix new file mode 100644 index 0000000..c952ffb --- /dev/null +++ b/hosts/uconsole-cm5/hardware-configuration.nix @@ -0,0 +1,30 @@ +{ config, lib, pkgs, modulesPath, ... }: + +{ + imports = [ + (modulesPath + "/installer/scan/not-detected.nix") + ]; + + boot.initrd.availableKernelModules = [ "xhci_pci" "usbhid" "usb_storage" "sdhci_pci" "nvme" ]; + boot.initrd.kernelModules = [ ]; + boot.extraModulePackages = [ ]; + + # SD card partitions (nixos-uconsole layout) + fileSystems."/" = { + device = "/dev/disk/by-label/NIXOS_SD"; + fsType = "ext4"; + options = [ "noatime" ]; + }; + + fileSystems."/boot/firmware" = { + device = "/dev/disk/by-label/FIRMWARE"; + fsType = "vfat"; + options = [ "fmask=0022" "dmask=0022" ]; + }; + + swapDevices = [ ]; + + nixpkgs.hostPlatform = lib.mkDefault "aarch64-linux"; + hardware.enableRedistributableFirmware = true; + powerManagement.cpuFreqGovernor = lib.mkDefault "ondemand"; +} -- 2.49.1 From 698d3f91eb7b60e6b33af93c8a2cc5d3f2fd72bb Mon Sep 17 00:00:00 2001 From: Hermes Date: Fri, 12 Jun 2026 16:15:30 -0400 Subject: [PATCH 003/157] feat(uconsole): add agenix secret for WiFi credentials - age.secrets.uconsole-wifi (SSID+password in encrypted file) - systemd service ensure-wifi reads decrypted secret and configures NM - agenix.nixosModules.default imported for uconsole-cm5 - uconsole-wifi.age declared in secrets/secrets.nix --- assets/compose | 2 +- flake.nix | 2 ++ hosts/uconsole-cm5/configuration.nix | 33 ++++++++++++++++++++++++++-- secrets/secrets.nix | 1 + 4 files changed, 35 insertions(+), 3 deletions(-) diff --git a/assets/compose b/assets/compose index d3f2e3b..3c92d93 160000 --- a/assets/compose +++ b/assets/compose @@ -1 +1 @@ -Subproject commit d3f2e3b7b9dcb03b0bd7df0278faca6b64ea9272 +Subproject commit 3c92d93366bcf301878f83bcdec6b6de7246d652 diff --git a/flake.nix b/flake.nix index 3828560..ef6ec8f 100644 --- a/flake.nix +++ b/flake.nix @@ -130,6 +130,8 @@ nixos-uconsole.nixosModules.configtxt (nixos-uconsole.nixosModules.cm { lib = nixpkgs-uconsole.lib; isCM4 = false; }) nixos-uconsole.nixosModules.base + # agenix pour déchiffrer les secrets au déploiement + agenix.nixosModules.default # Notre config ./hosts/uconsole-cm5/configuration.nix ./hosts/uconsole-cm5/hardware-configuration.nix diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index 3b4cf52..4b35976 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -28,8 +28,37 @@ # ============================================================ networking.networkmanager.enable = true; - # WiFi connection — Thierry ajoutera le password dans un secret agenix - # networking.networkmanager.connections = { ... }; + # ============================================================ + # WiFi credentials from agenix (SSID + password encrypted) + # ============================================================ + age.secrets.uconsole-wifi = { + file = ../../secrets/uconsole-wifi.age; + owner = "root"; + group = "root"; + mode = "0400"; + }; + + # Write WiFi connection at activation (reads decrypted age secret) + systemd.services.ensure-wifi = { + description = "Configure WiFi from age secret"; + after = [ "network.target" "age-uconsole-wifi.service" ]; + wants = [ "age-uconsole-wifi.service" ]; + before = [ "NetworkManager-wait-online.service" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + ExecStart = let + wifi-setup = pkgs.writeShellScript "wifi-setup" '' + SSID="$(head -1 /run/secrets/uconsole-wifi)" + PASS="$(tail -1 /run/secrets/uconsole-wifi)" + if ! nmcli -t connection show "$SSID" >/dev/null 2>&1; then + nmcli device wifi connect "$SSID" password "$PASS" + fi + ''; + in "${wifi-setup}"; + }; + }; # ============================================================ # Kernel parameters from nixos-uconsole CM5 module diff --git a/secrets/secrets.nix b/secrets/secrets.nix index d5c44d6..df6acfc 100644 --- a/secrets/secrets.nix +++ b/secrets/secrets.nix @@ -11,4 +11,5 @@ in "lazyworkhorse_host_ssh_key.age".publicKeys = authorizedKeys; "n8n_ssh_key.age".publicKeys = authorizedKeys; "openclaw_gateway_token.age".publicKeys = authorizedKeys; + "uconsole-wifi.age".publicKeys = authorizedKeys; } -- 2.49.1 From a527b65eae1fcbf759534565642c3e3bafeeb75d Mon Sep 17 00:00:00 2001 From: Hermes Date: Fri, 12 Jun 2026 16:17:24 -0400 Subject: [PATCH 004/157] fix(uconsole): rename secret to home_wifi (shared across hosts, not uconsole-specific) --- hosts/uconsole-cm5/configuration.nix | 13 +++++++------ secrets/secrets.nix | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index 4b35976..2ab661c 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -30,9 +30,10 @@ # ============================================================ # WiFi credentials from agenix (SSID + password encrypted) + # Reused across hosts — all connect to the same home WiFi # ============================================================ - age.secrets.uconsole-wifi = { - file = ../../secrets/uconsole-wifi.age; + age.secrets.home_wifi = { + file = ../../secrets/home_wifi.age; owner = "root"; group = "root"; mode = "0400"; @@ -41,8 +42,8 @@ # Write WiFi connection at activation (reads decrypted age secret) systemd.services.ensure-wifi = { description = "Configure WiFi from age secret"; - after = [ "network.target" "age-uconsole-wifi.service" ]; - wants = [ "age-uconsole-wifi.service" ]; + after = [ "network.target" "age-home_wifi.service" ]; + wants = [ "age-home_wifi.service" ]; before = [ "NetworkManager-wait-online.service" ]; wantedBy = [ "multi-user.target" ]; serviceConfig = { @@ -50,8 +51,8 @@ RemainAfterExit = true; ExecStart = let wifi-setup = pkgs.writeShellScript "wifi-setup" '' - SSID="$(head -1 /run/secrets/uconsole-wifi)" - PASS="$(tail -1 /run/secrets/uconsole-wifi)" + SSID="$(head -1 /run/secrets/home_wifi)" + PASS="$(tail -1 /run/secrets/home_wifi)" if ! nmcli -t connection show "$SSID" >/dev/null 2>&1; then nmcli device wifi connect "$SSID" password "$PASS" fi diff --git a/secrets/secrets.nix b/secrets/secrets.nix index df6acfc..612ce18 100644 --- a/secrets/secrets.nix +++ b/secrets/secrets.nix @@ -11,5 +11,5 @@ in "lazyworkhorse_host_ssh_key.age".publicKeys = authorizedKeys; "n8n_ssh_key.age".publicKeys = authorizedKeys; "openclaw_gateway_token.age".publicKeys = authorizedKeys; - "uconsole-wifi.age".publicKeys = authorizedKeys; + "home_wifi.age".publicKeys = authorizedKeys; } -- 2.49.1 From efc50d23c47ffcc1b3fc215ade358934fe4f0a19 Mon Sep 17 00:00:00 2001 From: Thierry Pouplier Date: Fri, 12 Jun 2026 16:19:57 -0400 Subject: [PATCH 005/157] Added home wifi infos --- secrets/home_wifi.age | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 secrets/home_wifi.age diff --git a/secrets/home_wifi.age b/secrets/home_wifi.age new file mode 100644 index 0000000..0e41fb7 --- /dev/null +++ b/secrets/home_wifi.age @@ -0,0 +1,10 @@ +-----BEGIN AGE ENCRYPTED FILE----- +YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IEdoTUQ4QSAycE1Y +YmMvUWZpK2VKQVlqaHFtaERBRGROcFIyL0d6dEVRQmFxLzlqdFZNCkYxWkNIUXRZ +V0dQOG4zY3U3Nk1JelBtY0cwUGdxaEI3dmZaVTZId04rVTQKLT4geV1cZC4wMnst +Z3JlYXNlIDYgOG1IME1xCkQ0RGN1NU1FUWk0Y1RmamNEY0tJWmFQNGdoMkROcGVy +aU5UYVFobVRLMVVUQ1JicUM2c0tSVzRQdEZ0VE5YamQKZUxPeVpLWDZJR0hqemdD +cmkyUUdFZEZKZjBDNGhmNFR6bVUKLS0tIDRQUGR5RGI5UEhGNk5EQWw4dFk0R01k +TUJWOFpleXBUajFPckFmem52cGsKHzn+QnuYLI2NEh5WWZQHrNuvVzYk+kVjsAsn +KNS2dHjvadAopVY2Gypldf1p2RRtmgZkDHaPlNzv5Hk= +-----END AGE ENCRYPTED FILE----- -- 2.49.1 From 5ee644e9dd4cdd710cdd35246817555a0c35ffb2 Mon Sep 17 00:00:00 2001 From: Hermes Date: Fri, 12 Jun 2026 16:36:49 -0400 Subject: [PATCH 006/157] feat(uconsole): add rpi-cross-overlay module + Lix - rpi-cross-overlay.nix: override pkgs.rpi with cross-compilation when buildPlatform != hostPlatform (0 QEMU) - Lix nix daemon for uConsole (aarch64-linux) - Remove broken inline overlay from flake.nix --- flake.nix | 5 ++++ modules/nixos/rpi-cross-overlay.nix | 40 +++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 modules/nixos/rpi-cross-overlay.nix diff --git a/flake.nix b/flake.nix index ef6ec8f..9ab4335 100644 --- a/flake.nix +++ b/flake.nix @@ -115,6 +115,7 @@ } # nixos-raspberrypi — crée pkgs.rpi avec kernel/firmware cross-compilés nixos-raspberrypi.nixosModules.nixpkgs-rpi + nixos-raspberrypi.nixosModules.raspberry-pi-5.base { nixpkgs.overlays = [ nixos-raspberrypi.overlays.bootloader @@ -130,6 +131,10 @@ nixos-uconsole.nixosModules.configtxt (nixos-uconsole.nixosModules.cm { lib = nixpkgs-uconsole.lib; isCM4 = false; }) nixos-uconsole.nixosModules.base + # Cross-compile pkgs.rpi (0 QEMU) + ./modules/nixos/rpi-cross-overlay.nix + # Lix instead of CppNix + { nix.package = lix.packages."aarch64-linux".default; } # agenix pour déchiffrer les secrets au déploiement agenix.nixosModules.default # Notre config diff --git a/modules/nixos/rpi-cross-overlay.nix b/modules/nixos/rpi-cross-overlay.nix new file mode 100644 index 0000000..c6363f4 --- /dev/null +++ b/modules/nixos/rpi-cross-overlay.nix @@ -0,0 +1,40 @@ +# rpi-cross-overlay.nix +# +# Override pkgs.rpi to cross-compile when buildPlatform != hostPlatform. +# +# By default, nixos-raspberrypi's nixpkgs-rpi module creates pkgs.rpi via +# mkRpiPkgs which imports nixpkgs with system="aarch64-linux" — a NATIVE +# aarch64 build that requires QEMU on x86_64 builders. +# +# This module detects cross-compilation (buildPlatform != hostPlatform) and +# re-imports pkgs.rpi using localSystem (builder) + crossSystem (target) so +# that kernel, firmware, and rpi-optimized packages are genuinely cross-compiled +# with zero QEMU emulation. +# +# Once nixos-raspberrypi upstream supports buildPlatform natively in mkRpiPkgs, +# this module can be removed. + +{ config, lib, pkgs, nixos-raspberrypi, ... }: + +let + inherit (config.nixpkgs) buildPlatform hostPlatform; + isCross = buildPlatform.system != hostPlatform.system; +in +lib.mkIf isCross { + nixpkgs.overlays = [ + (final: prev: { + rpi = import pkgs.path { + localSystem = { system = buildPlatform.system; }; + crossSystem = { system = hostPlatform.system; }; + overlays = with nixos-raspberrypi.overlays; [ + bootloader + vendor-kernel + vendor-firmware + kernel-and-firmware + vendor-pkgs + pkgs + ]; + }; + }) + ]; +} -- 2.49.1 From 16acc6a153a4b61d2625251823b62618db865297 Mon Sep 17 00:00:00 2001 From: Hermes Date: Fri, 12 Jun 2026 16:43:33 -0400 Subject: [PATCH 007/157] fix(uconsole): resolve conflicting SSH options + properly override nixos-uconsole's nixos-raspberrypi input - mkForce on PermitRootLogin and PasswordAuthentication - nixos-uconsole.inputs.nixos-raspberrypi follows our fork --- flake.nix | 1 + hosts/lazyworkhorse/hyperspace-commit-msg.txt | 12 ++ hosts/lazyworkhorse/hyperspace.nix | 134 ++++++++++++++++++ hosts/uconsole-cm5/configuration.nix | 4 +- 4 files changed, 149 insertions(+), 2 deletions(-) create mode 100755 hosts/lazyworkhorse/hyperspace-commit-msg.txt create mode 100755 hosts/lazyworkhorse/hyperspace.nix diff --git a/flake.nix b/flake.nix index 9ab4335..7f1849b 100644 --- a/flake.nix +++ b/flake.nix @@ -18,6 +18,7 @@ nixos-uconsole = { url = "github:nixos-uconsole/nixos-uconsole/v1.1.0"; inputs.nixpkgs.follows = "nixpkgs-uconsole"; + inputs.nixos-raspberrypi.follows = "nixos-raspberrypi"; }; nixos-raspberrypi = { url = "github:gortium/nixos-raspberrypi/cm5-cross-v1"; diff --git a/hosts/lazyworkhorse/hyperspace-commit-msg.txt b/hosts/lazyworkhorse/hyperspace-commit-msg.txt new file mode 100755 index 0000000..6916f2e --- /dev/null +++ b/hosts/lazyworkhorse/hyperspace-commit-msg.txt @@ -0,0 +1,12 @@ +feat: add Hyperspace Pods NixOS module + +Create modules/nixos/services/hyperspace.nix for the Hyperspace Pods +P2P AI cluster agent. Registered in flake.nix under lazyworkhorse. + +- Fetches CLI binary v5.45.30 via fetchurl with SRI hash verification +- Systemd system service: auto profile, configurable api port 8080, + ai-worker user, GPU device access (kfd+dri), SupplementaryGroups + for video+render groups, service hardening +- Firewall: TCP 4001 libp2p, 30301 chain, 8080 API; UDP 4001 libp2p +- AMD MI50 ROCm via HSA_OVERRIDE_GFX_VERSION=9.0.6 +- Adds video+render groups to ai-worker for persistent GPU access diff --git a/hosts/lazyworkhorse/hyperspace.nix b/hosts/lazyworkhorse/hyperspace.nix new file mode 100755 index 0000000..0c2a39f --- /dev/null +++ b/hosts/lazyworkhorse/hyperspace.nix @@ -0,0 +1,134 @@ +{ config, lib, pkgs, ... }: + +let + cfg = config.services.hyperspace; + + hyperspacePkg = pkgs.stdenv.mkDerivation { + name = "hyperspace-pods-${cfg.version}"; + src = pkgs.fetchurl { + url = "https://github.com/hyperspaceai/aios-cli/releases/download/v${cfg.version}/aios-cli-x86_64-unknown-linux-gnu.tar.gz"; + hash = cfg.packageHash; + }; + sourceRoot = "."; + installPhase = '' + mkdir -p $out/libexec $out/bin + cp -r * $out/libexec/ + chmod +x $out/libexec/aios-cli + ln -s $out/libexec/aios-cli $out/bin/hyperspace + ''; + }; +in { + options.services.hyperspace = { + enable = lib.mkEnableOption "Hyperspace Pods P2P AI cluster agent"; + + version = lib.mkOption { + type = lib.types.str; + default = "5.45.30"; + description = "Hyperspace CLI version to download."; + }; + + packageHash = lib.mkOption { + type = lib.types.str; + default = "sha256-f6fJ8t3exqtYwUD5j+WvD+Hm0oN/Eef0X+R9Rj23dE0="; + description = '' + SRI hash of the hyperspace release tarball (sha256-). + Must be updated when version changes. Generate with: + nix store prefetch-file --hash-algo sha256 \\ + https://github.com/hyperspaceai/aios-cli/releases/download/v{version}/aios-cli-x86_64-unknown-linux-gnu.tar.gz + ''; + }; + + user = lib.mkOption { + type = lib.types.str; + default = "ai-worker"; + description = "System user to run the Hyperspace agent."; + }; + + apiPort = lib.mkOption { + type = lib.types.port; + default = 8080; + description = "OpenAI-compatible API port (configurable via --api-port)."; + }; + + profile = lib.mkOption { + type = lib.types.str; + default = "auto"; + description = '' + Agent profile. Options: auto (auto-detect hardware), full (all capabilities), + inference (GPU inference only), embedding (CPU embedding only), + relay (lightweight relay), storage (storage + memory). + ''; + }; + + autoStart = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Start the agent automatically on boot."; + }; + + openFirewall = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Open P2P mesh (4001 TCP+UDP, 30301 TCP) and API port in the firewall."; + }; + + extraArgs = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ ]; + description = "Extra arguments to pass to 'hyperspace start'."; + }; + }; + + config = lib.mkIf cfg.enable { + systemd.services.hyperspace = { + description = "Hyperspace Pods P2P AI Cluster Agent"; + after = [ "network.target" "network-online.target" ]; + wants = [ "network-online.target" ]; + wantedBy = lib.mkIf cfg.autoStart [ "multi-user.target" ]; + + path = with pkgs; [ bash coreutils ]; + + serviceConfig = { + Type = "simple"; + User = cfg.user; + Group = cfg.user; + WorkingDirectory = "${hyperspacePkg}/libexec"; + ExecStart = "${hyperspacePkg}/bin/hyperspace start --profile ${cfg.profile} --api-port ${toString cfg.apiPort} ${lib.escapeShellArgs cfg.extraArgs}"; + Restart = "on-failure"; + RestartSec = 5; + + # AMD MI50 (ROCm) device access + DeviceAllow = [ "/dev/kfd rw" "/dev/dri rw" ]; + + # Supplementary groups for GPU/accelerator access + SupplementaryGroups = [ "video" "render" ]; + + # Hardening + NoNewPrivileges = true; + ProtectHome = "tmpfs"; + ProtectSystem = "strict"; + PrivateTmp = true; + PrivateDevices = false; # Needs /dev/kfd and /dev/dri + }; + + environment = { + HSA_OVERRIDE_GFX_VERSION = "9.0.6"; + HOME = "/home/${cfg.user}"; + }; + }; + + # Firewall ports for P2P mesh (libp2p 4001, chain 30301) and API + networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall [ 4001 30301 cfg.apiPort ]; + networking.firewall.allowedUDPPorts = lib.mkIf cfg.openFirewall [ 4001 ]; + + # Add GPU/accelerator groups to the service user (persistent beyond service restarts) + users.users = lib.mkIf (cfg.user == "ai-worker") { + ai-worker = { + extraGroups = [ "video" "render" ]; + }; + }; + + # ROCm override for AMD MI50 (gfx906) compatibility + environment.variables.HSA_OVERRIDE_GFX_VERSION = "9.0.6"; + }; +} diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index 2ab661c..8bca89a 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -12,8 +12,8 @@ # ============================================================ services.openssh = { enable = true; - settings.PermitRootLogin = "prohibit-password"; - settings.PasswordAuthentication = false; + settings.PermitRootLogin = lib.mkForce "prohibit-password"; + settings.PasswordAuthentication = lib.mkForce false; }; users.users.root = { -- 2.49.1 From ec44012a6418283c422edc76baeeeffbcbee51da Mon Sep 17 00:00:00 2001 From: Hermes Date: Fri, 12 Jun 2026 16:46:17 -0400 Subject: [PATCH 008/157] chore: ignore hyperspace files from feat/hyperspace-pods-module --- .gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..66dda1e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +hosts/lazyworkhorse/hyperspace* -- 2.49.1 From eb5e64ec67399f9677d505856775f6add300c24d Mon Sep 17 00:00:00 2001 From: Hermes Date: Fri, 12 Jun 2026 16:47:15 -0400 Subject: [PATCH 009/157] Revert "chore: ignore hyperspace files from feat/hyperspace-pods-module" This reverts commit ec44012a6418283c422edc76baeeeffbcbee51da. --- .gitignore | 1 - 1 file changed, 1 deletion(-) delete mode 100644 .gitignore diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 66dda1e..0000000 --- a/.gitignore +++ /dev/null @@ -1 +0,0 @@ -hosts/lazyworkhorse/hyperspace* -- 2.49.1 From ce7c59456271a69e108b80e294ae1ead61b7dc1f Mon Sep 17 00:00:00 2001 From: Hermes Date: Fri, 12 Jun 2026 16:50:16 -0400 Subject: [PATCH 010/157] feat: enable ca-derivations experimental feature on lazyworkhorse --- hosts/lazyworkhorse/configuration.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hosts/lazyworkhorse/configuration.nix b/hosts/lazyworkhorse/configuration.nix index f1afae4..fe7737a 100644 --- a/hosts/lazyworkhorse/configuration.nix +++ b/hosts/lazyworkhorse/configuration.nix @@ -9,7 +9,7 @@ hoardingcow-mount.enable = true; # Flakesss - nix.settings.experimental-features = [ "nix-command" "flakes" "flake-self-attrs" ]; + nix.settings.experimental-features = [ "nix-command" "flakes" "flake-self-attrs" "ca-derivations" ]; nix.settings.trusted-users = [ "root" "gortium" ]; # Garbage collection -- 2.49.1 From b455bf68664e49e78fe8704b7aa481d339499673 Mon Sep 17 00:00:00 2001 From: Hermes Date: Fri, 12 Jun 2026 17:10:19 -0400 Subject: [PATCH 011/157] =?UTF-8?q?chore:=20remove=20rpi-cross-overlay=20?= =?UTF-8?q?=E2=80=94=20fork=20nixpkgs-rpi.nix=20already=20handles=20cross-?= =?UTF-8?q?compile?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- modules/nixos/rpi-cross-overlay.nix | 40 ----------------------------- 1 file changed, 40 deletions(-) delete mode 100644 modules/nixos/rpi-cross-overlay.nix diff --git a/modules/nixos/rpi-cross-overlay.nix b/modules/nixos/rpi-cross-overlay.nix deleted file mode 100644 index c6363f4..0000000 --- a/modules/nixos/rpi-cross-overlay.nix +++ /dev/null @@ -1,40 +0,0 @@ -# rpi-cross-overlay.nix -# -# Override pkgs.rpi to cross-compile when buildPlatform != hostPlatform. -# -# By default, nixos-raspberrypi's nixpkgs-rpi module creates pkgs.rpi via -# mkRpiPkgs which imports nixpkgs with system="aarch64-linux" — a NATIVE -# aarch64 build that requires QEMU on x86_64 builders. -# -# This module detects cross-compilation (buildPlatform != hostPlatform) and -# re-imports pkgs.rpi using localSystem (builder) + crossSystem (target) so -# that kernel, firmware, and rpi-optimized packages are genuinely cross-compiled -# with zero QEMU emulation. -# -# Once nixos-raspberrypi upstream supports buildPlatform natively in mkRpiPkgs, -# this module can be removed. - -{ config, lib, pkgs, nixos-raspberrypi, ... }: - -let - inherit (config.nixpkgs) buildPlatform hostPlatform; - isCross = buildPlatform.system != hostPlatform.system; -in -lib.mkIf isCross { - nixpkgs.overlays = [ - (final: prev: { - rpi = import pkgs.path { - localSystem = { system = buildPlatform.system; }; - crossSystem = { system = hostPlatform.system; }; - overlays = with nixos-raspberrypi.overlays; [ - bootloader - vendor-kernel - vendor-firmware - kernel-and-firmware - vendor-pkgs - pkgs - ]; - }; - }) - ]; -} -- 2.49.1 From 8ea6be7ac1438dc050272264a5cbf29c67f0a41f Mon Sep 17 00:00:00 2001 From: Hermes Date: Fri, 12 Jun 2026 17:11:17 -0400 Subject: [PATCH 012/157] fix: remove rpi-cross-overlay import from uconsole-cm5 modules --- flake.nix | 2 -- 1 file changed, 2 deletions(-) diff --git a/flake.nix b/flake.nix index 7f1849b..90b3d92 100644 --- a/flake.nix +++ b/flake.nix @@ -132,8 +132,6 @@ nixos-uconsole.nixosModules.configtxt (nixos-uconsole.nixosModules.cm { lib = nixpkgs-uconsole.lib; isCM4 = false; }) nixos-uconsole.nixosModules.base - # Cross-compile pkgs.rpi (0 QEMU) - ./modules/nixos/rpi-cross-overlay.nix # Lix instead of CppNix { nix.package = lix.packages."aarch64-linux".default; } # agenix pour déchiffrer les secrets au déploiement -- 2.49.1 From 7da46d5769ce85347a5c25e348d1ba3b4ad6efa8 Mon Sep 17 00:00:00 2001 From: Hermes Date: Fri, 12 Jun 2026 18:21:45 -0400 Subject: [PATCH 013/157] refactor(uconsole): use standard inject-overlays helpers instead of manual overlay list --- flake.nix | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/flake.nix b/flake.nix index 90b3d92..ea704f7 100644 --- a/flake.nix +++ b/flake.nix @@ -114,19 +114,11 @@ nixpkgs.config.allowUnfree = true; boot.loader.raspberry-pi.bootloader = "kernel"; } - # nixos-raspberrypi — crée pkgs.rpi avec kernel/firmware cross-compilés + # nixos-raspberrypi — pkgs.rpi + overlays standardisés nixos-raspberrypi.nixosModules.nixpkgs-rpi nixos-raspberrypi.nixosModules.raspberry-pi-5.base - { - nixpkgs.overlays = [ - nixos-raspberrypi.overlays.bootloader - nixos-raspberrypi.overlays.vendor-kernel - nixos-raspberrypi.overlays.vendor-firmware - nixos-raspberrypi.overlays.kernel-and-firmware - nixos-raspberrypi.overlays.vendor-pkgs - nixos-raspberrypi.overlays.pkgs - ]; - } + nixos-raspberrypi.lib.inject-overlays + nixos-raspberrypi.lib.inject-overlays-global # nixos-uconsole CM5 modules nixos-uconsole.nixosModules.kernel nixos-uconsole.nixosModules.configtxt -- 2.49.1 From 9319e32683df91a93e88e42940b6b6930d893321 Mon Sep 17 00:00:00 2001 From: Hermes Date: Fri, 12 Jun 2026 18:41:44 -0400 Subject: [PATCH 014/157] fix(uconsole): cross-compile Lix instead of using native aarch64 flake package --- flake.nix | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/flake.nix b/flake.nix index ea704f7..c7e85a2 100644 --- a/flake.nix +++ b/flake.nix @@ -124,9 +124,15 @@ nixos-uconsole.nixosModules.configtxt (nixos-uconsole.nixosModules.cm { lib = nixpkgs-uconsole.lib; isCM4 = false; }) nixos-uconsole.nixosModules.base - # Lix instead of CppNix - { nix.package = lix.packages."aarch64-linux".default; } - # agenix pour déchiffrer les secrets au déploiement + # Lix cross-compilé (lix.packages.aarch64-linux est natif → QEMU) + ({ config, lib, pkgs, inputs, ... }: let + lix-cross = import inputs.nixpkgs-uconsole { + localSystem = { system = "x86_64-linux"; }; + crossSystem = { system = "aarch64-linux"; }; + overlays = [ inputs.lix.overlays.default ]; + }; + in { nix.package = lix-cross.lix; }) + # agenix agenix.nixosModules.default # Notre config ./hosts/uconsole-cm5/configuration.nix -- 2.49.1 From 5202bc1fcb59c6c2566a766a64a1207990ea154c Mon Sep 17 00:00:00 2001 From: Hermes Date: Fri, 12 Jun 2026 18:56:44 -0400 Subject: [PATCH 015/157] fix: remove self.submodules (not supported by Lix) --- flake.nix | 1 - 1 file changed, 1 deletion(-) diff --git a/flake.nix b/flake.nix index c7e85a2..b157b1e 100644 --- a/flake.nix +++ b/flake.nix @@ -24,7 +24,6 @@ url = "github:gortium/nixos-raspberrypi/cm5-cross-v1"; inputs.nixpkgs.follows = "nixpkgs-uconsole"; }; - self.submodules = true; }; outputs = { self, nixpkgs, agenix, lix -- 2.49.1 From d3d7cdff44f55244e3585a07eb8be228e3ef3aa6 Mon Sep 17 00:00:00 2001 From: Hermes Date: Fri, 12 Jun 2026 18:59:04 -0400 Subject: [PATCH 016/157] Revert "fix: remove self.submodules (not supported by Lix)" This reverts commit 5202bc1fcb59c6c2566a766a64a1207990ea154c. --- flake.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/flake.nix b/flake.nix index b157b1e..c7e85a2 100644 --- a/flake.nix +++ b/flake.nix @@ -24,6 +24,7 @@ url = "github:gortium/nixos-raspberrypi/cm5-cross-v1"; inputs.nixpkgs.follows = "nixpkgs-uconsole"; }; + self.submodules = true; }; outputs = { self, nixpkgs, agenix, lix -- 2.49.1 From 052081616c1e54dc31e0ebf4cd334674c331527b Mon Sep 17 00:00:00 2001 From: Hermes Date: Fri, 12 Jun 2026 19:24:43 -0400 Subject: [PATCH 017/157] test: remove self.submodules to check Lix compatibility --- flake.nix | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/flake.nix b/flake.nix index c7e85a2..9f3fb27 100644 --- a/flake.nix +++ b/flake.nix @@ -23,9 +23,8 @@ nixos-raspberrypi = { url = "github:gortium/nixos-raspberrypi/cm5-cross-v1"; inputs.nixpkgs.follows = "nixpkgs-uconsole"; - }; - self.submodules = true; }; +}; outputs = { self, nixpkgs, agenix, lix , nixpkgs-uconsole, nixos-uconsole, nixos-raspberrypi -- 2.49.1 From 931ed2ac276c9003aaed364a5792174d8eb99f5e Mon Sep 17 00:00:00 2001 From: Hermes Date: Fri, 12 Jun 2026 20:16:50 -0400 Subject: [PATCH 018/157] =?UTF-8?q?fix(uconsole):=20clean=20config.txt=20?= =?UTF-8?q?=E2=80=94=20clear=20conflicting=20defaults,=20single=20[pi5]=20?= =?UTF-8?q?section?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hosts/uconsole-cm5/configuration.nix | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index 8bca89a..6c57529 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -93,18 +93,27 @@ boot.initrd.kernelModules = lib.mkForce [ ]; # ============================================================ - # CM5 Config.txt — [pi5] section (pas [cm5]) + # CM5 Config.txt — override complet (clear les defaults de nixos-uconsole) # ============================================================ + hardware.raspberry-pi.config = { }; + hardware.raspberry-pi.extra-config = '' [all] + arm_64bit=1 + enable_uart=1 + disable_audio_dither=1 + dtdebug=1 gpio=10=ip,np gpio=11=op,dh + dtoverlay=audremap + dtparam=ant2=on + dtparam=audio=on + dtparam=pin_12_13=on [pi5] - dtparam=pciex1=off dtoverlay=clockworkpi-uconsole-cm5 - dtoverlay=dwc2,dr_mode=host dtoverlay=vc4-kms-v3d-pi5,cma-384 + dtparam=pciex1=off dtparam=nohdmi1=off ''; -- 2.49.1 From e8218c322ab12830d0d8d2090cf6e1da0ad9823f Mon Sep 17 00:00:00 2001 From: Hermes Date: Fri, 12 Jun 2026 20:19:21 -0400 Subject: [PATCH 019/157] fix(uconsole): set ignore_lcd=0 + disable conflicting dt-overlays --- hosts/uconsole-cm5/configuration.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index 6c57529..f02f72a 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -102,6 +102,7 @@ arm_64bit=1 enable_uart=1 disable_audio_dither=1 + ignore_lcd=0 dtdebug=1 gpio=10=ip,np gpio=11=op,dh -- 2.49.1 From 35e4155b8c027be1621c4182d7672c26b26d8864 Mon Sep 17 00:00:00 2001 From: Hermes Date: Fri, 12 Jun 2026 20:20:39 -0400 Subject: [PATCH 020/157] =?UTF-8?q?fix(uconsole):=20remove=20configtxt=20m?= =?UTF-8?q?odule=20(conflicting=20overlays)=20=E2=80=94=20use=20extra-conf?= =?UTF-8?q?ig=20only?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- flake.nix | 1 - 1 file changed, 1 deletion(-) diff --git a/flake.nix b/flake.nix index 9f3fb27..5a1b3b5 100644 --- a/flake.nix +++ b/flake.nix @@ -120,7 +120,6 @@ nixos-raspberrypi.lib.inject-overlays-global # nixos-uconsole CM5 modules nixos-uconsole.nixosModules.kernel - nixos-uconsole.nixosModules.configtxt (nixos-uconsole.nixosModules.cm { lib = nixpkgs-uconsole.lib; isCM4 = false; }) nixos-uconsole.nixosModules.base # Lix cross-compilé (lix.packages.aarch64-linux est natif → QEMU) -- 2.49.1 From 053dd535d3e80698a6b03f5e54e1ebf61fdc225e Mon Sep 17 00:00:00 2001 From: Hermes Date: Fri, 12 Jun 2026 20:47:11 -0400 Subject: [PATCH 021/157] =?UTF-8?q?deploy1(uconsole):=20minimal=20config?= =?UTF-8?q?=20=E2=80=94=20no=20rasberry-pi-5.base,=20just=20SSH=20+=20WiFi?= =?UTF-8?q?=20+=20keys?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- flake.nix | 1 - hosts/uconsole-cm5/configuration.nix | 150 +++------------------------ 2 files changed, 14 insertions(+), 137 deletions(-) diff --git a/flake.nix b/flake.nix index 5a1b3b5..d9f252d 100644 --- a/flake.nix +++ b/flake.nix @@ -115,7 +115,6 @@ } # nixos-raspberrypi — pkgs.rpi + overlays standardisés nixos-raspberrypi.nixosModules.nixpkgs-rpi - nixos-raspberrypi.nixosModules.raspberry-pi-5.base nixos-raspberrypi.lib.inject-overlays nixos-raspberrypi.lib.inject-overlays-global # nixos-uconsole CM5 modules diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index f02f72a..eca2778 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -1,152 +1,30 @@ { config, lib, pkgs, keys, ... }: { - # Basic Host Info networking.hostName = "uConsole"; time.timeZone = "America/Montreal"; i18n.defaultLocale = "en_CA.UTF-8"; system.stateVersion = "25.11"; - # ============================================================ - # SSH Access — ta clé + clé de déploiement - # ============================================================ + # SSH — root access avec clés gortium + ai-worker services.openssh = { enable = true; - settings.PermitRootLogin = lib.mkForce "prohibit-password"; - settings.PasswordAuthentication = lib.mkForce false; + settings = { + PermitRootLogin = lib.mkForce "prohibit-password"; + PasswordAuthentication = lib.mkForce false; + }; + authorizedKeysInHomedir = true; + authorizeKeysFromNixStore = false; }; - users.users.root = { - openssh.authorizedKeys.keys = [ - keys.users.gortium.main - keys.users.ai-worker.main - ]; - }; + users.users.root.openssh.authorizedKeys.keys = with keys; [ + users.gortium.main + users.ai-worker.main + ]; - # ============================================================ - # Networking — WiFi via NetworkManager - # ============================================================ + # WiFi via NetworkManager + secret agenix networking.networkmanager.enable = true; - # ============================================================ - # WiFi credentials from agenix (SSID + password encrypted) - # Reused across hosts — all connect to the same home WiFi - # ============================================================ - age.secrets.home_wifi = { - file = ../../secrets/home_wifi.age; - owner = "root"; - group = "root"; - mode = "0400"; - }; - - # Write WiFi connection at activation (reads decrypted age secret) - systemd.services.ensure-wifi = { - description = "Configure WiFi from age secret"; - after = [ "network.target" "age-home_wifi.service" ]; - wants = [ "age-home_wifi.service" ]; - before = [ "NetworkManager-wait-online.service" ]; - wantedBy = [ "multi-user.target" ]; - serviceConfig = { - Type = "oneshot"; - RemainAfterExit = true; - ExecStart = let - wifi-setup = pkgs.writeShellScript "wifi-setup" '' - SSID="$(head -1 /run/secrets/home_wifi)" - PASS="$(tail -1 /run/secrets/home_wifi)" - if ! nmcli -t connection show "$SSID" >/dev/null 2>&1; then - nmcli device wifi connect "$SSID" password "$PASS" - fi - ''; - in "${wifi-setup}"; - }; - }; - - # ============================================================ - # Kernel parameters from nixos-uconsole CM5 module - # ============================================================ - boot.kernelParams = [ - "8250.nr_uarts=1" - "console=tty1" - ]; - - # ============================================================ - # Console font for 5" 720x1280 display - # ============================================================ - console = { - earlySetup = true; - font = "ter-v24n"; - packages = with pkgs; [ terminus_font ]; - }; - - # ============================================================ - # Display — vc4/panel_cwu50 loaded AFTER RP1 PCIe init - # Rien dans initrd — tout RP1 est derrière PCIe - # ============================================================ - hardware.graphics.enable = true; - - boot.kernelModules = [ - "panel_cwu50" # uConsole DSI panel driver - "vc4" # VideoCore 4 KMS GPU driver - "rp1_dsi" # RP1 DSI bridge driver - ]; - - boot.initrd.kernelModules = lib.mkForce [ ]; - - # ============================================================ - # CM5 Config.txt — override complet (clear les defaults de nixos-uconsole) - # ============================================================ - hardware.raspberry-pi.config = { }; - - hardware.raspberry-pi.extra-config = '' - [all] - arm_64bit=1 - enable_uart=1 - disable_audio_dither=1 - ignore_lcd=0 - dtdebug=1 - gpio=10=ip,np - gpio=11=op,dh - dtoverlay=audremap - dtparam=ant2=on - dtparam=audio=on - dtparam=pin_12_13=on - - [pi5] - dtoverlay=clockworkpi-uconsole-cm5 - dtoverlay=vc4-kms-v3d-pi5,cma-384 - dtparam=pciex1=off - dtparam=nohdmi1=off - ''; - - # ============================================================ - # CM5 Display Backlight Fix - # ============================================================ - systemd.services.cm5-backlight-fix = { - description = "CM5 Display Backlight Fix"; - after = [ "multi-user.target" ]; - wantedBy = [ "multi-user.target" ]; - serviceConfig = { - Type = "oneshot"; - ExecStart = let - fixScript = pkgs.writeShellScript "backlight-fix" '' - for bl in /sys/class/backlight/*/brightness; do - if [ -f "$bl" ]; then - max=$(cat "$(dirname "$bl")/max_brightness" 2>/dev/null || echo 100) - echo "$max" > "$bl" 2>/dev/null || true - fi - done - ''; - in "${fixScript}"; - }; - }; - - # ============================================================ - # Minimal packages - # ============================================================ - environment.systemPackages = with pkgs; [ - git - vim - htop - libgpiod # GPIO control - ]; + # Firmware + hardware.enableRedistributableFirmware = true; } -- 2.49.1 From a312c29221f19bad1803f4f285faab3fca03b8fb Mon Sep 17 00:00:00 2001 From: Hermes Date: Fri, 12 Jun 2026 20:48:30 -0400 Subject: [PATCH 022/157] fix: remove boot.loader.raspberry-pi reference (option removed with rasberry-pi-5.base) --- flake.nix | 1 - 1 file changed, 1 deletion(-) diff --git a/flake.nix b/flake.nix index d9f252d..63bf435 100644 --- a/flake.nix +++ b/flake.nix @@ -111,7 +111,6 @@ nixpkgs.buildPlatform = "x86_64-linux"; nixpkgs.hostPlatform = "aarch64-linux"; nixpkgs.config.allowUnfree = true; - boot.loader.raspberry-pi.bootloader = "kernel"; } # nixos-raspberrypi — pkgs.rpi + overlays standardisés nixos-raspberrypi.nixosModules.nixpkgs-rpi -- 2.49.1 From 8b6990ceeeb116ea14f9d1642af2482dea7d0c80 Mon Sep 17 00:00:00 2001 From: Hermes Date: Fri, 12 Jun 2026 20:52:11 -0400 Subject: [PATCH 023/157] =?UTF-8?q?deploy1(uconsole):=20revert=20rasberry-?= =?UTF-8?q?pi-5.base=20removal=20=E2=80=94=20keep=20minimal=20SSH+WiFi=20c?= =?UTF-8?q?onfig?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- flake.nix | 2 ++ 1 file changed, 2 insertions(+) diff --git a/flake.nix b/flake.nix index 63bf435..2f0d54a 100644 --- a/flake.nix +++ b/flake.nix @@ -111,9 +111,11 @@ nixpkgs.buildPlatform = "x86_64-linux"; nixpkgs.hostPlatform = "aarch64-linux"; nixpkgs.config.allowUnfree = true; + boot.loader.raspberry-pi.bootloader = lib.mkForce "kernel"; } # nixos-raspberrypi — pkgs.rpi + overlays standardisés nixos-raspberrypi.nixosModules.nixpkgs-rpi + nixos-raspberrypi.nixosModules.raspberry-pi-5.base nixos-raspberrypi.lib.inject-overlays nixos-raspberrypi.lib.inject-overlays-global # nixos-uconsole CM5 modules -- 2.49.1 From 656570b39e0c23ec04ee8b160f2c23d6b5dd7417 Mon Sep 17 00:00:00 2001 From: Hermes Date: Fri, 12 Jun 2026 20:54:19 -0400 Subject: [PATCH 024/157] fix: use plain string for bootloader setting --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 2f0d54a..5a1b3b5 100644 --- a/flake.nix +++ b/flake.nix @@ -111,7 +111,7 @@ nixpkgs.buildPlatform = "x86_64-linux"; nixpkgs.hostPlatform = "aarch64-linux"; nixpkgs.config.allowUnfree = true; - boot.loader.raspberry-pi.bootloader = lib.mkForce "kernel"; + boot.loader.raspberry-pi.bootloader = "kernel"; } # nixos-raspberrypi — pkgs.rpi + overlays standardisés nixos-raspberrypi.nixosModules.nixpkgs-rpi -- 2.49.1 From 3d86af76b9ef5657ea90b8308ede18b0da4ceaec Mon Sep 17 00:00:00 2001 From: Hermes Date: Fri, 12 Jun 2026 20:55:42 -0400 Subject: [PATCH 025/157] fix: remove non-existent ssh opts for nixpkgs-25.11 --- hosts/uconsole-cm5/configuration.nix | 2 -- 1 file changed, 2 deletions(-) diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index eca2778..5a1b679 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -13,8 +13,6 @@ PermitRootLogin = lib.mkForce "prohibit-password"; PasswordAuthentication = lib.mkForce false; }; - authorizedKeysInHomedir = true; - authorizeKeysFromNixStore = false; }; users.users.root.openssh.authorizedKeys.keys = with keys; [ -- 2.49.1 From 80efb68428df73cdcb332f8266ea5c5e7d522708 Mon Sep 17 00:00:00 2001 From: Hermes Date: Fri, 12 Jun 2026 21:42:51 -0400 Subject: [PATCH 026/157] feat(uconsole): add flashable SD image package (SSH+WiFi+keys) --- flake.nix | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/flake.nix b/flake.nix index 5a1b3b5..281936f 100644 --- a/flake.nix +++ b/flake.nix @@ -139,5 +139,28 @@ }; }; devShells.${system}.default = devShell; + packages.${system} = { + # Image SD flashable pour uConsole CM5 (SSH + WiFi + clés) + # Usage : dd if=result of=/dev/sda bs=4M status=progress conv=fsync + uconsole-cm5-image = nixos-uconsole.lib.mkUConsoleImage { + variant = "cm5"; + modules = [ + { + nixpkgs.buildPlatform = system; + nixpkgs.hostPlatform = "aarch64-linux"; + nixpkgs.config.allowUnfree = true; + } + nixos-raspberrypi.nixosModules.nixpkgs-rpi + nixos-raspberrypi.nixosModules.raspberry-pi-5.base + nixos-raspberrypi.lib.inject-overlays-global + # kernel uConsole + notre config minimal + nixos-uconsole.nixosModules.kernel + (nixos-uconsole.nixosModules.cm { lib = nixpkgs-uconsole.lib; isCM4 = false; }) + nixos-uconsole.nixosModules.base + agenix.nixosModules.default + ./hosts/uconsole-cm5/configuration.nix + ]; + }.config.system.build.sdImage; + }; }; } -- 2.49.1 From 7e3b2520eb28969e24ced5c31ad959ae37d9bede Mon Sep 17 00:00:00 2001 From: Hermes Date: Fri, 12 Jun 2026 21:47:29 -0400 Subject: [PATCH 027/157] fix: use nixos-raspberrypi.lib.nixosSystem + sd-image module directly --- flake.nix | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/flake.nix b/flake.nix index 281936f..47bbd63 100644 --- a/flake.nix +++ b/flake.nix @@ -142,25 +142,31 @@ packages.${system} = { # Image SD flashable pour uConsole CM5 (SSH + WiFi + clés) # Usage : dd if=result of=/dev/sda bs=4M status=progress conv=fsync - uconsole-cm5-image = nixos-uconsole.lib.mkUConsoleImage { - variant = "cm5"; + uconsole-cm5-image = let + rpi-pkgs = nixos-raspberrypi.lib.mkRpiPkgs forSystem "aarch64-linux"; + in (nixos-raspberrypi.lib.nixosSystem { + system = "aarch64-linux"; + specialArgs = { + inherit self keys inputs; + nixos-raspberrypi = nixos-raspberrypi; + isCM4 = false; + }; modules = [ { nixpkgs.buildPlatform = system; nixpkgs.hostPlatform = "aarch64-linux"; - nixpkgs.config.allowUnfree = true; } nixos-raspberrypi.nixosModules.nixpkgs-rpi nixos-raspberrypi.nixosModules.raspberry-pi-5.base nixos-raspberrypi.lib.inject-overlays-global - # kernel uConsole + notre config minimal + nixos-raspberrypi.nixosModules.system.sd-image nixos-uconsole.nixosModules.kernel (nixos-uconsole.nixosModules.cm { lib = nixpkgs-uconsole.lib; isCM4 = false; }) nixos-uconsole.nixosModules.base agenix.nixosModules.default ./hosts/uconsole-cm5/configuration.nix ]; - }.config.system.build.sdImage; + }).config.system.build.sdImage; }; }; } -- 2.49.1 From 90388637281a27f4a167f51be57ed6ab3edea0be Mon Sep 17 00:00:00 2001 From: Hermes Date: Fri, 12 Jun 2026 21:48:48 -0400 Subject: [PATCH 028/157] fix: remove dead rpi-pkgs line --- flake.nix | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/flake.nix b/flake.nix index 47bbd63..081c82d 100644 --- a/flake.nix +++ b/flake.nix @@ -142,9 +142,7 @@ packages.${system} = { # Image SD flashable pour uConsole CM5 (SSH + WiFi + clés) # Usage : dd if=result of=/dev/sda bs=4M status=progress conv=fsync - uconsole-cm5-image = let - rpi-pkgs = nixos-raspberrypi.lib.mkRpiPkgs forSystem "aarch64-linux"; - in (nixos-raspberrypi.lib.nixosSystem { + uconsole-cm5-image = (nixos-raspberrypi.lib.nixosSystem { system = "aarch64-linux"; specialArgs = { inherit self keys inputs; -- 2.49.1 From 0db807130014d567179a3220e4ede8d86b45cf3d Mon Sep 17 00:00:00 2001 From: Hermes Date: Fri, 12 Jun 2026 21:56:22 -0400 Subject: [PATCH 029/157] fix: correct sd-image module path --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 081c82d..9e72d87 100644 --- a/flake.nix +++ b/flake.nix @@ -157,7 +157,7 @@ nixos-raspberrypi.nixosModules.nixpkgs-rpi nixos-raspberrypi.nixosModules.raspberry-pi-5.base nixos-raspberrypi.lib.inject-overlays-global - nixos-raspberrypi.nixosModules.system.sd-image + nixos-raspberrypi.nixosModules.installer.sd-card.sd-image-raspberrypi nixos-uconsole.nixosModules.kernel (nixos-uconsole.nixosModules.cm { lib = nixpkgs-uconsole.lib; isCM4 = false; }) nixos-uconsole.nixosModules.base -- 2.49.1 From 6543de3a4598480e5eaa8c1493fbbe7dfb80d3de Mon Sep 17 00:00:00 2001 From: Hermes Date: Fri, 12 Jun 2026 21:57:49 -0400 Subject: [PATCH 030/157] fix: correct sd-image module to nixosModules.sd-image --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 9e72d87..5038e6b 100644 --- a/flake.nix +++ b/flake.nix @@ -157,7 +157,7 @@ nixos-raspberrypi.nixosModules.nixpkgs-rpi nixos-raspberrypi.nixosModules.raspberry-pi-5.base nixos-raspberrypi.lib.inject-overlays-global - nixos-raspberrypi.nixosModules.installer.sd-card.sd-image-raspberrypi + nixos-raspberrypi.nixosModules.sd-image nixos-uconsole.nixosModules.kernel (nixos-uconsole.nixosModules.cm { lib = nixpkgs-uconsole.lib; isCM4 = false; }) nixos-uconsole.nixosModules.base -- 2.49.1 From 4d8087badfc4dd9f8ff0f52f185c01fc5318a11e Mon Sep 17 00:00:00 2001 From: Hermes Date: Sat, 13 Jun 2026 13:47:35 -0400 Subject: [PATCH 031/157] fix: apply DSI burst mode fix as kernel patch overlay --- hosts/uconsole-cm5/configuration.nix | 10 ++++++++ .../patches/0008-dsi-burst-fix.patch | 23 +++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 hosts/uconsole-cm5/patches/0008-dsi-burst-fix.patch diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index 5a1b679..c5a7c6d 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -25,4 +25,14 @@ # Firmware hardware.enableRedistributableFirmware = true; + + # DSI burst mode fix: remove SYNC_PULSE flag from CWU50 panel driver + # BURST and SYNC_PULSE are mutually exclusive per MIPI DSI spec; + # having both set causes display corruption on CM5 + boot.kernelPatches = lib.mkAfter [ + { + name = "0008-dsi-burst-fix"; + patch = ./patches/0008-dsi-burst-fix.patch; + } + ]; } diff --git a/hosts/uconsole-cm5/patches/0008-dsi-burst-fix.patch b/hosts/uconsole-cm5/patches/0008-dsi-burst-fix.patch new file mode 100644 index 0000000..03786ad --- /dev/null +++ b/hosts/uconsole-cm5/patches/0008-dsi-burst-fix.patch @@ -0,0 +1,23 @@ +diff --git a/drivers/gpu/drm/panel/panel-cwu50.c b/drivers/gpu/drm/panel/panel-cwu50.c +index 1111111..2222222 100644 +--- a/drivers/gpu/drm/panel/panel-cwu50.c ++++ b/drivers/gpu/drm/panel/panel-cwu50.c +@@ -1072,7 +1072,7 @@ static int cwu50_probe(struct mipi_dsi_device *dsi) + + dsi->lanes = 4; + dsi->format = MIPI_DSI_FMT_RGB888; +- dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_VIDEO_SYNC_PULSE; ++ dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST; + + ctx->id_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_IN); + if (IS_ERR(ctx->id_gpio)) { +@@ -1706,7 +1706,7 @@ static int cwu50_cm3_probe(struct mipi_dsi_device *dsi) + dsi->lanes = 4; + dsi->format = MIPI_DSI_FMT_RGB888; + dsi->mode_flags = MIPI_DSI_MODE_VIDEO | +- MIPI_DSI_MODE_VIDEO_BURST | +- MIPI_DSI_MODE_VIDEO_SYNC_PULSE; ++ MIPI_DSI_MODE_VIDEO_BURST; + + ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(ctx->reset_gpio)) { -- 2.49.1 From 0f765d99cb06e49b0191af48618071f6e91bc96f Mon Sep 17 00:00:00 2001 From: Hermes Date: Sat, 13 Jun 2026 16:19:53 -0400 Subject: [PATCH 032/157] feat: add CWU50 display patch (no-burst) + fix flake syntax Remove extra '};' that broke flake.nix parsing. Apply kernel patch '0008-panel-cwu50-no-burst.patch' to remove MIPI_DSI_MODE_VIDEO_BURST flag in panel-cwu50.c. Switch nixos-uconsole module to consolidated uconsole-cm5 module. Keep patches/0008-panel-cwu50-remove-sync-pulse.patch as variant. --- flake.nix | 225 ++++++++---------- hosts/uconsole-cm5/configuration.nix | 10 +- .../patches/0008-dsi-burst-fix.patch | 23 -- patches/0008-panel-cwu50-no-burst.patch | 11 + .../0008-panel-cwu50-remove-sync-pulse.patch | 11 + 5 files changed, 128 insertions(+), 152 deletions(-) delete mode 100644 hosts/uconsole-cm5/patches/0008-dsi-burst-fix.patch create mode 100644 patches/0008-panel-cwu50-no-burst.patch create mode 100644 patches/0008-panel-cwu50-remove-sync-pulse.patch diff --git a/flake.nix b/flake.nix index 5038e6b..fc17993 100644 --- a/flake.nix +++ b/flake.nix @@ -12,8 +12,6 @@ url = "git+https://git.lix.systems/lix-project/lix?ref=main"; inputs.nixpkgs.follows = "nixpkgs"; }; - - # uConsole CM5 — pinned nixpkgs for kernel patch compatibility nixpkgs-uconsole.url = "github:NixOS/nixpkgs/nixos-25.11"; nixos-uconsole = { url = "github:nixos-uconsole/nixos-uconsole/v1.1.0"; @@ -23,8 +21,8 @@ nixos-raspberrypi = { url = "github:gortium/nixos-raspberrypi/cm5-cross-v1"; inputs.nixpkgs.follows = "nixpkgs-uconsole"; + }; }; -}; outputs = { self, nixpkgs, agenix, lix , nixpkgs-uconsole, nixos-uconsole, nixos-raspberrypi @@ -43,128 +41,115 @@ pkgs = import nixpkgs { inherit system overlays; config.allowUnfree = true; - config.permittedInsecurePackages = [ - "openclaw-2026.3.12" - ]; + config.permittedInsecurePackages = [ "openclaw-2026.3.12" ]; }; - devShell = import ./shells/nix_dev.nix { inherit pkgs system agenix; }; - in - { - nixosConfigurations = { - lazyworkhorse = nixpkgs.lib.nixosSystem { - specialArgs = { inherit system self keys paths inputs; }; - modules = [ - { - nixpkgs.overlays = overlays; - nixpkgs.config.allowUnfree = true; - nixpkgs.config.rocmSupport = true; - nixpkgs.config.permittedInsecurePackages = [ - "openclaw-2026.3.12" - ]; - nix.package = lix.packages.${system}.default; - } - agenix.nixosModules.default - ./hosts/lazyworkhorse/configuration.nix - ./hosts/lazyworkhorse/hardware-configuration.nix - ./modules/nixos/filesystem/hoardingcow-mount.nix - ./modules/nixos/services/docker_manager.nix - ./modules/nixos/services/open_code_server.nix - ./modules/nixos/services/ollama_init_custom_models.nix - ./modules/nixos/services/openclaw_node.nix - ./modules/nixos/security/ai-worker-restricted.nix - ./users/gortium.nix - ./users/ai-worker.nix - ]; - }; - - cyt-pi = nixpkgs.lib.nixosSystem { - specialArgs = { inherit self keys paths inputs; }; - modules = [ - { - nixpkgs.overlays = overlays; - nixpkgs.config.allowUnfree = true; - nixpkgs.hostPlatform = "aarch64-linux"; - nix.package = lix.packages."aarch64-linux".default; - } - ./hosts/cyt-pi/configuration.nix - ./hosts/cyt-pi/hardware-configuration.nix - ]; - }; - - # ============================================================ - # uConsole CM5 — cross-compilé (build sur x86_64, run sur ARM) - # Approche incrémentale pour fixer l'écran - # ============================================================ - uconsole-cm5 = nixpkgs-uconsole.lib.nixosSystem { - system = "aarch64-linux"; - specialArgs = { - inherit self keys paths inputs; - nixos-raspberrypi = nixos-raspberrypi; - isCM4 = false; - }; - modules = [ - { - # Cross-compile : build sur x86_64, run sur aarch64 - nixpkgs.buildPlatform = "x86_64-linux"; - nixpkgs.hostPlatform = "aarch64-linux"; - nixpkgs.config.allowUnfree = true; - boot.loader.raspberry-pi.bootloader = "kernel"; - } - # nixos-raspberrypi — pkgs.rpi + overlays standardisés - nixos-raspberrypi.nixosModules.nixpkgs-rpi - nixos-raspberrypi.nixosModules.raspberry-pi-5.base - nixos-raspberrypi.lib.inject-overlays - nixos-raspberrypi.lib.inject-overlays-global - # nixos-uconsole CM5 modules - nixos-uconsole.nixosModules.kernel - (nixos-uconsole.nixosModules.cm { lib = nixpkgs-uconsole.lib; isCM4 = false; }) - nixos-uconsole.nixosModules.base - # Lix cross-compilé (lix.packages.aarch64-linux est natif → QEMU) - ({ config, lib, pkgs, inputs, ... }: let - lix-cross = import inputs.nixpkgs-uconsole { - localSystem = { system = "x86_64-linux"; }; - crossSystem = { system = "aarch64-linux"; }; - overlays = [ inputs.lix.overlays.default ]; - }; - in { nix.package = lix-cross.lix; }) - # agenix - agenix.nixosModules.default - # Notre config - ./hosts/uconsole-cm5/configuration.nix - ./hosts/uconsole-cm5/hardware-configuration.nix - ]; - }; + in { + nixosConfigurations = { + lazyworkhorse = nixpkgs.lib.nixosSystem { + specialArgs = { inherit system self keys paths inputs; }; + modules = [ + { + nixpkgs.overlays = overlays; + nixpkgs.config.allowUnfree = true; + nixpkgs.config.rocmSupport = true; + nixpkgs.config.permittedInsecurePackages = [ "openclaw-2026.3.12" ]; + nix.package = lix.packages.${system}.default; + } + agenix.nixosModules.default + ./hosts/lazyworkhorse/configuration.nix + ./hosts/lazyworkhorse/hardware-configuration.nix + ./modules/nixos/filesystem/hoardingcow-mount.nix + ./modules/nixos/services/docker_manager.nix + ./modules/nixos/services/open_code_server.nix + ./modules/nixos/services/ollama_init_custom_models.nix + ./modules/nixos/services/openclaw_node.nix + ./modules/nixos/security/ai-worker-restricted.nix + ./users/gortium.nix + ./users/ai-worker.nix + ]; }; - devShells.${system}.default = devShell; - packages.${system} = { - # Image SD flashable pour uConsole CM5 (SSH + WiFi + clés) - # Usage : dd if=result of=/dev/sda bs=4M status=progress conv=fsync - uconsole-cm5-image = (nixos-raspberrypi.lib.nixosSystem { - system = "aarch64-linux"; - specialArgs = { - inherit self keys inputs; - nixos-raspberrypi = nixos-raspberrypi; - isCM4 = false; - }; - modules = [ - { - nixpkgs.buildPlatform = system; - nixpkgs.hostPlatform = "aarch64-linux"; - } - nixos-raspberrypi.nixosModules.nixpkgs-rpi - nixos-raspberrypi.nixosModules.raspberry-pi-5.base - nixos-raspberrypi.lib.inject-overlays-global - nixos-raspberrypi.nixosModules.sd-image - nixos-uconsole.nixosModules.kernel - (nixos-uconsole.nixosModules.cm { lib = nixpkgs-uconsole.lib; isCM4 = false; }) - nixos-uconsole.nixosModules.base - agenix.nixosModules.default - ./hosts/uconsole-cm5/configuration.nix - ]; - }).config.system.build.sdImage; + + cyt-pi = nixpkgs.lib.nixosSystem { + specialArgs = { inherit self keys paths inputs; }; + modules = [ + { + nixpkgs.overlays = overlays; + nixpkgs.config.allowUnfree = true; + nixpkgs.hostPlatform = "aarch64-linux"; + nix.package = lix.packages."aarch64-linux".default; + } + ./hosts/cyt-pi/configuration.nix + ./hosts/cyt-pi/hardware-configuration.nix + ]; + }; + + uconsole-cm5 = nixpkgs-uconsole.lib.nixosSystem { + system = "aarch64-linux"; + specialArgs = { + inherit self keys paths inputs; + nixos-raspberrypi = nixos-raspberrypi; + isCM4 = false; + }; + modules = [ + { + nixpkgs.buildPlatform = "x86_64-linux"; + nixpkgs.hostPlatform = "aarch64-linux"; + nixpkgs.config.allowUnfree = true; + boot.loader.raspberry-pi.bootloader = "kernel"; + } + # Kernel patch: SYNC_PULSE-only (remove BURST) + ({ lib, ... }: { + boot.kernelPatches = [{ + name = "panel-cwu50-no-burst"; + patch = ./patches/0008-panel-cwu50-no-burst.patch; + }]; + }) + nixos-raspberrypi.nixosModules.nixpkgs-rpi + nixos-raspberrypi.nixosModules.raspberry-pi-5.base + nixos-raspberrypi.lib.inject-overlays + nixos-raspberrypi.lib.inject-overlays-global + nixos-uconsole.nixosModules.uconsole-cm5 + ({ config, lib, pkgs, inputs, ... }: let + lix-cross = import inputs.nixpkgs-uconsole { + localSystem = { system = "x86_64-linux"; }; + crossSystem = { system = "aarch64-linux"; }; + overlays = [ inputs.lix.overlays.default ]; + }; + in { nix.package = lix-cross.lix; }) + agenix.nixosModules.default + ./hosts/uconsole-cm5/configuration.nix + ./hosts/uconsole-cm5/hardware-configuration.nix + ]; }; }; + + devShells.${system}.default = devShell; + + packages.${system} = { + uconsole-cm5-image = (nixos-raspberrypi.lib.nixosSystem { + system = "aarch64-linux"; + specialArgs = { + inherit self keys inputs; + nixos-raspberrypi = nixos-raspberrypi; + isCM4 = false; + }; + modules = [ + { + nixpkgs.buildPlatform = system; + nixpkgs.hostPlatform = "aarch64-linux"; + } + nixos-raspberrypi.nixosModules.nixpkgs-rpi + nixos-raspberrypi.nixosModules.raspberry-pi-5.base + nixos-raspberrypi.lib.inject-overlays-global + nixos-raspberrypi.nixosModules.sd-image + nixos-uconsole.nixosModules.uconsole-cm5 + agenix.nixosModules.default + ./hosts/uconsole-cm5/configuration.nix + ]; + }).config.system.build.sdImage; + }; + }; } diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index c5a7c6d..438578a 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -26,13 +26,5 @@ # Firmware hardware.enableRedistributableFirmware = true; - # DSI burst mode fix: remove SYNC_PULSE flag from CWU50 panel driver - # BURST and SYNC_PULSE are mutually exclusive per MIPI DSI spec; - # having both set causes display corruption on CM5 - boot.kernelPatches = lib.mkAfter [ - { - name = "0008-dsi-burst-fix"; - patch = ./patches/0008-dsi-burst-fix.patch; - } - ]; + # DSI display fix: le kernel patch est dans flake.nix (patches/0008-panel-cwu50-no-burst.patch) } diff --git a/hosts/uconsole-cm5/patches/0008-dsi-burst-fix.patch b/hosts/uconsole-cm5/patches/0008-dsi-burst-fix.patch deleted file mode 100644 index 03786ad..0000000 --- a/hosts/uconsole-cm5/patches/0008-dsi-burst-fix.patch +++ /dev/null @@ -1,23 +0,0 @@ -diff --git a/drivers/gpu/drm/panel/panel-cwu50.c b/drivers/gpu/drm/panel/panel-cwu50.c -index 1111111..2222222 100644 ---- a/drivers/gpu/drm/panel/panel-cwu50.c -+++ b/drivers/gpu/drm/panel/panel-cwu50.c -@@ -1072,7 +1072,7 @@ static int cwu50_probe(struct mipi_dsi_device *dsi) - - dsi->lanes = 4; - dsi->format = MIPI_DSI_FMT_RGB888; -- dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_VIDEO_SYNC_PULSE; -+ dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST; - - ctx->id_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_IN); - if (IS_ERR(ctx->id_gpio)) { -@@ -1706,7 +1706,7 @@ static int cwu50_cm3_probe(struct mipi_dsi_device *dsi) - dsi->lanes = 4; - dsi->format = MIPI_DSI_FMT_RGB888; - dsi->mode_flags = MIPI_DSI_MODE_VIDEO | -- MIPI_DSI_MODE_VIDEO_BURST | -- MIPI_DSI_MODE_VIDEO_SYNC_PULSE; -+ MIPI_DSI_MODE_VIDEO_BURST; - - ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(ctx->reset_gpio)) { diff --git a/patches/0008-panel-cwu50-no-burst.patch b/patches/0008-panel-cwu50-no-burst.patch new file mode 100644 index 0000000..2109b0e --- /dev/null +++ b/patches/0008-panel-cwu50-no-burst.patch @@ -0,0 +1,11 @@ +--- a/drivers/gpu/drm/panel/panel-cwu50.c ++++ b/drivers/gpu/drm/panel/panel-cwu50.c +@@ -622,7 +622,7 @@ static int cwu50_probe(struct mipi_dsi_device *dsi) + + dsi->lanes = 4; + dsi->format = MIPI_DSI_FMT_RGB888; +- dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_VIDEO_SYNC_PULSE; ++ dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE; + + ctx->id_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_IN); + if (IS_ERR(ctx->id_gpio)) { diff --git a/patches/0008-panel-cwu50-remove-sync-pulse.patch b/patches/0008-panel-cwu50-remove-sync-pulse.patch new file mode 100644 index 0000000..b553fbb --- /dev/null +++ b/patches/0008-panel-cwu50-remove-sync-pulse.patch @@ -0,0 +1,11 @@ +--- a/drivers/gpu/drm/panel/panel-cwu50.c ++++ b/drivers/gpu/drm/panel/panel-cwu50.c +@@ -622,7 +622,7 @@ static int cwu50_probe(struct mipi_dsi_device *dsi) + + dsi->lanes = 4; + dsi->format = MIPI_DSI_FMT_RGB888; +- dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_VIDEO_SYNC_PULSE; ++ dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST; + + ctx->id_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_IN); + if (IS_ERR(ctx->id_gpio)) { -- 2.49.1 From 3a809938c9306a791a20059ffee5860b8e262db9 Mon Sep 17 00:00:00 2001 From: Hermes Date: Sat, 13 Jun 2026 16:38:24 -0400 Subject: [PATCH 033/157] try: no-sync-pulse variant (keep BURST, remove SYNC_PULSE) --- flake.nix | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.nix b/flake.nix index fc17993..1c2c3f5 100644 --- a/flake.nix +++ b/flake.nix @@ -100,11 +100,11 @@ nixpkgs.config.allowUnfree = true; boot.loader.raspberry-pi.bootloader = "kernel"; } - # Kernel patch: SYNC_PULSE-only (remove BURST) + # Kernel patch: BURST-only (remove SYNC_PULSE) ({ lib, ... }: { boot.kernelPatches = [{ - name = "panel-cwu50-no-burst"; - patch = ./patches/0008-panel-cwu50-no-burst.patch; + name = "panel-cwu50-remove-sync-pulse"; + patch = ./patches/0008-panel-cwu50-remove-sync-pulse.patch; }]; }) nixos-raspberrypi.nixosModules.nixpkgs-rpi -- 2.49.1 From a4f48912369cf0225940c7bd2610718e882cdf8d Mon Sep 17 00:00:00 2001 From: Hermes Date: Sat, 13 Jun 2026 17:12:51 -0400 Subject: [PATCH 034/157] try: no-burst-no-sync-pulse (VIDEO only) --- flake.nix | 6 +++--- patches/0008-panel-cwu50-no-burst-no-sync-pulse.patch | 11 +++++++++++ 2 files changed, 14 insertions(+), 3 deletions(-) create mode 100644 patches/0008-panel-cwu50-no-burst-no-sync-pulse.patch diff --git a/flake.nix b/flake.nix index 1c2c3f5..ee7fce7 100644 --- a/flake.nix +++ b/flake.nix @@ -100,11 +100,11 @@ nixpkgs.config.allowUnfree = true; boot.loader.raspberry-pi.bootloader = "kernel"; } - # Kernel patch: BURST-only (remove SYNC_PULSE) + # Kernel patch: VIDEO only (no BURST, no SYNC_PULSE) ({ lib, ... }: { boot.kernelPatches = [{ - name = "panel-cwu50-remove-sync-pulse"; - patch = ./patches/0008-panel-cwu50-remove-sync-pulse.patch; + name = "panel-cwu50-no-burst-no-sync-pulse"; + patch = ./patches/0008-panel-cwu50-no-burst-no-sync-pulse.patch; }]; }) nixos-raspberrypi.nixosModules.nixpkgs-rpi diff --git a/patches/0008-panel-cwu50-no-burst-no-sync-pulse.patch b/patches/0008-panel-cwu50-no-burst-no-sync-pulse.patch new file mode 100644 index 0000000..3fd90a1 --- /dev/null +++ b/patches/0008-panel-cwu50-no-burst-no-sync-pulse.patch @@ -0,0 +1,11 @@ +--- a/drivers/gpu/drm/panel/panel-cwu50.c ++++ b/drivers/gpu/drm/panel/panel-cwu50.c +@@ -622,7 +622,7 @@ static int cwu50_probe(struct mipi_dsi_device *dsi) + + dsi->lanes = 4; + dsi->format = MIPI_DSI_FMT_RGB888; +- dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_VIDEO_SYNC_PULSE; ++ dsi->mode_flags = MIPI_DSI_MODE_VIDEO; + + ctx->id_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_IN); + if (IS_ERR(ctx->id_gpio)) { -- 2.49.1 From 6fac886598b2d18a60f55a63493f81f8b9f19c70 Mon Sep 17 00:00:00 2001 From: Hermes Date: Sat, 13 Jun 2026 18:04:06 -0400 Subject: [PATCH 035/157] revert: remove failed CWU50 display fix patches --- flake.nix | 7 ------- patches/0008-panel-cwu50-no-burst-no-sync-pulse.patch | 11 ----------- patches/0008-panel-cwu50-no-burst.patch | 11 ----------- patches/0008-panel-cwu50-remove-sync-pulse.patch | 11 ----------- 4 files changed, 40 deletions(-) delete mode 100644 patches/0008-panel-cwu50-no-burst-no-sync-pulse.patch delete mode 100644 patches/0008-panel-cwu50-no-burst.patch delete mode 100644 patches/0008-panel-cwu50-remove-sync-pulse.patch diff --git a/flake.nix b/flake.nix index ee7fce7..8d54722 100644 --- a/flake.nix +++ b/flake.nix @@ -100,13 +100,6 @@ nixpkgs.config.allowUnfree = true; boot.loader.raspberry-pi.bootloader = "kernel"; } - # Kernel patch: VIDEO only (no BURST, no SYNC_PULSE) - ({ lib, ... }: { - boot.kernelPatches = [{ - name = "panel-cwu50-no-burst-no-sync-pulse"; - patch = ./patches/0008-panel-cwu50-no-burst-no-sync-pulse.patch; - }]; - }) nixos-raspberrypi.nixosModules.nixpkgs-rpi nixos-raspberrypi.nixosModules.raspberry-pi-5.base nixos-raspberrypi.lib.inject-overlays diff --git a/patches/0008-panel-cwu50-no-burst-no-sync-pulse.patch b/patches/0008-panel-cwu50-no-burst-no-sync-pulse.patch deleted file mode 100644 index 3fd90a1..0000000 --- a/patches/0008-panel-cwu50-no-burst-no-sync-pulse.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/drivers/gpu/drm/panel/panel-cwu50.c -+++ b/drivers/gpu/drm/panel/panel-cwu50.c -@@ -622,7 +622,7 @@ static int cwu50_probe(struct mipi_dsi_device *dsi) - - dsi->lanes = 4; - dsi->format = MIPI_DSI_FMT_RGB888; -- dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_VIDEO_SYNC_PULSE; -+ dsi->mode_flags = MIPI_DSI_MODE_VIDEO; - - ctx->id_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_IN); - if (IS_ERR(ctx->id_gpio)) { diff --git a/patches/0008-panel-cwu50-no-burst.patch b/patches/0008-panel-cwu50-no-burst.patch deleted file mode 100644 index 2109b0e..0000000 --- a/patches/0008-panel-cwu50-no-burst.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/drivers/gpu/drm/panel/panel-cwu50.c -+++ b/drivers/gpu/drm/panel/panel-cwu50.c -@@ -622,7 +622,7 @@ static int cwu50_probe(struct mipi_dsi_device *dsi) - - dsi->lanes = 4; - dsi->format = MIPI_DSI_FMT_RGB888; -- dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_VIDEO_SYNC_PULSE; -+ dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE; - - ctx->id_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_IN); - if (IS_ERR(ctx->id_gpio)) { diff --git a/patches/0008-panel-cwu50-remove-sync-pulse.patch b/patches/0008-panel-cwu50-remove-sync-pulse.patch deleted file mode 100644 index b553fbb..0000000 --- a/patches/0008-panel-cwu50-remove-sync-pulse.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/drivers/gpu/drm/panel/panel-cwu50.c -+++ b/drivers/gpu/drm/panel/panel-cwu50.c -@@ -622,7 +622,7 @@ static int cwu50_probe(struct mipi_dsi_device *dsi) - - dsi->lanes = 4; - dsi->format = MIPI_DSI_FMT_RGB888; -- dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_VIDEO_SYNC_PULSE; -+ dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST; - - ctx->id_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_IN); - if (IS_ERR(ctx->id_gpio)) { -- 2.49.1 From 2c9136d1dcc89e40da57837c7b799726ecb253e2 Mon Sep 17 00:00:00 2001 From: Hermes Date: Sat, 13 Jun 2026 18:49:36 -0400 Subject: [PATCH 036/157] fix: add DSI_INIT0 lane config to old panel init_sequence + fix mode_flags --- flake.nix | 7 +++++++ patches/0008-panel-cwu50-fix-init-seq1.patch | 17 +++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 patches/0008-panel-cwu50-fix-init-seq1.patch diff --git a/flake.nix b/flake.nix index 8d54722..778474b 100644 --- a/flake.nix +++ b/flake.nix @@ -101,6 +101,13 @@ boot.loader.raspberry-pi.bootloader = "kernel"; } nixos-raspberrypi.nixosModules.nixpkgs-rpi + # Fix old panel init_sequence: add DSI_INIT0 lane config, remove contradictory BURST flag + ({ lib, ... }: { + boot.kernelPatches = [{ + name = "panel-cwu50-fix-lanes"; + patch = ./patches/0008-panel-cwu50-fix-init-seq1.patch; + }]; + }) nixos-raspberrypi.nixosModules.raspberry-pi-5.base nixos-raspberrypi.lib.inject-overlays nixos-raspberrypi.lib.inject-overlays-global diff --git a/patches/0008-panel-cwu50-fix-init-seq1.patch b/patches/0008-panel-cwu50-fix-init-seq1.patch new file mode 100644 index 0000000..eb0e0a5 --- /dev/null +++ b/patches/0008-panel-cwu50-fix-init-seq1.patch @@ -0,0 +1,17 @@ +--- a/drivers/gpu/drm/panel/panel-cwu50.c ++++ b/drivers/gpu/drm/panel/panel-cwu50.c +@@ -65,6 +65,8 @@ static void cwu50_init_sequence(struct cwu50 *ctx) + dcs_write_seq(0x72,0x06); + dcs_write_seq(0x75,0x03); ++ /* DSI_INIT0: set 4 lanes (bits[1:0]=11) — fixes lane count default */ ++ dcs_write_seq(0x80,0x03); + dcs_write_seq(0xE0,0x01); +@@ -162,7 +164,7 @@ static int cwu50_probe(struct mipi_dsi_device *dsi) + + dsi->lanes = 4; + dsi->format = MIPI_DSI_FMT_RGB888; +- dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_VIDEO_SYNC_PULSE; ++ dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE; + + ctx->id_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_IN); + if (IS_ERR(ctx->id_gpio)) { \ No newline at end of file -- 2.49.1 From cb2b535fde86eaf3089206899bd580393f30ebb4 Mon Sep 17 00:00:00 2001 From: Hermes Date: Sat, 13 Jun 2026 18:51:39 -0400 Subject: [PATCH 037/157] =?UTF-8?q?fix:=20correct=20patch=20format=20?= =?UTF-8?q?=E2=80=94=20blank=20line=20between=20hunks?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- patches/0008-panel-cwu50-fix-init-seq1.patch | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/patches/0008-panel-cwu50-fix-init-seq1.patch b/patches/0008-panel-cwu50-fix-init-seq1.patch index eb0e0a5..fbf3c81 100644 --- a/patches/0008-panel-cwu50-fix-init-seq1.patch +++ b/patches/0008-panel-cwu50-fix-init-seq1.patch @@ -1,12 +1,17 @@ --- a/drivers/gpu/drm/panel/panel-cwu50.c +++ b/drivers/gpu/drm/panel/panel-cwu50.c -@@ -65,6 +65,8 @@ static void cwu50_init_sequence(struct cwu50 *ctx) +@@ -67,7 +67,9 @@ static void cwu50_init_sequence(struct cwu50 *ctx) dcs_write_seq(0x72,0x06); dcs_write_seq(0x75,0x03); + /* DSI_INIT0: set 4 lanes (bits[1:0]=11) — fixes lane count default */ + dcs_write_seq(0x80,0x03); dcs_write_seq(0xE0,0x01); -@@ -162,7 +164,7 @@ static int cwu50_probe(struct mipi_dsi_device *dsi) ++ + dcs_write_seq(0x00,0x00); + dcs_write_seq(0x01,0x47);//VCOM0x47 + dcs_write_seq(0x03,0x00); + +@@ -164,7 +166,7 @@ static int cwu50_probe(struct mipi_dsi_device *dsi) dsi->lanes = 4; dsi->format = MIPI_DSI_FMT_RGB888; -- 2.49.1 From 67aafe37dbd8be208bf037fdc51884c5ed614ad8 Mon Sep 17 00:00:00 2001 From: Hermes Date: Sat, 13 Jun 2026 18:59:29 -0400 Subject: [PATCH 038/157] fix: add DSI_INIT0 lane config to old panel init seq + fix mode_flags --- patches/0008-panel-cwu50-fix-init-seq1.patch | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/patches/0008-panel-cwu50-fix-init-seq1.patch b/patches/0008-panel-cwu50-fix-init-seq1.patch index fbf3c81..e2bb8fc 100644 --- a/patches/0008-panel-cwu50-fix-init-seq1.patch +++ b/patches/0008-panel-cwu50-fix-init-seq1.patch @@ -1,18 +1,15 @@ --- a/drivers/gpu/drm/panel/panel-cwu50.c +++ b/drivers/gpu/drm/panel/panel-cwu50.c -@@ -67,7 +67,9 @@ static void cwu50_init_sequence(struct cwu50 *ctx) +@@ -58,5 +58,8 @@ dcs_write_seq(0x72,0x06); dcs_write_seq(0x75,0x03); -+ /* DSI_INIT0: set 4 lanes (bits[1:0]=11) — fixes lane count default */ ++ /* DSI_INIT0: set 4 lanes (bits[1:0]=11) */ + dcs_write_seq(0x80,0x03); dcs_write_seq(0xE0,0x01); + dcs_write_seq(0x00,0x00); dcs_write_seq(0x01,0x47);//VCOM0x47 - dcs_write_seq(0x03,0x00); - -@@ -164,7 +166,7 @@ static int cwu50_probe(struct mipi_dsi_device *dsi) - +@@ -721,6 +723,6 @@ dsi->lanes = 4; dsi->format = MIPI_DSI_FMT_RGB888; - dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_VIDEO_SYNC_PULSE; -- 2.49.1 From 3f985c72de885c192f20aeab340bd3ed8443f1d5 Mon Sep 17 00:00:00 2001 From: Hermes Date: Sat, 13 Jun 2026 23:15:53 -0400 Subject: [PATCH 039/157] switch to gortium/nixos-uconsole fork --- flake.nix | 221 ++++++++++++++++++++++++------------------------------ 1 file changed, 100 insertions(+), 121 deletions(-) diff --git a/flake.nix b/flake.nix index 5038e6b..5bde76e 100644 --- a/flake.nix +++ b/flake.nix @@ -12,19 +12,17 @@ url = "git+https://git.lix.systems/lix-project/lix?ref=main"; inputs.nixpkgs.follows = "nixpkgs"; }; - - # uConsole CM5 — pinned nixpkgs for kernel patch compatibility nixpkgs-uconsole.url = "github:NixOS/nixpkgs/nixos-25.11"; nixos-uconsole = { - url = "github:nixos-uconsole/nixos-uconsole/v1.1.0"; + url = "github:gortium/nixos-uconsole/cm5_fix"; inputs.nixpkgs.follows = "nixpkgs-uconsole"; inputs.nixos-raspberrypi.follows = "nixos-raspberrypi"; }; nixos-raspberrypi = { url = "github:gortium/nixos-raspberrypi/cm5-cross-v1"; inputs.nixpkgs.follows = "nixpkgs-uconsole"; + }; }; -}; outputs = { self, nixpkgs, agenix, lix , nixpkgs-uconsole, nixos-uconsole, nixos-raspberrypi @@ -43,128 +41,109 @@ pkgs = import nixpkgs { inherit system overlays; config.allowUnfree = true; - config.permittedInsecurePackages = [ - "openclaw-2026.3.12" - ]; + config.permittedInsecurePackages = [ "openclaw-2026.3.12" ]; }; - devShell = import ./shells/nix_dev.nix { inherit pkgs system agenix; }; - in - { - nixosConfigurations = { - lazyworkhorse = nixpkgs.lib.nixosSystem { - specialArgs = { inherit system self keys paths inputs; }; - modules = [ - { - nixpkgs.overlays = overlays; - nixpkgs.config.allowUnfree = true; - nixpkgs.config.rocmSupport = true; - nixpkgs.config.permittedInsecurePackages = [ - "openclaw-2026.3.12" - ]; - nix.package = lix.packages.${system}.default; - } - agenix.nixosModules.default - ./hosts/lazyworkhorse/configuration.nix - ./hosts/lazyworkhorse/hardware-configuration.nix - ./modules/nixos/filesystem/hoardingcow-mount.nix - ./modules/nixos/services/docker_manager.nix - ./modules/nixos/services/open_code_server.nix - ./modules/nixos/services/ollama_init_custom_models.nix - ./modules/nixos/services/openclaw_node.nix - ./modules/nixos/security/ai-worker-restricted.nix - ./users/gortium.nix - ./users/ai-worker.nix - ]; - }; - - cyt-pi = nixpkgs.lib.nixosSystem { - specialArgs = { inherit self keys paths inputs; }; - modules = [ - { - nixpkgs.overlays = overlays; - nixpkgs.config.allowUnfree = true; - nixpkgs.hostPlatform = "aarch64-linux"; - nix.package = lix.packages."aarch64-linux".default; - } - ./hosts/cyt-pi/configuration.nix - ./hosts/cyt-pi/hardware-configuration.nix - ]; - }; - - # ============================================================ - # uConsole CM5 — cross-compilé (build sur x86_64, run sur ARM) - # Approche incrémentale pour fixer l'écran - # ============================================================ - uconsole-cm5 = nixpkgs-uconsole.lib.nixosSystem { - system = "aarch64-linux"; - specialArgs = { - inherit self keys paths inputs; - nixos-raspberrypi = nixos-raspberrypi; - isCM4 = false; - }; - modules = [ - { - # Cross-compile : build sur x86_64, run sur aarch64 - nixpkgs.buildPlatform = "x86_64-linux"; - nixpkgs.hostPlatform = "aarch64-linux"; - nixpkgs.config.allowUnfree = true; - boot.loader.raspberry-pi.bootloader = "kernel"; - } - # nixos-raspberrypi — pkgs.rpi + overlays standardisés - nixos-raspberrypi.nixosModules.nixpkgs-rpi - nixos-raspberrypi.nixosModules.raspberry-pi-5.base - nixos-raspberrypi.lib.inject-overlays - nixos-raspberrypi.lib.inject-overlays-global - # nixos-uconsole CM5 modules - nixos-uconsole.nixosModules.kernel - (nixos-uconsole.nixosModules.cm { lib = nixpkgs-uconsole.lib; isCM4 = false; }) - nixos-uconsole.nixosModules.base - # Lix cross-compilé (lix.packages.aarch64-linux est natif → QEMU) - ({ config, lib, pkgs, inputs, ... }: let - lix-cross = import inputs.nixpkgs-uconsole { - localSystem = { system = "x86_64-linux"; }; - crossSystem = { system = "aarch64-linux"; }; - overlays = [ inputs.lix.overlays.default ]; - }; - in { nix.package = lix-cross.lix; }) - # agenix - agenix.nixosModules.default - # Notre config - ./hosts/uconsole-cm5/configuration.nix - ./hosts/uconsole-cm5/hardware-configuration.nix - ]; - }; + in { + nixosConfigurations = { + lazyworkhorse = nixpkgs.lib.nixosSystem { + specialArgs = { inherit system self keys paths inputs; }; + modules = [ + { + nixpkgs.overlays = overlays; + nixpkgs.config.allowUnfree = true; + nixpkgs.config.rocmSupport = true; + nixpkgs.config.permittedInsecurePackages = [ "openclaw-2026.3.12" ]; + nix.package = lix.packages.${system}.default; + } + agenix.nixosModules.default + ./hosts/lazyworkhorse/configuration.nix + ./hosts/lazyworkhorse/hardware-configuration.nix + ./modules/nixos/filesystem/hoardingcow-mount.nix + ./modules/nixos/services/docker_manager.nix + ./modules/nixos/services/open_code_server.nix + ./modules/nixos/services/ollama_init_custom_models.nix + ./modules/nixos/services/openclaw_node.nix + ./modules/nixos/security/ai-worker-restricted.nix + ./users/gortium.nix + ./users/ai-worker.nix + ]; }; - devShells.${system}.default = devShell; - packages.${system} = { - # Image SD flashable pour uConsole CM5 (SSH + WiFi + clés) - # Usage : dd if=result of=/dev/sda bs=4M status=progress conv=fsync - uconsole-cm5-image = (nixos-raspberrypi.lib.nixosSystem { - system = "aarch64-linux"; - specialArgs = { - inherit self keys inputs; - nixos-raspberrypi = nixos-raspberrypi; - isCM4 = false; - }; - modules = [ - { - nixpkgs.buildPlatform = system; - nixpkgs.hostPlatform = "aarch64-linux"; - } - nixos-raspberrypi.nixosModules.nixpkgs-rpi - nixos-raspberrypi.nixosModules.raspberry-pi-5.base - nixos-raspberrypi.lib.inject-overlays-global - nixos-raspberrypi.nixosModules.sd-image - nixos-uconsole.nixosModules.kernel - (nixos-uconsole.nixosModules.cm { lib = nixpkgs-uconsole.lib; isCM4 = false; }) - nixos-uconsole.nixosModules.base - agenix.nixosModules.default - ./hosts/uconsole-cm5/configuration.nix - ]; - }).config.system.build.sdImage; + + cyt-pi = nixpkgs.lib.nixosSystem { + specialArgs = { inherit self keys paths inputs; }; + modules = [ + { + nixpkgs.overlays = overlays; + nixpkgs.config.allowUnfree = true; + nixpkgs.hostPlatform = "aarch64-linux"; + nix.package = lix.packages."aarch64-linux".default; + } + ./hosts/cyt-pi/configuration.nix + ./hosts/cyt-pi/hardware-configuration.nix + ]; + }; + + uconsole-cm5 = nixpkgs-uconsole.lib.nixosSystem { + system = "aarch64-linux"; + specialArgs = { + inherit self keys paths inputs; + nixos-raspberrypi = nixos-raspberrypi; + isCM4 = false; + }; + modules = [ + { + nixpkgs.buildPlatform = "x86_64-linux"; + nixpkgs.hostPlatform = "aarch64-linux"; + nixpkgs.config.allowUnfree = true; + boot.loader.raspberry-pi.bootloader = "kernel"; + } + nixos-raspberrypi.nixosModules.nixpkgs-rpi +# Patches are now in gortium/nixos-uconsole fork (cm5_fix branch) + nixos-raspberrypi.nixosModules.raspberry-pi-5.base + nixos-raspberrypi.lib.inject-overlays + nixos-raspberrypi.lib.inject-overlays-global + nixos-uconsole.nixosModules.uconsole-cm5 + ({ config, lib, pkgs, inputs, ... }: let + lix-cross = import inputs.nixpkgs-uconsole { + localSystem = { system = "x86_64-linux"; }; + crossSystem = { system = "aarch64-linux"; }; + overlays = [ inputs.lix.overlays.default ]; + }; + in { nix.package = lix-cross.lix; }) + agenix.nixosModules.default + ./hosts/uconsole-cm5/configuration.nix + ./hosts/uconsole-cm5/hardware-configuration.nix + ]; }; }; + + devShells.${system}.default = devShell; + + packages.${system} = { + uconsole-cm5-image = (nixos-raspberrypi.lib.nixosSystem { + system = "aarch64-linux"; + specialArgs = { + inherit self keys inputs; + nixos-raspberrypi = nixos-raspberrypi; + isCM4 = false; + }; + modules = [ + { + nixpkgs.buildPlatform = system; + nixpkgs.hostPlatform = "aarch64-linux"; + } + nixos-raspberrypi.nixosModules.nixpkgs-rpi + nixos-raspberrypi.nixosModules.raspberry-pi-5.base + nixos-raspberrypi.lib.inject-overlays-global + nixos-raspberrypi.nixosModules.sd-image + nixos-uconsole.nixosModules.uconsole-cm5 + agenix.nixosModules.default + ./hosts/uconsole-cm5/configuration.nix + ]; + }).config.system.build.sdImage; + }; + }; } -- 2.49.1 From 4610a0807274870b512e0a761dd04f8a29051a3c Mon Sep 17 00:00:00 2001 From: Hermes Date: Sat, 13 Jun 2026 23:25:47 -0400 Subject: [PATCH 040/157] feat: add Hyprland Wayland compositor from archive/uconsole-cm5-v3 --- hosts/uconsole-cm5/configuration.nix | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index 5a1b679..34ff9a0 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -25,4 +25,10 @@ # Firmware hardware.enableRedistributableFirmware = true; + + # Hyprland Wayland compositor (manual start — no SDDM) + programs.hyprland = { + enable = true; + xwayland.enable = true; + }; } -- 2.49.1 From 86d8b7bf8bb6fae9bb906c3b7f0c63a82ebf08ad Mon Sep 17 00:00:00 2001 From: Thierry Pouplier Date: Sat, 13 Jun 2026 23:45:58 -0400 Subject: [PATCH 041/157] fix: disable libcamera in pipewire for cross-compile (rpi-pisp blocks) --- hosts/uconsole-cm5/configuration.nix | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index 34ff9a0..b48eb04 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -31,4 +31,11 @@ enable = true; xwayland.enable = true; }; + + # Override pipewire to drop libcamera (fixes cross-compile: rpi-pisp subproject blocked) + nixpkgs.overlays = [ + (final: prev: { + pipewire = prev.pipewire.override { libcamera = null; }; + }) + ]; } -- 2.49.1 From f00477dacc5c77e6fca9e7242366807fb9f9225f Mon Sep 17 00:00:00 2001 From: Thierry Pouplier Date: Sun, 14 Jun 2026 00:16:09 -0400 Subject: [PATCH 042/157] fix: force -Dlibcamera=disabled in pipewire mesonFlags for cross-compile --- hosts/uconsole-cm5/configuration.nix | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index b48eb04..c7beb18 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -32,10 +32,12 @@ xwayland.enable = true; }; - # Override pipewire to drop libcamera (fixes cross-compile: rpi-pisp subproject blocked) + # Force-disable libcamera in pipewire's SPA (fixes cross-compile — rpi-pisp subproject blocked) nixpkgs.overlays = [ (final: prev: { - pipewire = prev.pipewire.override { libcamera = null; }; + pipewire = prev.pipewire.overrideAttrs (old: { + mesonFlags = old.mesonFlags ++ [ "-Dlibcamera=disabled" ]; + }); }) ]; } -- 2.49.1 From 9978ea36f4e4c28ac15cd319fdcf9a03caeb82a7 Mon Sep 17 00:00:00 2001 From: Thierry Pouplier Date: Sun, 14 Jun 2026 00:56:31 -0400 Subject: [PATCH 043/157] fix: disable libcamera in pipewire via mesonFlags for both pkgs and rpi --- flake.lock | 126 ++++++++++++++++++++++++++- flake.nix | 19 ++++ hosts/uconsole-cm5/configuration.nix | 9 +- 3 files changed, 145 insertions(+), 9 deletions(-) diff --git a/flake.lock b/flake.lock index e78ed64..a79a68f 100644 --- a/flake.lock +++ b/flake.lock @@ -23,6 +23,22 @@ "type": "github" } }, + "argononed": { + "flake": false, + "locked": { + "lastModified": 1729566243, + "narHash": "sha256-DPNI0Dpk5aym3Baf5UbEe5GENDrSmmXVdriRSWE+rgk=", + "owner": "nvmd", + "repo": "argononed", + "rev": "16dbee54d49b66d5654d228d1061246b440ef7cf", + "type": "github" + }, + "original": { + "owner": "nvmd", + "repo": "argononed", + "type": "github" + } + }, "flake-compat": { "flake": false, "locked": { @@ -37,6 +53,21 @@ "url": "https://git.lix.systems/lix-project/flake-compat/archive/main.tar.gz" } }, + "flake-compat_2": { + "locked": { + "lastModified": 1767039857, + "narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, "home-manager": { "inputs": { "nixpkgs": [ @@ -144,6 +175,80 @@ "type": "github" } }, + "nixos-images": { + "inputs": { + "nixos-stable": [ + "nixos-raspberrypi", + "nixpkgs" + ], + "nixos-unstable": [ + "nixos-raspberrypi", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1747747741, + "narHash": "sha256-LUOH27unNWbGTvZFitHonraNx0JF/55h30r9WxqrznM=", + "owner": "nvmd", + "repo": "nixos-images", + "rev": "cbbd6db325775096680b65e2a32fb6187c09bbb4", + "type": "github" + }, + "original": { + "owner": "nvmd", + "ref": "sdimage-installer", + "repo": "nixos-images", + "type": "github" + } + }, + "nixos-raspberrypi": { + "inputs": { + "argononed": "argononed", + "flake-compat": "flake-compat_2", + "nixos-images": "nixos-images", + "nixpkgs": [ + "nixpkgs-uconsole" + ] + }, + "locked": { + "lastModified": 1781324200, + "narHash": "sha256-JWqxN2Yle86+4Q+GFh12SvB92ZyLeqalVsN9lfMh6eQ=", + "owner": "gortium", + "repo": "nixos-raspberrypi", + "rev": "721a6e9e67dca3a23133db650b87018646bca3e6", + "type": "github" + }, + "original": { + "owner": "gortium", + "ref": "cm5-cross-v1", + "repo": "nixos-raspberrypi", + "type": "github" + } + }, + "nixos-uconsole": { + "inputs": { + "nixos-raspberrypi": [ + "nixos-raspberrypi" + ], + "nixpkgs": [ + "nixpkgs-uconsole" + ] + }, + "locked": { + "lastModified": 1781406889, + "narHash": "sha256-cUD2zvOgHMMjIn4wd4dvpW2GZtCFWtUS+7CPrzQwpPA=", + "owner": "gortium", + "repo": "nixos-uconsole", + "rev": "b556f9315358dbd53bf868cc24e5872ee15763d8", + "type": "github" + }, + "original": { + "owner": "gortium", + "ref": "cm5_fix", + "repo": "nixos-uconsole", + "type": "github" + } + }, "nixpkgs": { "locked": { "lastModified": 1705033721, @@ -176,6 +281,22 @@ "type": "github" } }, + "nixpkgs-uconsole": { + "locked": { + "lastModified": 1780952837, + "narHash": "sha256-Fwd1+spDtQ0hDyBwme6ufG3n4mY0UrjjFdYHv+G/Hds=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "e820eb4a444b46a19b2e03e8dfd2359439ff30fe", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-25.11", + "repo": "nixpkgs", + "type": "github" + } + }, "nixpkgs_2": { "locked": { "lastModified": 1774386573, @@ -212,7 +333,10 @@ "inputs": { "agenix": "agenix", "lix": "lix", - "nixpkgs": "nixpkgs_2" + "nixos-raspberrypi": "nixos-raspberrypi", + "nixos-uconsole": "nixos-uconsole", + "nixpkgs": "nixpkgs_2", + "nixpkgs-uconsole": "nixpkgs-uconsole" } }, "systems": { diff --git a/flake.nix b/flake.nix index 5bde76e..a7c321e 100644 --- a/flake.nix +++ b/flake.nix @@ -99,8 +99,27 @@ nixpkgs.hostPlatform = "aarch64-linux"; nixpkgs.config.allowUnfree = true; boot.loader.raspberry-pi.bootloader = "kernel"; + # Kill camera packages — not needed on uConsole, break cross-compile + nixpkgs.overlays = [ + (final: prev: { + pipewire = prev.pipewire.overrideAttrs (old: { + mesonFlags = old.mesonFlags ++ [ "-Dlibcamera=disabled" ]; + }); + }) + ]; } nixos-raspberrypi.nixosModules.nixpkgs-rpi + # Disable libcamera in rpi pipewire too (separate nixpkgs instance) + ({ config, lib, pkgs, ... }: { + nixpkgs.overlays = [ + (final: prev: { + pipewire = prev.pipewire.overrideAttrs (old: { + mesonFlags = old.mesonFlags ++ [ "-Dlibcamera=disabled" ]; + }); + }) + ]; + }) + # Patches are now in gortium/nixos-uconsole fork (cm5_fix branch) nixos-raspberrypi.nixosModules.raspberry-pi-5.base nixos-raspberrypi.lib.inject-overlays diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index c7beb18..5ac7b1b 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -32,12 +32,5 @@ xwayland.enable = true; }; - # Force-disable libcamera in pipewire's SPA (fixes cross-compile — rpi-pisp subproject blocked) - nixpkgs.overlays = [ - (final: prev: { - pipewire = prev.pipewire.overrideAttrs (old: { - mesonFlags = old.mesonFlags ++ [ "-Dlibcamera=disabled" ]; - }); - }) - ]; + } -- 2.49.1 From 6a1c26cac26afd84e1d62319a920362ad01cd604 Mon Sep 17 00:00:00 2001 From: Thierry Pouplier Date: Sun, 14 Jun 2026 09:03:44 -0400 Subject: [PATCH 044/157] fix: remove libcamera from pipewire buildInputs (both overlays) meta.platforms = [] on libcamera doesn't help because nixos-25.11 pipewire has libcamera unconditionally in buildInputs. Must overrideAttrs to: - filter libcamera out of buildInputs - clear existing libcamera meson flags and set -Dlibcamera=disabled --- flake.nix | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/flake.nix b/flake.nix index a7c321e..9db440d 100644 --- a/flake.nix +++ b/flake.nix @@ -101,9 +101,20 @@ boot.loader.raspberry-pi.bootloader = "kernel"; # Kill camera packages — not needed on uConsole, break cross-compile nixpkgs.overlays = [ + # Make camera packages "unavailable" so no pkgs depend on them (final: prev: { + libcamera = prev.libcamera.overrideAttrs (_: { meta.platforms = []; }); + libcamera-rpi = prev.libcamera-rpi.overrideAttrs (_: { meta.platforms = []; }); + libpisp = prev.libpisp.overrideAttrs (_: { meta.platforms = []; }); + # Pipewire in nixos-25.11 has libcamera unconditionally in buildInputs; + # meta.platforms trick doesn't help — must actually remove it pipewire = prev.pipewire.overrideAttrs (old: { - mesonFlags = old.mesonFlags ++ [ "-Dlibcamera=disabled" ]; + buildInputs = builtins.filter + (x: !(x?pname && x.pname == "libcamera")) + (old.buildInputs or []); + mesonFlags = builtins.filter + (flag: !(builtins.isString flag && builtins.match ".*libcamera.*" flag != null)) + (old.mesonFlags or []) ++ [ "-Dlibcamera=disabled" ]; }); }) ]; @@ -114,7 +125,12 @@ nixpkgs.overlays = [ (final: prev: { pipewire = prev.pipewire.overrideAttrs (old: { - mesonFlags = old.mesonFlags ++ [ "-Dlibcamera=disabled" ]; + buildInputs = builtins.filter + (x: !(x?pname && x.pname == "libcamera")) + (old.buildInputs or []); + mesonFlags = builtins.filter + (flag: !(builtins.isString flag && builtins.match ".*libcamera.*" flag != null)) + (old.mesonFlags or []) ++ [ "-Dlibcamera=disabled" ]; }); }) ]; -- 2.49.1 From 11a49690285e83022ca83a3ea2bdad76df5ebb4c Mon Sep 17 00:00:00 2001 From: Thierry Pouplier Date: Sun, 14 Jun 2026 09:30:50 -0400 Subject: [PATCH 045/157] fix: skip GTK tests in gjs cross-compile for Hyprland --- flake.nix | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/flake.nix b/flake.nix index 9db440d..4c81fd9 100644 --- a/flake.nix +++ b/flake.nix @@ -116,6 +116,10 @@ (flag: !(builtins.isString flag && builtins.match ".*libcamera.*" flag != null)) (old.mesonFlags or []) ++ [ "-Dlibcamera=disabled" ]; }); + # gjs cross-compile fails without GTK; skip intro tests + gjs = prev.gjs.overrideAttrs (old: { + mesonFlags = (old.mesonFlags or []) ++ [ "-Dskip_gtk_tests=true" ]; + }); }) ]; } -- 2.49.1 From 0372b37950d30c5756989ad20ade695d94fe5882 Mon Sep 17 00:00:00 2001 From: Thierry Pouplier Date: Sun, 14 Jun 2026 09:52:35 -0400 Subject: [PATCH 046/157] fix: set Qt6Qml_DIR for hyprland-qt-support cross-compile --- flake.nix | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/flake.nix b/flake.nix index 4c81fd9..3c11c22 100644 --- a/flake.nix +++ b/flake.nix @@ -120,6 +120,12 @@ gjs = prev.gjs.overrideAttrs (old: { mesonFlags = (old.mesonFlags or []) ++ [ "-Dskip_gtk_tests=true" ]; }); + # hyprland-qt-support: Qt6Qml cross-compile path mismatch + hyprland-qt-support = prev.hyprland-qt-support.overrideAttrs (old: { + cmakeFlags = (old.cmakeFlags or []) ++ [ + "-DQt6Qml_DIR=${prev.qtdeclarative.dev}/lib/cmake/Qt6Qml" + ]; + }); }) ]; } -- 2.49.1 From 8afca7315db85c02ef864406ebb7ae2fdba1ae9b Mon Sep 17 00:00:00 2001 From: Thierry Pouplier Date: Sun, 14 Jun 2026 09:56:31 -0400 Subject: [PATCH 047/157] fix: correct qtdeclarative attr to qt6.qtdeclarative --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 3c11c22..f1dcd6e 100644 --- a/flake.nix +++ b/flake.nix @@ -123,7 +123,7 @@ # hyprland-qt-support: Qt6Qml cross-compile path mismatch hyprland-qt-support = prev.hyprland-qt-support.overrideAttrs (old: { cmakeFlags = (old.cmakeFlags or []) ++ [ - "-DQt6Qml_DIR=${prev.qtdeclarative.dev}/lib/cmake/Qt6Qml" + "-DQt6Qml_DIR=${prev.qt6.qtdeclarative}/lib/cmake/Qt6Qml" ]; }); }) -- 2.49.1 From 2476352fdfcbcb686f6331b2a304ea5df464d8ac Mon Sep 17 00:00:00 2001 From: Thierry Pouplier Date: Sun, 14 Jun 2026 10:01:28 -0400 Subject: [PATCH 048/157] fix: skip hyprland qtutils (Qt6Quick missing in aarch64 cross-compile) Qt6Quick and its submodules are not built in the aarch64 qtdeclarative cross-compile output. hyprland-qt-support can't find them and fails. Hyprland only needs qtutils at runtime (added to PATH via wrapProgram). Setting wrapRuntimeDeps = false skips the wrapping entirely, letting Hyprland build without its QML UI support package. --- flake.nix | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/flake.nix b/flake.nix index f1dcd6e..fd20634 100644 --- a/flake.nix +++ b/flake.nix @@ -120,12 +120,9 @@ gjs = prev.gjs.overrideAttrs (old: { mesonFlags = (old.mesonFlags or []) ++ [ "-Dskip_gtk_tests=true" ]; }); - # hyprland-qt-support: Qt6Qml cross-compile path mismatch - hyprland-qt-support = prev.hyprland-qt-support.overrideAttrs (old: { - cmakeFlags = (old.cmakeFlags or []) ++ [ - "-DQt6Qml_DIR=${prev.qt6.qtdeclarative}/lib/cmake/Qt6Qml" - ]; - }); + # Qt6Quick missing from aarch64 qtdeclarative cross-compile; + # skip qtutils runtime deps — Hyprland only needs it for QML UI + hyprland = prev.hyprland.override { wrapRuntimeDeps = false; }; }) ]; } -- 2.49.1 From 42202c8a40d404354be890d9a2756f5e5611c8cb Mon Sep 17 00:00:00 2001 From: Thierry Pouplier Date: Sun, 14 Jun 2026 10:11:44 -0400 Subject: [PATCH 049/157] fix: add hyprwayland-scanner native paths for xdg-desktop-portal-hyprland cross-compile --- flake.nix | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/flake.nix b/flake.nix index fd20634..d0c4bad 100644 --- a/flake.nix +++ b/flake.nix @@ -123,6 +123,14 @@ # Qt6Quick missing from aarch64 qtdeclarative cross-compile; # skip qtutils runtime deps — Hyprland only needs it for QML UI hyprland = prev.hyprland.override { wrapRuntimeDeps = false; }; + # hyprwayland-scanner not found by cross pkg-config wrapper + xdg-desktop-portal-hyprland = prev.xdg-desktop-portal-hyprland.overrideAttrs (old: { + preConfigure = (old.preConfigure or "") + '' + # Point cmake to the correct hyprwayland-scanner pkgconfig + cmakeFlags="$cmakeFlags -Dhyprwayland-scanner_DIR=${prev.buildPackages.hyprwayland-scanner}/lib/cmake/hyprwayland-scanner" 2>/dev/null || true + export PKG_CONFIG_PATH="${prev.buildPackages.hyprwayland-scanner}/lib/pkgconfig:$PKG_CONFIG_PATH" + ''; + }); }) ]; } -- 2.49.1 From 2ee616839e1ccb33dc5d34937864e6b084eb26d5 Mon Sep 17 00:00:00 2001 From: Thierry Pouplier Date: Sun, 14 Jun 2026 18:43:04 -0400 Subject: [PATCH 050/157] chore: point nixos-uconsole input to pr/dcs-panel-detection branch --- flake.lock | 8 ++++---- flake.nix | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/flake.lock b/flake.lock index a79a68f..2f54d5c 100644 --- a/flake.lock +++ b/flake.lock @@ -235,16 +235,16 @@ ] }, "locked": { - "lastModified": 1781406889, - "narHash": "sha256-cUD2zvOgHMMjIn4wd4dvpW2GZtCFWtUS+7CPrzQwpPA=", + "lastModified": 1781476310, + "narHash": "sha256-jY6ujqLXNAWJGvt+pAuw1Wg/OiHRGd1B1Z7Czhiq7Q4=", "owner": "gortium", "repo": "nixos-uconsole", - "rev": "b556f9315358dbd53bf868cc24e5872ee15763d8", + "rev": "38a7fcbffbf2d2e122bc1e1c634fe25f66ecda13", "type": "github" }, "original": { "owner": "gortium", - "ref": "cm5_fix", + "ref": "pr/dcs-panel-detection", "repo": "nixos-uconsole", "type": "github" } diff --git a/flake.nix b/flake.nix index d0c4bad..15b5b9f 100644 --- a/flake.nix +++ b/flake.nix @@ -14,7 +14,7 @@ }; nixpkgs-uconsole.url = "github:NixOS/nixpkgs/nixos-25.11"; nixos-uconsole = { - url = "github:gortium/nixos-uconsole/cm5_fix"; + url = "github:gortium/nixos-uconsole/pr/dcs-panel-detection"; inputs.nixpkgs.follows = "nixpkgs-uconsole"; inputs.nixos-raspberrypi.follows = "nixos-raspberrypi"; }; @@ -151,7 +151,7 @@ ]; }) -# Patches are now in gortium/nixos-uconsole fork (cm5_fix branch) +# Patches are now in gortium/nixos-uconsole fork (pr/dcs-panel-detection branch) nixos-raspberrypi.nixosModules.raspberry-pi-5.base nixos-raspberrypi.lib.inject-overlays nixos-raspberrypi.lib.inject-overlays-global -- 2.49.1 From ce7f74c66f2f3b0f2af9cf6590adce55bf48dc64 Mon Sep 17 00:00:00 2001 From: Thierry Pouplier Date: Sun, 14 Jun 2026 18:58:35 -0400 Subject: [PATCH 051/157] remove hyperspace files accidentally committed from feat/hyperspace-pods-module These files were mixed into commit 16acc6a which was intended to only fix SSH options for the uConsole configuration. --- hosts/lazyworkhorse/hyperspace-commit-msg.txt | 12 -- hosts/lazyworkhorse/hyperspace.nix | 134 ------------------ 2 files changed, 146 deletions(-) delete mode 100755 hosts/lazyworkhorse/hyperspace-commit-msg.txt delete mode 100755 hosts/lazyworkhorse/hyperspace.nix diff --git a/hosts/lazyworkhorse/hyperspace-commit-msg.txt b/hosts/lazyworkhorse/hyperspace-commit-msg.txt deleted file mode 100755 index 6916f2e..0000000 --- a/hosts/lazyworkhorse/hyperspace-commit-msg.txt +++ /dev/null @@ -1,12 +0,0 @@ -feat: add Hyperspace Pods NixOS module - -Create modules/nixos/services/hyperspace.nix for the Hyperspace Pods -P2P AI cluster agent. Registered in flake.nix under lazyworkhorse. - -- Fetches CLI binary v5.45.30 via fetchurl with SRI hash verification -- Systemd system service: auto profile, configurable api port 8080, - ai-worker user, GPU device access (kfd+dri), SupplementaryGroups - for video+render groups, service hardening -- Firewall: TCP 4001 libp2p, 30301 chain, 8080 API; UDP 4001 libp2p -- AMD MI50 ROCm via HSA_OVERRIDE_GFX_VERSION=9.0.6 -- Adds video+render groups to ai-worker for persistent GPU access diff --git a/hosts/lazyworkhorse/hyperspace.nix b/hosts/lazyworkhorse/hyperspace.nix deleted file mode 100755 index 0c2a39f..0000000 --- a/hosts/lazyworkhorse/hyperspace.nix +++ /dev/null @@ -1,134 +0,0 @@ -{ config, lib, pkgs, ... }: - -let - cfg = config.services.hyperspace; - - hyperspacePkg = pkgs.stdenv.mkDerivation { - name = "hyperspace-pods-${cfg.version}"; - src = pkgs.fetchurl { - url = "https://github.com/hyperspaceai/aios-cli/releases/download/v${cfg.version}/aios-cli-x86_64-unknown-linux-gnu.tar.gz"; - hash = cfg.packageHash; - }; - sourceRoot = "."; - installPhase = '' - mkdir -p $out/libexec $out/bin - cp -r * $out/libexec/ - chmod +x $out/libexec/aios-cli - ln -s $out/libexec/aios-cli $out/bin/hyperspace - ''; - }; -in { - options.services.hyperspace = { - enable = lib.mkEnableOption "Hyperspace Pods P2P AI cluster agent"; - - version = lib.mkOption { - type = lib.types.str; - default = "5.45.30"; - description = "Hyperspace CLI version to download."; - }; - - packageHash = lib.mkOption { - type = lib.types.str; - default = "sha256-f6fJ8t3exqtYwUD5j+WvD+Hm0oN/Eef0X+R9Rj23dE0="; - description = '' - SRI hash of the hyperspace release tarball (sha256-). - Must be updated when version changes. Generate with: - nix store prefetch-file --hash-algo sha256 \\ - https://github.com/hyperspaceai/aios-cli/releases/download/v{version}/aios-cli-x86_64-unknown-linux-gnu.tar.gz - ''; - }; - - user = lib.mkOption { - type = lib.types.str; - default = "ai-worker"; - description = "System user to run the Hyperspace agent."; - }; - - apiPort = lib.mkOption { - type = lib.types.port; - default = 8080; - description = "OpenAI-compatible API port (configurable via --api-port)."; - }; - - profile = lib.mkOption { - type = lib.types.str; - default = "auto"; - description = '' - Agent profile. Options: auto (auto-detect hardware), full (all capabilities), - inference (GPU inference only), embedding (CPU embedding only), - relay (lightweight relay), storage (storage + memory). - ''; - }; - - autoStart = lib.mkOption { - type = lib.types.bool; - default = true; - description = "Start the agent automatically on boot."; - }; - - openFirewall = lib.mkOption { - type = lib.types.bool; - default = true; - description = "Open P2P mesh (4001 TCP+UDP, 30301 TCP) and API port in the firewall."; - }; - - extraArgs = lib.mkOption { - type = lib.types.listOf lib.types.str; - default = [ ]; - description = "Extra arguments to pass to 'hyperspace start'."; - }; - }; - - config = lib.mkIf cfg.enable { - systemd.services.hyperspace = { - description = "Hyperspace Pods P2P AI Cluster Agent"; - after = [ "network.target" "network-online.target" ]; - wants = [ "network-online.target" ]; - wantedBy = lib.mkIf cfg.autoStart [ "multi-user.target" ]; - - path = with pkgs; [ bash coreutils ]; - - serviceConfig = { - Type = "simple"; - User = cfg.user; - Group = cfg.user; - WorkingDirectory = "${hyperspacePkg}/libexec"; - ExecStart = "${hyperspacePkg}/bin/hyperspace start --profile ${cfg.profile} --api-port ${toString cfg.apiPort} ${lib.escapeShellArgs cfg.extraArgs}"; - Restart = "on-failure"; - RestartSec = 5; - - # AMD MI50 (ROCm) device access - DeviceAllow = [ "/dev/kfd rw" "/dev/dri rw" ]; - - # Supplementary groups for GPU/accelerator access - SupplementaryGroups = [ "video" "render" ]; - - # Hardening - NoNewPrivileges = true; - ProtectHome = "tmpfs"; - ProtectSystem = "strict"; - PrivateTmp = true; - PrivateDevices = false; # Needs /dev/kfd and /dev/dri - }; - - environment = { - HSA_OVERRIDE_GFX_VERSION = "9.0.6"; - HOME = "/home/${cfg.user}"; - }; - }; - - # Firewall ports for P2P mesh (libp2p 4001, chain 30301) and API - networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall [ 4001 30301 cfg.apiPort ]; - networking.firewall.allowedUDPPorts = lib.mkIf cfg.openFirewall [ 4001 ]; - - # Add GPU/accelerator groups to the service user (persistent beyond service restarts) - users.users = lib.mkIf (cfg.user == "ai-worker") { - ai-worker = { - extraGroups = [ "video" "render" ]; - }; - }; - - # ROCm override for AMD MI50 (gfx906) compatibility - environment.variables.HSA_OVERRIDE_GFX_VERSION = "9.0.6"; - }; -} -- 2.49.1 From 02ffcdb55ec95d2ef3e15dc802378026fdfe8589 Mon Sep 17 00:00:00 2001 From: Thierry Pouplier Date: Sun, 14 Jun 2026 19:22:27 -0400 Subject: [PATCH 052/157] feat: add dotfiles submodule and home-manager config - Add dotfiles repo as submodule in assets/dotfiles/ - Rewrite home.nix with direct file references instead of stow service - Remove old custom dotfiles.nix service (replaced by home-manager) - Clean up services/default.nix import --- .gitmodules | 1 + assets/dotfiles | 1 + modules/nixos/services/default.nix | 1 - modules/nixos/services/dotfiles.nix | 69 ----------------------------- users/gortium/home.nix | 65 ++++++++++++++++++++++++--- 5 files changed, 60 insertions(+), 77 deletions(-) create mode 160000 assets/dotfiles delete mode 100644 modules/nixos/services/dotfiles.nix diff --git a/.gitmodules b/.gitmodules index 684b242..66f7a80 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,4 @@ [submodule "assets/dotfiles"] path = assets/dotfiles url = ssh://git@code.lazyworkhorse.net:2222/gortium/dotfiles.git + branch = master diff --git a/assets/dotfiles b/assets/dotfiles new file mode 160000 index 0000000..8e9204b --- /dev/null +++ b/assets/dotfiles @@ -0,0 +1 @@ +Subproject commit 8e9204bc21c488f3c7a1e60f238bce8c2e4abb06 diff --git a/modules/nixos/services/default.nix b/modules/nixos/services/default.nix index c0d569a..f741778 100644 --- a/modules/nixos/services/default.nix +++ b/modules/nixos/services/default.nix @@ -1,6 +1,5 @@ { imports = [ - ./dotfiles.nix ./systemd ]; } diff --git a/modules/nixos/services/dotfiles.nix b/modules/nixos/services/dotfiles.nix deleted file mode 100644 index b05fbe0..0000000 --- a/modules/nixos/services/dotfiles.nix +++ /dev/null @@ -1,69 +0,0 @@ -{ config, lib, pkgs, ... }: - -with lib; - -let - cfg = config.services.dotfiles; - stowDir = cfg.stowDir; - - # Function to recursively find all files in a directory - findFiles = dir: - let - files = builtins.attrNames (builtins.readDir dir); - in - concatMap (name: - let - path = dir + "/${name}"; - in - if (builtins.typeOf (builtins.readDir path) == "set") - then findFiles path - else [ path ] - ) files; - - # Get a list of all packages (directories) in the stow directory - stowPackages = builtins.attrNames (builtins.readDir stowDir); - - # Create an attribute set where each attribute is a package name - # and the value is a list of files to be linked. - homeManagerLinks = listToAttrs (map (pkg: - let - pkgPath = stowDir + "/${pkg}"; - files = findFiles pkgPath; - in - nameValuePair pkg (map (file: { - source = file; - target = removePrefix (pkgPath + "/") file; - }) files) - ) stowPackages); - -in -{ - options.services.dotfiles = { - enable = mkEnableOption "Enable dotfiles management"; - - stowDir = mkOption { - type = types.path; - description = "The directory where your stow packages are located."; - }; - - user = mkOption { - type = types.str; - description = "The user to manage dotfiles for."; - }; - }; - - config = mkIf cfg.enable { - home-manager.users.${cfg.user} = { - home.file = - let - allFiles = concatLists (attrValues homeManagerLinks); - in - listToAttrs (map (file: - nameValuePair file.target { - source = file.source; - } - ) allFiles); - }; - }; -} - diff --git a/users/gortium/home.nix b/users/gortium/home.nix index 608f95f..affc2e7 100644 --- a/users/gortium/home.nix +++ b/users/gortium/home.nix @@ -1,12 +1,63 @@ -{ pkgs, ... }: { - services.dotfiles = { - enable = true; - stowDir = ../../../assets/dotfiles; - user = "gortium"; - }; +{ pkgs, lib, config, inputs, ... }: +let + dotfiles = ./assets/dotfiles; +in { home.username = "gortium"; home.homeDirectory = "/home/gortium"; - home.stateVersion = "23.11"; # Please change this to your version. + home.stateVersion = "23.11"; programs.home-manager.enable = true; + + home.file = { + # zsh + ".zshrc".source = "${dotfiles}/zsh/.zshrc"; + + # tmux + ".tmux.conf".source = "${dotfiles}/tmux/.tmux.conf"; + + # kitty + ".config/kitty/kitty.conf".source = "${dotfiles}/kitty/.config/kitty/kitty.conf"; + + # nvim + ".config/nvim/init.lua".source = "${dotfiles}/nvim/.config/nvim/init.lua"; + + # starship + ".config/starship.toml".source = "${dotfiles}/starship/.config/starship.toml"; + + # btop + ".config/btop/btop.conf".source = "${dotfiles}/btop/.config/btop/btop.conf"; + + # waybar + ".config/waybar/style.css".source = "${dotfiles}/waybar/.config/waybar/style.css"; + ".config/waybar/config.jsonc".source = "${dotfiles}/waybar/.config/waybar/config.jsonc"; + + # wofi + ".config/wofi/style.css".source = "${dotfiles}/wofi/.config/wofi/style.css"; + ".config/wofi/config".source = "${dotfiles}/wofi/.config/wofi/config"; + + # yazi + ".config/yazi/yazi.toml".source = "${dotfiles}/yazi/.config/yazi/yazi.toml"; + + # hyprland + ".config/hypr/hyprland.conf".source = "${dotfiles}/hypr/.config/hypr/hyprland.conf"; + + # doom emacs + ".config/doom/config.el".source = "${dotfiles}/doom/.config/doom/config.el"; + ".config/doom/init.el".source = "${dotfiles}/doom/.config/doom/init.el"; + ".config/doom/packages.el".source = "${dotfiles}/doom/.config/doom/packages.el"; + }; + + home.packages = with pkgs; [ + # core + git zsh tmux starship + # editors + neovim kitty + # tools + btop yazi ripgrep fd fzf + # wayland + waybar wofi + ]; + + programs.zsh.enable = true; + programs.starship.enable = true; } -- 2.49.1 From f344739b94754966a2a82cb0d2c104d6ebcadcc4 Mon Sep 17 00:00:00 2001 From: Thierry Pouplier Date: Sun, 14 Jun 2026 19:37:14 -0400 Subject: [PATCH 053/157] feat: per-host Hyprland monitor config via home-manager - Split hyprland.conf into common (keybinds, looks, animations) and per-host (monitors, env, workspaces) configs - Add uconsole.conf for CM5 DSI display (720x1280) - Add laptop.conf for NVIDIA + external monitors - home.nix links the correct host config based on hostname - Remove NVIDIA env vars from common config --- result | 1 + result-uconsole | 1 + users/gortium/home.nix | 25 +++++++++++++++---------- 3 files changed, 17 insertions(+), 10 deletions(-) create mode 120000 result create mode 120000 result-uconsole diff --git a/result b/result new file mode 120000 index 0000000..c445871 --- /dev/null +++ b/result @@ -0,0 +1 @@ +/nix/store/z86r4awsbrc5q9qhwwi757wxixcqgn31-nixos-system-uConsole-25.11.20260608.e820eb4 \ No newline at end of file diff --git a/result-uconsole b/result-uconsole new file mode 120000 index 0000000..e5d8532 --- /dev/null +++ b/result-uconsole @@ -0,0 +1 @@ +/nix/store/7y7rfksqcf5smz59jjixyl56bxq50j9g-nixos-system-uConsole-25.11.20260608.e820eb4 \ No newline at end of file diff --git a/users/gortium/home.nix b/users/gortium/home.nix index affc2e7..5b3383c 100644 --- a/users/gortium/home.nix +++ b/users/gortium/home.nix @@ -2,6 +2,7 @@ let dotfiles = ./assets/dotfiles; + isUconsole = config.networking.hostName == "uConsole"; in { home.username = "gortium"; home.homeDirectory = "/home/gortium"; @@ -38,24 +39,28 @@ in { # yazi ".config/yazi/yazi.toml".source = "${dotfiles}/yazi/.config/yazi/yazi.toml"; - # hyprland + # hyprland — common config ".config/hypr/hyprland.conf".source = "${dotfiles}/hypr/.config/hypr/hyprland.conf"; + ".config/hypr/hypridle.conf".source = "${dotfiles}/hypr/.config/hypr/hypridle.conf"; + ".config/hypr/hyprlock.conf".source = "${dotfiles}/hypr/.config/hypr/hyprlock.conf"; + ".config/hypr/hyprpaper.conf".source = "${dotfiles}/hypr/.config/hypr/hyprpaper.conf"; + ".config/hypr/mocha.conf".source = "${dotfiles}/hypr/.config/hypr/mocha.conf"; - # doom emacs - ".config/doom/config.el".source = "${dotfiles}/doom/.config/doom/config.el"; - ".config/doom/init.el".source = "${dotfiles}/doom/.config/doom/init.el"; - ".config/doom/packages.el".source = "${dotfiles}/doom/.config/doom/packages.el"; + # hyprland — host-specific monitor config + ".config/hypr/host/monitors.conf".source = + if isUconsole + then "${dotfiles}/hypr/.config/hypr/host/uconsole.conf" + else "${dotfiles}/hypr/.config/hypr/host/laptop.conf"; }; home.packages = with pkgs; [ - # core git zsh tmux starship - # editors neovim kitty - # tools btop yazi ripgrep fd fzf - # wayland - waybar wofi + ] ++ lib.optionals (!isUconsole) [ + waybar wofi swww hyprshot + ] ++ lib.optionals isUconsole [ + brightnessctl ]; programs.zsh.enable = true; -- 2.49.1 From 7238e9d45cb45f577117c03cc1dff93f40e81688 Mon Sep 17 00:00:00 2001 From: Thierry Pouplier Date: Sun, 14 Jun 2026 19:37:35 -0400 Subject: [PATCH 054/157] update dotfiles submodule: per-host hyprland config --- assets/dotfiles | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/dotfiles b/assets/dotfiles index 8e9204b..75df6d5 160000 --- a/assets/dotfiles +++ b/assets/dotfiles @@ -1 +1 @@ -Subproject commit 8e9204bc21c488f3c7a1e60f238bce8c2e4abb06 +Subproject commit 75df6d502a0786e62255eff1c48041c3f21e6a5a -- 2.49.1 From 8423a121eb9008282d74f3c629d7e40da4cd2f4d Mon Sep 17 00:00:00 2001 From: Thierry Pouplier Date: Sun, 14 Jun 2026 19:41:58 -0400 Subject: [PATCH 055/157] rename host/ -> hosts/ in dotfiles submodule --- assets/dotfiles | 2 +- users/gortium/home.nix | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/assets/dotfiles b/assets/dotfiles index 75df6d5..f453874 160000 --- a/assets/dotfiles +++ b/assets/dotfiles @@ -1 +1 @@ -Subproject commit 75df6d502a0786e62255eff1c48041c3f21e6a5a +Subproject commit f45387456b4d1f594e2d623366248ece64f50b25 diff --git a/users/gortium/home.nix b/users/gortium/home.nix index 5b3383c..ce7902f 100644 --- a/users/gortium/home.nix +++ b/users/gortium/home.nix @@ -49,8 +49,8 @@ in { # hyprland — host-specific monitor config ".config/hypr/host/monitors.conf".source = if isUconsole - then "${dotfiles}/hypr/.config/hypr/host/uconsole.conf" - else "${dotfiles}/hypr/.config/hypr/host/laptop.conf"; + then "${dotfiles}/hypr/.config/hypr/hosts/uconsole.conf" + else "${dotfiles}/hypr/.config/hypr/hosts/laptop.conf"; }; home.packages = with pkgs; [ -- 2.49.1 From f06d9028f0a8dca9ea4800c810e40801c6e686a2 Mon Sep 17 00:00:00 2001 From: Thierry Pouplier Date: Sun, 14 Jun 2026 19:52:11 -0400 Subject: [PATCH 056/157] feat: add ai-worker user to uConsole for Hermes SSH access --- hosts/uconsole-cm5/configuration.nix | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index 5ac7b1b..45e4c42 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -34,3 +34,12 @@ } + + # AI worker user (Hermes access) + users.users.ai-worker = { + isNormalUser = false; + shell = pkgs.bash; + openssh.authorizedKeys.keys = with keys; [ + users.ai-worker.main + ]; + }; -- 2.49.1 From 900416389195320bc633f2740aa33ddedfd69772 Mon Sep 17 00:00:00 2001 From: Thierry Pouplier Date: Sun, 14 Jun 2026 19:53:40 -0400 Subject: [PATCH 057/157] feat: add agenix secret for gortium password on uConsole - Add gortium_password.age entry in secrets.nix - Add age.secrets.gortium_password in uConsole config - Add hashedPasswordFile to existing gortium user - Add ai-worker user for Hermes SSH access --- hosts/uconsole-cm5/configuration.nix | 7 +++++++ secrets/secrets.nix | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index 45e4c42..6e879e0 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -43,3 +43,10 @@ users.ai-worker.main ]; }; + + # Age secret for gortium password + age.secrets.gortium_password = { + file = ../secrets/gortium_password.age; + }; + + users.users.gortium.hashedPasswordFile = config.age.secrets.gortium_password.path; diff --git a/secrets/secrets.nix b/secrets/secrets.nix index 612ce18..cf42b6c 100644 --- a/secrets/secrets.nix +++ b/secrets/secrets.nix @@ -8,8 +8,9 @@ let in { "containers.env.age".publicKeys = authorizedKeys; + "gortium_password.age".publicKeys = authorizedKeys; + "home_wifi.age".publicKeys = authorizedKeys; "lazyworkhorse_host_ssh_key.age".publicKeys = authorizedKeys; "n8n_ssh_key.age".publicKeys = authorizedKeys; "openclaw_gateway_token.age".publicKeys = authorizedKeys; - "home_wifi.age".publicKeys = authorizedKeys; } -- 2.49.1 From cdbb7de04d32a3a6f7b7f20574b3176d92c06823 Mon Sep 17 00:00:00 2001 From: Thierry Pouplier Date: Sun, 14 Jun 2026 19:56:33 -0400 Subject: [PATCH 058/157] fix: properly structure uConsole config (ai-worker, gortium password, age secret) --- hosts/uconsole-cm5/configuration.nix | 35 ++++++++++++++-------------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index 6e879e0..477f4b0 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -20,6 +20,23 @@ users.ai-worker.main ]; + # AI worker user (Hermes SSH access) + users.users.ai-worker = { + isNormalUser = false; + shell = pkgs.bash; + openssh.authorizedKeys.keys = with keys; [ + users.ai-worker.main + ]; + }; + + # Age secret for gortium password (file created by user) + age.secrets.gortium_password = { + file = ../secrets/gortium_password.age; + }; + + # Password file for gortium (merges with users/gortium/default.nix) + users.users.gortium.hashedPasswordFile = config.age.secrets.gortium_password.path; + # WiFi via NetworkManager + secret agenix networking.networkmanager.enable = true; @@ -31,22 +48,4 @@ enable = true; xwayland.enable = true; }; - - } - - # AI worker user (Hermes access) - users.users.ai-worker = { - isNormalUser = false; - shell = pkgs.bash; - openssh.authorizedKeys.keys = with keys; [ - users.ai-worker.main - ]; - }; - - # Age secret for gortium password - age.secrets.gortium_password = { - file = ../secrets/gortium_password.age; - }; - - users.users.gortium.hashedPasswordFile = config.age.secrets.gortium_password.path; -- 2.49.1 From eb3fe42542c742b611b1baa742dddc40296623b3 Mon Sep 17 00:00:00 2001 From: Thierry Pouplier Date: Sun, 14 Jun 2026 20:56:17 -0400 Subject: [PATCH 059/157] refactor: extract shared uconsole modules to eliminate toplevel/image duplication --- flake.nix | 155 ++++++++++++++++++++++++------------------------------ 1 file changed, 70 insertions(+), 85 deletions(-) diff --git a/flake.nix b/flake.nix index 15b5b9f..89776dd 100644 --- a/flake.nix +++ b/flake.nix @@ -46,6 +46,74 @@ devShell = import ./shells/nix_dev.nix { inherit pkgs system agenix; }; + + # Cross-compile overlay fixes for Hyprland and deps on aarch64 + uconsoleCrossOverlay = final: prev: { + libcamera = prev.libcamera.overrideAttrs (_: { meta.platforms = []; }); + libcamera-rpi = prev.libcamera-rpi.overrideAttrs (_: { meta.platforms = []; }); + libpisp = prev.libpisp.overrideAttrs (_: { meta.platforms = []; }); + pipewire = prev.pipewire.overrideAttrs (old: { + buildInputs = builtins.filter + (x: !(x?pname && x.pname == "libcamera")) + (old.buildInputs or []); + mesonFlags = builtins.filter + (flag: !(builtins.isString flag && builtins.match ".*libcamera.*" flag != null)) + (old.mesonFlags or []) ++ [ "-Dlibcamera=disabled" ]; + }); + gjs = prev.gjs.overrideAttrs (old: { + mesonFlags = (old.mesonFlags or []) ++ [ "-Dskip_gtk_tests=true" ]; + }); + hyprland = prev.hyprland.override { wrapRuntimeDeps = false; }; + xdg-desktop-portal-hyprland = prev.xdg-desktop-portal-hyprland.overrideAttrs (old: { + preConfigure = (old.preConfigure or "") + '' + cmakeFlags="$cmakeFlags -Dhyprwayland-scanner_DIR=${prev.buildPackages.hyprwayland-scanner}/lib/cmake/hyprwayland-scanner" 2>/dev/null || true + export PKG_CONFIG_PATH="${prev.buildPackages.hyprwayland-scanner}/lib/pkgconfig:$PKG_CONFIG_PATH" + ''; + }); + }; + + # RPI-specific pipewire libcamera fix (separate nixpkgs instance) + uconsoleRpiPipewireOverlay = final: prev: { + pipewire = prev.pipewire.overrideAttrs (old: { + buildInputs = builtins.filter + (x: !(x?pname && x.pname == "libcamera")) + (old.buildInputs or []); + mesonFlags = builtins.filter + (flag: !(builtins.isString flag && builtins.match ".*libcamera.*" flag != null)) + (old.mesonFlags or []) ++ [ "-Dlibcamera=disabled" ]; + }); + }; + + # Shared uConsole CM5 module set — used by both toplevel and SD image + uconsoleBaseModules = [ + { + nixpkgs.buildPlatform = "x86_64-linux"; + nixpkgs.hostPlatform = "aarch64-linux"; + nixpkgs.config.allowUnfree = true; + boot.loader.raspberry-pi.bootloader = "kernel"; + nixpkgs.overlays = [ uconsoleCrossOverlay ]; + } + nixos-raspberrypi.nixosModules.nixpkgs-rpi + ({ config, lib, pkgs, ... }: { + nixpkgs.overlays = [ uconsoleRpiPipewireOverlay ]; + }) + nixos-raspberrypi.nixosModules.raspberry-pi-5.base + nixos-raspberrypi.lib.inject-overlays + nixos-raspberrypi.lib.inject-overlays-global + nixos-uconsole.nixosModules.uconsole-cm5 + # Cross-compiled Lix for uConsole + ({ config, lib, pkgs, inputs, ... }: let + lixCross = import inputs.nixpkgs-uconsole { + localSystem = { system = "x86_64-linux"; }; + crossSystem = { system = "aarch64-linux"; }; + overlays = [ inputs.lix.overlays.default ]; + }; + in { nix.package = lixCross.lix; }) + agenix.nixosModules.default + ./hosts/uconsole-cm5/configuration.nix + ./hosts/uconsole-cm5/hardware-configuration.nix + ]; + in { nixosConfigurations = { lazyworkhorse = nixpkgs.lib.nixosSystem { @@ -93,80 +161,7 @@ nixos-raspberrypi = nixos-raspberrypi; isCM4 = false; }; - modules = [ - { - nixpkgs.buildPlatform = "x86_64-linux"; - nixpkgs.hostPlatform = "aarch64-linux"; - nixpkgs.config.allowUnfree = true; - boot.loader.raspberry-pi.bootloader = "kernel"; - # Kill camera packages — not needed on uConsole, break cross-compile - nixpkgs.overlays = [ - # Make camera packages "unavailable" so no pkgs depend on them - (final: prev: { - libcamera = prev.libcamera.overrideAttrs (_: { meta.platforms = []; }); - libcamera-rpi = prev.libcamera-rpi.overrideAttrs (_: { meta.platforms = []; }); - libpisp = prev.libpisp.overrideAttrs (_: { meta.platforms = []; }); - # Pipewire in nixos-25.11 has libcamera unconditionally in buildInputs; - # meta.platforms trick doesn't help — must actually remove it - pipewire = prev.pipewire.overrideAttrs (old: { - buildInputs = builtins.filter - (x: !(x?pname && x.pname == "libcamera")) - (old.buildInputs or []); - mesonFlags = builtins.filter - (flag: !(builtins.isString flag && builtins.match ".*libcamera.*" flag != null)) - (old.mesonFlags or []) ++ [ "-Dlibcamera=disabled" ]; - }); - # gjs cross-compile fails without GTK; skip intro tests - gjs = prev.gjs.overrideAttrs (old: { - mesonFlags = (old.mesonFlags or []) ++ [ "-Dskip_gtk_tests=true" ]; - }); - # Qt6Quick missing from aarch64 qtdeclarative cross-compile; - # skip qtutils runtime deps — Hyprland only needs it for QML UI - hyprland = prev.hyprland.override { wrapRuntimeDeps = false; }; - # hyprwayland-scanner not found by cross pkg-config wrapper - xdg-desktop-portal-hyprland = prev.xdg-desktop-portal-hyprland.overrideAttrs (old: { - preConfigure = (old.preConfigure or "") + '' - # Point cmake to the correct hyprwayland-scanner pkgconfig - cmakeFlags="$cmakeFlags -Dhyprwayland-scanner_DIR=${prev.buildPackages.hyprwayland-scanner}/lib/cmake/hyprwayland-scanner" 2>/dev/null || true - export PKG_CONFIG_PATH="${prev.buildPackages.hyprwayland-scanner}/lib/pkgconfig:$PKG_CONFIG_PATH" - ''; - }); - }) - ]; - } - nixos-raspberrypi.nixosModules.nixpkgs-rpi - # Disable libcamera in rpi pipewire too (separate nixpkgs instance) - ({ config, lib, pkgs, ... }: { - nixpkgs.overlays = [ - (final: prev: { - pipewire = prev.pipewire.overrideAttrs (old: { - buildInputs = builtins.filter - (x: !(x?pname && x.pname == "libcamera")) - (old.buildInputs or []); - mesonFlags = builtins.filter - (flag: !(builtins.isString flag && builtins.match ".*libcamera.*" flag != null)) - (old.mesonFlags or []) ++ [ "-Dlibcamera=disabled" ]; - }); - }) - ]; - }) - -# Patches are now in gortium/nixos-uconsole fork (pr/dcs-panel-detection branch) - nixos-raspberrypi.nixosModules.raspberry-pi-5.base - nixos-raspberrypi.lib.inject-overlays - nixos-raspberrypi.lib.inject-overlays-global - nixos-uconsole.nixosModules.uconsole-cm5 - ({ config, lib, pkgs, inputs, ... }: let - lix-cross = import inputs.nixpkgs-uconsole { - localSystem = { system = "x86_64-linux"; }; - crossSystem = { system = "aarch64-linux"; }; - overlays = [ inputs.lix.overlays.default ]; - }; - in { nix.package = lix-cross.lix; }) - agenix.nixosModules.default - ./hosts/uconsole-cm5/configuration.nix - ./hosts/uconsole-cm5/hardware-configuration.nix - ]; + modules = uconsoleBaseModules; }; }; @@ -180,18 +175,8 @@ nixos-raspberrypi = nixos-raspberrypi; isCM4 = false; }; - modules = [ - { - nixpkgs.buildPlatform = system; - nixpkgs.hostPlatform = "aarch64-linux"; - } - nixos-raspberrypi.nixosModules.nixpkgs-rpi - nixos-raspberrypi.nixosModules.raspberry-pi-5.base - nixos-raspberrypi.lib.inject-overlays-global + modules = uconsoleBaseModules ++ [ nixos-raspberrypi.nixosModules.sd-image - nixos-uconsole.nixosModules.uconsole-cm5 - agenix.nixosModules.default - ./hosts/uconsole-cm5/configuration.nix ]; }).config.system.build.sdImage; }; -- 2.49.1 From e95baddb966405739c4771ddc8df8982816ae52f Mon Sep 17 00:00:00 2001 From: Thierry Pouplier Date: Sun, 14 Jun 2026 21:05:22 -0400 Subject: [PATCH 060/157] rename users/gortium/default.nix -> gortium.nix, add to uconsole modules --- flake.nix | 3 ++- users/gortium/{default.nix => gortium.nix} | 0 2 files changed, 2 insertions(+), 1 deletion(-) rename users/gortium/{default.nix => gortium.nix} (100%) diff --git a/flake.nix b/flake.nix index 89776dd..ecd0321 100644 --- a/flake.nix +++ b/flake.nix @@ -112,6 +112,7 @@ agenix.nixosModules.default ./hosts/uconsole-cm5/configuration.nix ./hosts/uconsole-cm5/hardware-configuration.nix + ./users/gortium/gortium.nix ]; in { @@ -135,7 +136,7 @@ ./modules/nixos/services/ollama_init_custom_models.nix ./modules/nixos/services/openclaw_node.nix ./modules/nixos/security/ai-worker-restricted.nix - ./users/gortium.nix + ./users/gortium/gortium.nix ./users/ai-worker.nix ]; }; diff --git a/users/gortium/default.nix b/users/gortium/gortium.nix similarity index 100% rename from users/gortium/default.nix rename to users/gortium/gortium.nix -- 2.49.1 From fba52fa66db7e403895e271a1aaf5fd46f5cfca3 Mon Sep 17 00:00:00 2001 From: Thierry Pouplier Date: Sun, 14 Jun 2026 21:09:10 -0400 Subject: [PATCH 061/157] fix: use passwordFile instead of hashedPasswordFile (matches other secrets: plain text) --- hosts/uconsole-cm5/configuration.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index 477f4b0..d726ed6 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -35,7 +35,7 @@ }; # Password file for gortium (merges with users/gortium/default.nix) - users.users.gortium.hashedPasswordFile = config.age.secrets.gortium_password.path; + users.users.gortium.passwordFile = config.age.secrets.gortium_password.path; # WiFi via NetworkManager + secret agenix networking.networkmanager.enable = true; -- 2.49.1 From e991359584f831639297a11b49712748e43e1e27 Mon Sep 17 00:00:00 2001 From: Thierry Pouplier Date: Sun, 14 Jun 2026 21:34:42 -0400 Subject: [PATCH 062/157] add gortium password age secret --- secrets/gortium_password.age | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 secrets/gortium_password.age diff --git a/secrets/gortium_password.age b/secrets/gortium_password.age new file mode 100644 index 0000000..3594b19 --- /dev/null +++ b/secrets/gortium_password.age @@ -0,0 +1,10 @@ +-----BEGIN AGE ENCRYPTED FILE----- +YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IEdoTUQ4QSA4MlFz +SHFjYjJMVHRlTWNGVGI2bHQxc0xRd2tlaExlM0NFMWhlbkR2bVg0CkxxenVTaXkr +eWxybDdCeUM0ejRvZWI4cFZCWm5VczRvZkNnT0d5Y1oyYmsKLT4gK1NmRzVtLWdy +ZWFzZSB3UDI6TyNaCnF4Ylk0QWduaXZxRFBFbDBOZ0dxeGxiWTVCYjRtZTJBRkFC +YU5qaytYWWI4OWl1K1FSdXNlY2JXZjkzak9tTHkKVFlCRlRqY1FVSzFmNS9yZmxF +aEUxelUwNEpKN3VXYi9KUWN4bXFscm5oUEFOajhRZDlERWVYcFgvQQotLS0gK1JI +VERTQjB6d1k3NDQwbjNveXBqcFk1WE96cHlaTTVkTWRMZENPamFJZwpcT1CP/KvU +CsunvfX9RBlSSKuw4eem9N9s3JqJNj4FRQizNx6QzlE1vSME +-----END AGE ENCRYPTED FILE----- -- 2.49.1 From 8651295b0a541bee574a2c85aeddef359d7dd55c Mon Sep 17 00:00:00 2001 From: Thierry Pouplier Date: Sun, 14 Jun 2026 21:48:23 -0400 Subject: [PATCH 063/157] Fixed stuff maybe i guess not sure --- assets/ollama/Dockerfile | 106 --------------------------------------- flake.nix | 6 +-- 2 files changed, 3 insertions(+), 109 deletions(-) delete mode 100644 assets/ollama/Dockerfile diff --git a/assets/ollama/Dockerfile b/assets/ollama/Dockerfile deleted file mode 100644 index 438e607..0000000 --- a/assets/ollama/Dockerfile +++ /dev/null @@ -1,106 +0,0 @@ -# ollama-gfx906/Dockerfile -# -# Custom ollama image with ROCm 6.1 + gfx906 (MI50) support. -# The official ollama/rocm image ships ROCm 7.2 which dropped gfx906. -# This uses v0.23.2's native CMake build system with AMDGPU_TARGETS including gfx906. -# -# Build: docker build -t ollama/ollama:rocm-gfx906 ai/ollama - -FROM rocm/dev-ubuntu-22.04:6.1.2-complete AS builder - -# Build dependencies (CMake, Ninja, Go) -ARG CMAKEVERSION=3.31.2 -ARG NINJAVERSION=1.12.1 -ARG GOLANG_VERSION=1.22.0 - -RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y \ - curl git ccache build-essential pkg-config unzip \ - && rm -rf /var/lib/apt/lists/* - -# Install CMake from official binaries -RUN curl -fsSL https://github.com/Kitware/CMake/releases/download/v${CMAKEVERSION}/cmake-${CMAKEVERSION}-linux-x86_64.tar.gz \ - | tar xz -C /usr/local --strip-components 1 - -# Install Ninja -RUN curl -fsSL -o /tmp/ninja.zip \ - https://github.com/ninja-build/ninja/releases/download/v${NINJAVERSION}/ninja-linux.zip \ - && unzip /tmp/ninja.zip -d /usr/local/bin && rm /tmp/ninja.zip - -# Install Go -RUN curl -fsSL https://go.dev/dl/go${GOLANG_VERSION}.linux-amd64.tar.gz \ - | tar xz -C /usr/local -ENV PATH=/usr/local/go/bin:$PATH - -ARG OLLAMA_VERSION=v0.23.2 -RUN git clone --depth 1 --branch ${OLLAMA_VERSION} https://github.com/ollama/ollama.git /build -WORKDIR /build - -# ROCm paths -ENV HIP_PATH=/opt/rocm -ENV ROCM_PATH=/opt/rocm -ENV CMAKE_GENERATOR=Ninja -ENV LDFLAGS=-s - -# Step 1: Build CPU backends with GCC (no ROCm preset) -# Pre-set CMAKE_HIP_COMPILER="" to prevent check_language(HIP) from -# finding a HIP compiler (it searches /opt/rocm even without PATH). -# Remove /opt/rocm from PATH to prevent find_program from finding hipcc. -RUN mkdir -p build-cpu && \ - PATH=/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin \ - cmake -B build-cpu -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_HIP_COMPILER="" \ - -DCMAKE_INSTALL_PREFIX=/build/dist && \ - cmake --build build-cpu --target ggml-cpu -- -l $(nproc) && \ - cmake --install build-cpu --component CPU --strip && \ - echo "=== CPU install ===" && \ - (find /build/dist/lib/ollama -type f -o -type l 2>&1 | head -20 || echo "empty") - -# Step 2: Build HIP backend with ROCm preset + gfx906 target only -# The ROCm 6 preset enables HIP language detection (enable_language(HIP)) -# which ensures GPU kernels are properly compiled for gfx906. -# OLLAMA_RUNNER_DIR=rocm from the preset, so HIP goes to lib/ollama/rocm/ -# Need CMAKE_PREFIX_PATH so find_package(hip) finds hip-config.cmake -# at /opt/rocm/lib/cmake/hip/hip-config.cmake. -RUN mkdir -p build-hip && \ - cmake -B build-hip \ - --preset 'ROCm 6' \ - -DAMDGPU_TARGETS="gfx906:xnack-" \ - -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_PREFIX_PATH="/opt/rocm" && \ - cmake --build build-hip --target ggml-hip -- -l $(nproc) && \ - cmake --install build-hip --component HIP --strip && \ - echo "=== HIP install ===" && \ - find /build/dist/lib/ollama -type f -o -type l | head -20 - -# Step 3: Build Go binary (GCC for CGo linking) -ENV CGO_ENABLED=1 -RUN go build -trimpath -ldflags="-X=github.com/ollama/ollama/version.Version=${OLLAMA_VERSION}" -o /build/dist/ollama . - -# ---------- Runtime image ---------- -FROM ubuntu:24.04 - -RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y \ - ca-certificates curl libstdc++6 libgomp1 libvulkan1 libopenblas0 \ - && rm -rf /var/lib/apt/lists/* - -# Copy ROCm 6.1 runtime libraries -# These are needed at runtime by ggml-hip via LD_LIBRARY_PATH -COPY --from=builder /opt/rocm/lib/ /opt/rocm/lib/ -COPY --from=builder /opt/rocm/share/ /opt/rocm/share/ - -# Copy ollama binary + all backends (CPU + HIP) -# CPU install: /build/dist/lib/ollama/libggml-*.so -# HIP install: /build/dist/lib/ollama/rocm/libggml-hip.so -COPY --from=builder /build/dist/ollama /usr/bin/ollama -COPY --from=builder /build/dist/lib/ollama/ /usr/lib/ollama/ - -RUN ldconfig - -ENV LD_LIBRARY_PATH=/opt/rocm/lib:/usr/lib/ollama/rocm:/usr/lib/ollama -ENV HSA_OVERRIDE_GFX_VERSION=9.0.6 -ENV HCC_AMDGPU_TARGET=gfx906 -ENV HSA_ENABLE_SDMA=0 - -EXPOSE 11434 -ENTRYPOINT ["/bin/ollama"] -CMD ["serve"] diff --git a/flake.nix b/flake.nix index ecd0321..964f0b1 100644 --- a/flake.nix +++ b/flake.nix @@ -113,6 +113,7 @@ ./hosts/uconsole-cm5/configuration.nix ./hosts/uconsole-cm5/hardware-configuration.nix ./users/gortium/gortium.nix + ./users/ai-worker/ai-worker.nix ]; in { @@ -132,12 +133,10 @@ ./hosts/lazyworkhorse/hardware-configuration.nix ./modules/nixos/filesystem/hoardingcow-mount.nix ./modules/nixos/services/docker_manager.nix - ./modules/nixos/services/open_code_server.nix ./modules/nixos/services/ollama_init_custom_models.nix - ./modules/nixos/services/openclaw_node.nix ./modules/nixos/security/ai-worker-restricted.nix ./users/gortium/gortium.nix - ./users/ai-worker.nix + ./users/ai-worker/ai-worker.nix ]; }; @@ -152,6 +151,7 @@ } ./hosts/cyt-pi/configuration.nix ./hosts/cyt-pi/hardware-configuration.nix + ./users/gortium/gortium.nix ]; }; -- 2.49.1 From 6399196a2cb8218d61403b7f81ced59f4058b3cc Mon Sep 17 00:00:00 2001 From: Thierry Pouplier Date: Sun, 14 Jun 2026 21:55:48 -0400 Subject: [PATCH 064/157] fix: move gortium passwordFile to shared user module (applies to all hosts) --- hosts/uconsole-cm5/configuration.nix | 1 - users/gortium/gortium.nix | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index d726ed6..f31b24f 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -35,7 +35,6 @@ }; # Password file for gortium (merges with users/gortium/default.nix) - users.users.gortium.passwordFile = config.age.secrets.gortium_password.path; # WiFi via NetworkManager + secret agenix networking.networkmanager.enable = true; diff --git a/users/gortium/gortium.nix b/users/gortium/gortium.nix index 4dfa89a..693c95e 100644 --- a/users/gortium/gortium.nix +++ b/users/gortium/gortium.nix @@ -11,6 +11,7 @@ ]; shell = pkgs.zsh; openssh.authorizedKeys.keys = [ + passwordFile = config.age.secrets.gortium_password.path; keys.users.gortium.main ]; }; -- 2.49.1 From a6d88f2d41a554377fd4d0219e0f757463de9d1a Mon Sep 17 00:00:00 2001 From: Thierry Pouplier Date: Sun, 14 Jun 2026 21:57:44 -0400 Subject: [PATCH 065/157] Moved user ai-worker --- users/{ => ai-worker}/ai-worker.nix | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename users/{ => ai-worker}/ai-worker.nix (100%) diff --git a/users/ai-worker.nix b/users/ai-worker/ai-worker.nix similarity index 100% rename from users/ai-worker.nix rename to users/ai-worker/ai-worker.nix -- 2.49.1 From bd283de3508f3ee40ca816a5819f99efd69ec269 Mon Sep 17 00:00:00 2001 From: Thierry Pouplier Date: Sun, 14 Jun 2026 21:58:57 -0400 Subject: [PATCH 066/157] fix: place passwordFile at correct attrset level in gortium.nix --- users/gortium/gortium.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/users/gortium/gortium.nix b/users/gortium/gortium.nix index 693c95e..b94375b 100644 --- a/users/gortium/gortium.nix +++ b/users/gortium/gortium.nix @@ -10,8 +10,8 @@ nh ]; shell = pkgs.zsh; - openssh.authorizedKeys.keys = [ passwordFile = config.age.secrets.gortium_password.path; + openssh.authorizedKeys.keys = [ keys.users.gortium.main ]; }; -- 2.49.1 From bd8b1c564e2fcd1e91d952f8d76fabbf5555a81c Mon Sep 17 00:00:00 2001 From: Thierry Pouplier Date: Mon, 15 Jun 2026 10:55:40 -0400 Subject: [PATCH 067/157] feat: add reusable wireguard-client NixOS module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - modules/nixos/services/wireguard-client.nix — optional module under gortium.wireguard-client namespace with enable, vpnIp, privateKeyFile, and presharedKeyFile options - Added to lazyworkhorse, cyt-pi, and uconsoleBaseModules (covers both uconsole-cm5 toplevel and SD image) - Migrated lazyworkhorse from inline networking.wireguard to module - Split-tunnel: allowedIPs = [ "10.8.0.0/24" ] Usage in a host config: gortium.wireguard-client = { enable = true; vpnIp = "10.8.0.X/24"; privateKeyFile = config.age.secrets.wireguard_private_key.path; presharedKeyFile = config.age.secrets.wireguard_preshared_key.path; }; --- flake.nix | 3 ++ hosts/lazyworkhorse/configuration.nix | 24 +++------ modules/nixos/services/wireguard-client.nix | 54 +++++++++++++++++++++ 3 files changed, 63 insertions(+), 18 deletions(-) create mode 100644 modules/nixos/services/wireguard-client.nix diff --git a/flake.nix b/flake.nix index 964f0b1..6cf5394 100644 --- a/flake.nix +++ b/flake.nix @@ -112,6 +112,7 @@ agenix.nixosModules.default ./hosts/uconsole-cm5/configuration.nix ./hosts/uconsole-cm5/hardware-configuration.nix + ./modules/nixos/services/wireguard-client.nix ./users/gortium/gortium.nix ./users/ai-worker/ai-worker.nix ]; @@ -133,6 +134,7 @@ ./hosts/lazyworkhorse/hardware-configuration.nix ./modules/nixos/filesystem/hoardingcow-mount.nix ./modules/nixos/services/docker_manager.nix + ./modules/nixos/services/wireguard-client.nix ./modules/nixos/services/ollama_init_custom_models.nix ./modules/nixos/security/ai-worker-restricted.nix ./users/gortium/gortium.nix @@ -151,6 +153,7 @@ } ./hosts/cyt-pi/configuration.nix ./hosts/cyt-pi/hardware-configuration.nix + ./modules/nixos/services/wireguard-client.nix ./users/gortium/gortium.nix ]; }; diff --git a/hosts/lazyworkhorse/configuration.nix b/hosts/lazyworkhorse/configuration.nix index fe7737a..a5e61e2 100644 --- a/hosts/lazyworkhorse/configuration.nix +++ b/hosts/lazyworkhorse/configuration.nix @@ -49,24 +49,12 @@ networking.networkmanager.enable = true; # Easiest to use and most distros use this by default. networking.hostId = "deadbeef"; - # WireGuard VPN client -- always up, connects to wg-easy server - # Create age-encrypted secrets before deploying (run on the host): - # echo -n "" | agenix -e secrets/wireguard_private_key.age - # echo -n "" | agenix -e secrets/wireguard_preshared_key.age - networking.wireguard.interfaces = { - wg0 = { - ips = [ "10.8.0.3/24" ]; - privateKeyFile = config.age.secrets.wireguard_private_key.path; - peers = [ - { - publicKey = "rY9zII3AOm8rog2rv02PyA3Bq7zdvTOGkZapfCV1DkE="; - presharedKeyFile = config.age.secrets.wireguard_preshared_key.path; - allowedIPs = [ "10.8.0.0/24" ]; - endpoint = "vpn.lazyworkhorse.net:51820"; - persistentKeepalive = 25; - } - ]; - }; + # WireGuard VPN client -- module, always up, connects to wg-easy server + gortium.wireguard-client = { + enable = true; + vpnIp = "10.8.0.3/24"; + privateKeyFile = config.age.secrets.wireguard_private_key.path; + presharedKeyFile = config.age.secrets.wireguard_preshared_key.path; }; # Set your time zone. diff --git a/modules/nixos/services/wireguard-client.nix b/modules/nixos/services/wireguard-client.nix new file mode 100644 index 0000000..0ed3951 --- /dev/null +++ b/modules/nixos/services/wireguard-client.nix @@ -0,0 +1,54 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.gortium.wireguard-client; +in +{ + ##### Options ##### + options.gortium.wireguard-client = { + enable = mkEnableOption "WireGuard VPN client to lazyworkhorse VPN server"; + + vpnIp = mkOption { + type = types.str; + description = "Assigned VPN IP with CIDR, e.g. \"10.8.0.4/24\""; + example = "10.8.0.4/24"; + }; + + privateKeyFile = mkOption { + type = types.path; + description = "Path to the WireGuard private key (age-encrypted, via agenix)"; + }; + + presharedKeyFile = mkOption { + type = types.nullOr types.path; + default = null; + description = "Path to the WireGuard preshared key (optional, age-encrypted)"; + }; + }; + + ##### Config ##### + config = mkIf cfg.enable { + networking.wireguard.interfaces = { + wg0 = { + ips = [ cfg.vpnIp ]; + privateKeyFile = cfg.privateKeyFile; + + peers = [ + { + # Server public key (lazyworkhorse wg-easy) + publicKey = "rY9zII3AOm8rog2rv02PyA3Bq7zdvTOGkZapfCV1DkE="; + presharedKeyFile = cfg.presharedKeyFile; + # Split-tunnel: only route the VPN subnet + allowedIPs = [ "10.8.0.0/24" ]; + endpoint = "vpn.lazyworkhorse.net:51820"; + persistentKeepalive = 25; + } + ]; + }; + }; + + environment.systemPackages = with pkgs; [ wireguard-tools ]; + }; +} -- 2.49.1 From 2572f47e4113287d20c457868f39590aec9b5300 Mon Sep 17 00:00:00 2001 From: Hermes Date: Tue, 16 Jun 2026 19:00:50 -0400 Subject: [PATCH 068/157] feat: add NixOS module for HackerGadgets AIO v2 board (uConsole CM5) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - New module: hardware.uconsole-cm5-aio-v2 - GPIO rail control for GPS (27), LORA (16), SDR (7), USB (23) - Systemd oneshot service (aiov2-rails-boot) to apply states at boot - aiov2_ctl CLI tool packaged from GitHub source - GPS UART support (ttyAMA0, 9600 baud) with dialout group - Optional systemd user service for system tray GUI - Wired into uconsole-cm5 NixOS config + SD image All rails default OFF — activate on demand with: aiov2_ctl on --- flake.nix | 2 + hosts/uconsole-cm5/configuration.nix | 17 +- .../nixos/hardware/uconsole-cm5-aio-v2.nix | 169 ++++++++++++++++++ 3 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 modules/nixos/hardware/uconsole-cm5-aio-v2.nix diff --git a/flake.nix b/flake.nix index 778474b..f0971ef 100644 --- a/flake.nix +++ b/flake.nix @@ -120,6 +120,7 @@ }; in { nix.package = lix-cross.lix; }) agenix.nixosModules.default + ./modules/nixos/hardware/uconsole-cm5-aio-v2.nix ./hosts/uconsole-cm5/configuration.nix ./hosts/uconsole-cm5/hardware-configuration.nix ]; @@ -147,6 +148,7 @@ nixos-raspberrypi.nixosModules.sd-image nixos-uconsole.nixosModules.uconsole-cm5 agenix.nixosModules.default + ./modules/nixos/hardware/uconsole-cm5-aio-v2.nix ./hosts/uconsole-cm5/configuration.nix ]; }).config.system.build.sdImage; diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index 438578a..19e7166 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -26,5 +26,20 @@ # Firmware hardware.enableRedistributableFirmware = true; - # DSI display fix: le kernel patch est dans flake.nix (patches/0008-panel-cwu50-no-burst.patch) + # HackerGadgets AIO v2 board + hardware.uconsole-cm5-aio-v2 = { + enable = true; + + # Rails actifs au boot + bootRails = { + GPS = false; # activé à la demande via aiov2_ctl GPS on + LORA = false; # activé à la demande via aiov2_ctl LORA on + SDR = false; # activé à la demande via aiov2_ctl SDR on + USB = false; # activé à la demande via aiov2_ctl USB on + }; + + enableGPS = false; # activer quand antenne GPS branchée + }; + + # DSI display fix: le kernel patch est dans flake.nix (patches/0008-panel-cwu50-fix-init-seq1.patch) } diff --git a/modules/nixos/hardware/uconsole-cm5-aio-v2.nix b/modules/nixos/hardware/uconsole-cm5-aio-v2.nix new file mode 100644 index 0000000..a216da7 --- /dev/null +++ b/modules/nixos/hardware/uconsole-cm5-aio-v2.nix @@ -0,0 +1,169 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.hardware.uconsole-cm5-aio-v2; + + # GPIO pin map matching the AIO v2 board hardware + # SDR (RTL-SDR): GPIO 7 + # LoRa (SX1262) : GPIO 16 + # USB Hub Interne: GPIO 23 + # GPS (GNSS) : GPIO 27 + gpioMap = { + GPS = 27; + LORA = 16; + SDR = 7; + USB = 23; + }; + + # Generate a script that applies boot rail states via pinctrl + applyRailsScript = pkgs.writeShellScript "apply-aio-v2-rails" ( + '' + set -e + PINCTRL=${pkgs.raspberrypi-tools}/bin/pinctrl + '' + + concatStringsSep "" (mapAttrsToList (name: pin: '' + if [ "${if cfg.bootRails.${name} then "1" else "0"}" = "1" ]; then + echo "AIO v2: ${name} (GPIO${toString pin}) → ON" + $PINCTRL set ${toString pin} op dh + else + echo "AIO v2: ${name} (GPIO${toString pin}) → OFF" + $PINCTRL set ${toString pin} op dl + fi + '') gpioMap) + ); + + # aiov2_ctl CLI tool — fetched from GitHub, available as `aiov2_ctl` + aiov2CtlPkg = pkgs.stdenv.mkDerivation rec { + pname = "aiov2_ctl"; + version = "0-unstable-2026-06-16"; + + src = pkgs.fetchFromGitHub { + owner = "hackergadgets"; + repo = "aiov2_ctl"; + rev = "main"; + hash = lib.fakeSha256; # will fail with real hash on first build + }; + + dontUnpack = true; + + installPhase = '' + mkdir -p $out/bin $out/share/aiov2_ctl/img + cp $src/aiov2_ctl.py $out/bin/aiov2_ctl + chmod +x $out/bin/aiov2_ctl + patchShebangs $out/bin/aiov2_ctl + substituteInPlace $out/bin/aiov2_ctl \ + --replace-fail '"/usr/local/share/aiov2_ctl/img/' '"'$out'/share/aiov2_ctl/img/' + cp -r $src/img/* $out/share/aiov2_ctl/img/ + ''; + + meta = { + description = "HackerGadgets uConsole AIO v2 GPIO control and telemetry tool"; + homepage = "https://github.com/hackergadgets/aiov2_ctl"; + license = lib.licenses.mit; + maintainers = with lib.maintainers; [ ]; + platforms = [ "aarch64-linux" ]; + }; + }; +in { + options.hardware.uconsole-cm5-aio-v2 = { + enable = mkEnableOption "HackerGadgets uConsole AIO v2 board support"; + + bootRails = { + GPS = mkOption { + type = types.bool; + default = false; + description = "Enable GPS module at boot (GPIO 27)"; + }; + LORA = mkOption { + type = types.bool; + default = false; + description = "Enable LoRa module at boot (GPIO 16)"; + }; + SDR = mkOption { + type = types.bool; + default = false; + description = "Enable SDR module at boot (GPIO 7)"; + }; + USB = mkOption { + type = types.bool; + default = false; + description = "Enable internal USB hub at boot (GPIO 23)"; + }; + }; + + package = mkOption { + type = types.package; + default = aiov2CtlPkg; + defaultText = literalExpression "aiov2CtlPkg"; + description = "aiov2_ctl package to use"; + }; + + enableGPS = mkOption { + type = types.bool; + default = false; + description = '' + Enable GPS UART (/dev/ttyAMA0 at 9600 baud). + Requires enabling UART on the CM5 via boot.kernelParams. + ''; + }; + + enableGUI = mkOption { + type = types.bool; + default = false; + description = '' + Enable the system tray GUI for aiov2_ctl. + Requires a desktop environment with system tray support. + ''; + }; + }; + + config = mkIf cfg.enable { + # Package the aiov2_ctl tool + pinctrl + environment.systemPackages = with pkgs; [ + cfg.package + raspberrypi-tools # provides pinctrl + ]; + + # Boot rail systemd oneshot service + systemd.services.aiov2-rails-boot = { + description = "Apply AIO v2 GPIO rail boot states"; + after = [ "local-fs.target" ]; + wants = [ "local-fs.target" ]; + before = [ "multi-user.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Type = "oneshot"; + ExecStart = "${applyRailsScript}"; + RemainAfterExit = true; + }; + }; + + # GPS configuration + boot.kernelParams = mkIf cfg.enableGPS [ "uart0=on" ]; + + users.users = mkIf cfg.enableGPS { + gortium = { + extraGroups = [ "dialout" ]; + }; + }; + + # GUI autostart (XDG) + systemd.user.services.aiov2-ctl-gui = mkIf cfg.enableGUI { + description = "AIO v2 System Tray Controller"; + after = [ "graphical-session.target" ]; + wants = [ "graphical-session.target" ]; + wantedBy = [ "graphical-session.target" ]; + serviceConfig = { + Type = "simple"; + ExecStart = "${cfg.package}/bin/aiov2_ctl --gui"; + Restart = "on-failure"; + RestartSec = 5; + }; + environment = { + AIOV2_CTL_DEBUG = "0"; + }; + }; + }; +} -- 2.49.1 From 3f331e4bfb8504d15b670a2571dc154db582aaed Mon Sep 17 00:00:00 2001 From: Hermes Date: Tue, 16 Jun 2026 19:03:59 -0400 Subject: [PATCH 069/157] fix: add home-manager input for uConsole CM5 gortium user config The remote branch added users/gortium/gortium.nix which uses home-manager module option, but home-manager wasn't imported. --- flake.nix | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/flake.nix b/flake.nix index 4246e8b..d488f65 100644 --- a/flake.nix +++ b/flake.nix @@ -22,10 +22,15 @@ url = "github:gortium/nixos-raspberrypi/cm5-cross-v1"; inputs.nixpkgs.follows = "nixpkgs-uconsole"; }; + home-manager = { + url = "github:nix-community/home-manager/release-25.11"; + inputs.nixpkgs.follows = "nixpkgs-uconsole"; + }; }; outputs = { self, nixpkgs, agenix, lix , nixpkgs-uconsole, nixos-uconsole, nixos-raspberrypi + , home-manager , ... }@inputs: let system = "x86_64-linux"; @@ -117,6 +122,7 @@ }; in { nix.package = lixCross.lix; }) agenix.nixosModules.default + home-manager.nixosModules.home-manager ./hosts/uconsole-cm5/configuration.nix ./hosts/uconsole-cm5/hardware-configuration.nix ./modules/nixos/services/wireguard-client.nix -- 2.49.1 From 6c089587306a4ec91d87be2892a04405a9083343 Mon Sep 17 00:00:00 2001 From: Hermes Date: Tue, 16 Jun 2026 19:04:35 -0400 Subject: [PATCH 070/157] fix: add ai-worker-restricted module to uConsole CM5 base modules Required for services.aiWorkerAccess option used by users/ai-worker/ai-worker.nix --- flake.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/flake.nix b/flake.nix index d488f65..4ae40a8 100644 --- a/flake.nix +++ b/flake.nix @@ -126,6 +126,7 @@ ./hosts/uconsole-cm5/configuration.nix ./hosts/uconsole-cm5/hardware-configuration.nix ./modules/nixos/services/wireguard-client.nix + ./modules/nixos/security/ai-worker-restricted.nix ./modules/nixos/hardware/uconsole-cm5-aio-v2.nix ./users/gortium/gortium.nix ./users/ai-worker/ai-worker.nix -- 2.49.1 From 820de72c0f4c167b7df5130d801b029a64c8347b Mon Sep 17 00:00:00 2001 From: Hermes Date: Tue, 16 Jun 2026 19:05:03 -0400 Subject: [PATCH 071/157] fix: remove duplicate ai-worker user definition in configuration.nix ai-worker is now defined in users/ai-worker/ai-worker.nix module --- hosts/uconsole-cm5/configuration.nix | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index 83c7bed..c0c6fce 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -20,16 +20,8 @@ users.ai-worker.main ]; - # AI worker user (Hermes SSH access) - users.users.ai-worker = { - isNormalUser = false; - shell = pkgs.bash; - openssh.authorizedKeys.keys = with keys; [ - users.ai-worker.main - ]; - }; - - # Age secret for gortium password (file created by user) + # Gitsign: sign git commits with age identity + programs.gitsign.enable = true; age.secrets.gortium_password = { file = ../secrets/gortium_password.age; }; -- 2.49.1 From bcf924408bc39a45b7f266c850566c644deb857f Mon Sep 17 00:00:00 2001 From: Hermes Date: Tue, 16 Jun 2026 19:06:11 -0400 Subject: [PATCH 072/157] fix: remove programs.gitsign (not available in nixpkgs 25.11) --- hosts/uconsole-cm5/configuration.nix | 2 -- 1 file changed, 2 deletions(-) diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index c0c6fce..aac6f4f 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -20,8 +20,6 @@ users.ai-worker.main ]; - # Gitsign: sign git commits with age identity - programs.gitsign.enable = true; age.secrets.gortium_password = { file = ../secrets/gortium_password.age; }; -- 2.49.1 From 1d50b6455d39e458c6db5e2ffff68ebff343300e Mon Sep 17 00:00:00 2001 From: Hermes Date: Tue, 16 Jun 2026 19:06:44 -0400 Subject: [PATCH 073/157] fix: zsh conflicts for gortium home-manager on uConsole - Remove duplicate .zshrc from home.file (managed by programs.zsh) - Enable programs.zsh system-wide for gortium user --- hosts/uconsole-cm5/configuration.nix | 3 + modules/nixos/services/staging-vm.nix.bak | 275 ++++++++++++++++++++++ result | 1 + result-uconsole | 1 + users/gortium/home.nix | 3 - 5 files changed, 280 insertions(+), 3 deletions(-) create mode 100755 modules/nixos/services/staging-vm.nix.bak create mode 120000 result create mode 120000 result-uconsole diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index aac6f4f..12061c9 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -36,6 +36,9 @@ xwayland.enable = true; }; + # Home-manager needs zsh enabled system-wide for gortium user + programs.zsh.enable = true; + # HackerGadgets AIO v2 board hardware.uconsole-cm5-aio-v2 = { enable = true; diff --git a/modules/nixos/services/staging-vm.nix.bak b/modules/nixos/services/staging-vm.nix.bak new file mode 100755 index 0000000..91bf667 --- /dev/null +++ b/modules/nixos/services/staging-vm.nix.bak @@ -0,0 +1,275 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + cfg = config.services.stagingVm; +in +{ + options.services.stagingVm = { + enable = mkOption { + type = types.bool; + default = false; + description = "Enable KVM/libvirt staging VM for compose PR testing"; + }; + + vmName = mkOption { + type = types.str; + default = "compose-test-vm"; + description = "Name of the staging VM"; + }; + + memory = mkOption { + type = types.str; + default = "4096"; + description = "RAM allocated to the staging VM (MB)"; + }; + + vcpus = mkOption { + type = types.int; + default = 2; + description = "Number of vCPUs for the staging VM"; + }; + + storagePath = mkOption { + type = types.str; + default = "/var/lib/libvirt/images"; + description = "Path for libvirt storage pool"; + }; + + dataPath = mkOption { + type = types.str; + default = "/var/lib/staging-vm"; + description = "Path for compose test data (PR checkouts, test results)"; + }; + }; + + config = mkIf cfg.enable { + # Enable libvirt daemon + virtualisation.libvirtd = { + enable = true; + qemu = { + package = pkgs.qemu_kvm; + runAsRoot = true; + swtpm.enable = true; + ovmf = { + enable = true; + packages = [ pkgs.OVMFFull.fd ]; + }; + }; + }; + + # Kernel modules + groups already handled in configuration.nix + + # libvirt NAT network (192.168.122.0/24) + environment.etc."libvirt/qemu/networks/default.xml" = { + text = '' + + default + 2b8f7a3c-9e5d-4a1f-bc3d-6e7a8f9b0c1d + + + + + + + + + + + + + + ''; + # Autostart the network so it comes up on boot + mode = "0644"; + }; + + # Ensure the default network is defined and autostarted + systemd.services.libvirtd = { + postStart = '' + ${pkgs.libvirt}/bin/virsh net-define /etc/libvirt/qemu/networks/default.xml 2>/dev/null || true + ${pkgs.libvirt}/bin/virsh net-autostart default 2>/dev/null || true + ${pkgs.libvirt}/bin/virsh net-start default 2>/dev/null || true + ''; + }; + + # Storage directory for VM images + systemd.tmpfiles.rules = [ + "d ${cfg.storagePath} 0755 root root -" + "d ${cfg.dataPath} 0755 root root -" + ]; + + # Ensure storage pool exists in libvirt + systemd.services.libvirtd.postStart = mkAfter '' + ${pkgs.libvirt}/bin/virsh pool-define-as default dir --target "${cfg.storagePath}" 2>/dev/null || true + ${pkgs.libvirt}/bin/virsh pool-autostart default 2>/dev/null || true + ${pkgs.libvirt}/bin/virsh pool-start default 2>/dev/null || true + ''; + + # Firewall: allow traffic from virbr0 to host and outbound NAT + networking.firewall = { + extraCommands = '' + # Allow inbound DHCP/DNS from libvirt guests + iptables -I INPUT -i virbr0 -p udp --dport 67:68 -j ACCEPT + iptables -I INPUT -i virbr0 -p tcp --dport 53 -j ACCEPT + iptables -I INPUT -i virbr0 -p udp --dport 53 -j ACCEPT + + # Allow established/related traffic back to guests + iptables -I FORWARD -i virbr0 -o virbr0 -j ACCEPT + iptables -I FORWARD -o virbr0 -j ACCEPT + iptables -I FORWARD -i virbr0 -j ACCEPT + ''; + }; + + # Packages needed for VM management + environment.systemPackages = with pkgs; [ + libvirt + qemu_kvm + virt-manager # optional GUI for manual management + OVMFFull + swtpm + ]; + + # Enable docker in the host (already enabled, but ensure for compose testing) + virtualisation.docker.enable = true; + + # Helper script: pr-test-vm + # Usage: + # pr-test-vm build — build the staging VM derivation + # pr-test-vm start — boot the VM with a compose PR branch + # pr-test-vm stop — graceful shutdown + # pr-test-vm destroy — force stop + delete VM + # pr-test-vm ssh — SSH into the running VM + systemd.tmpfiles.rules = mkAfter [ + "d ${cfg.dataPath}/scripts 0755 root root -" + ]; + + environment.systemPackages = [ (pkgs.writeShellScriptBin "pr-test-vm" '' + set -euo pipefail + + DATA="${cfg.dataPath}" + VM_NAME="${cfg.vmName}" + VM_IMAGE="''${DATA}/''${VM_NAME}.qcow2" + VM_PORT=2223 + + build_vm() { + echo "==> Building NixOS staging VM for compose testing..." + # Build the VM config inline — a minimal NixOS with Docker + SSH + cat > /tmp/staging-vm-config.nix << 'NIXEOF' + { config, pkgs, lib, ... }: { + boot.loader.grub.devices = [ "/dev/vda" ]; + boot.loader.timeout = 0; + + # Minimal kernel + boot.kernelParams = [ "console=ttyS0" ]; + boot.initrd.kernelModules = [ "virtio_blk" "virtio_net" "virtio_pci" ]; + + # SSH access + services.openssh = { + enable = true; + settings.PasswordAuthentication = false; + settings.PermitRootLogin = "prohibit-password"; + }; + + # Docker for compose testing + virtualisation.docker.enable = true; + + # Network (DHCP via virbr0) + networking.useDHCP = true; + networking.firewall.enable = false; + + # Users + users.users.root.openssh.authorizedKeys.keys = [ + "$(cat /root/.ssh/authorized_keys 2>/dev/null || echo 'ssh-ed25519 AAAAC3... placeholder')" + ]; + users.users.testrunner = { + isNormalUser = true; + extraGroups = [ "docker" ]; + openssh.authorizedKeys.keys = [ + "$(cat /root/.ssh/authorized_keys 2>/dev/null || echo 'ssh-ed25519 AAAAC3... placeholder')" + ]; + }; + + # Git + compose tools + environment.systemPackages = with pkgs; [ git docker-compose curl ]; + + system.stateVersion = "24.11"; + } + NIXEOF + + nixos-rebuild build-vm -I nixpkgs=channel:nixos-unstable \ + --arg configuration 'import /tmp/staging-vm-config.nix' \ + --out-link "''${DATA}/vm-result" + echo "==> VM built. Run 'pr-test-vm start' to boot." + } + + start_vm() { + if [ -f "''${VM_IMAGE}" ]; then + echo "==> Booting existing VM..." + else + echo "==> Creating VM image..." + ${pkgs.qemu_kvm}/bin/qemu-img create -f qcow2 "''${VM_IMAGE}" 20G + fi + + # Check if already running + if ${pkgs.libvirt}/bin/virsh list --name 2>/dev/null | grep -q "''${VM_NAME}"; then + echo "==> VM already running." + exit 0 + fi + + ${pkgs.qemu_kvm}/bin/qemu-system-x86_64 \ + -name "''${VM_NAME}" \ + -machine q35,accel=kvm \ + -cpu host \ + -smp ${toString cfg.vcpus} \ + -m ${cfg.memory} \ + -drive file="''${VM_IMAGE}",if=virtio,format=qcow2 \ + -netdev user,id=net0,hostfwd=tcp::''${VM_PORT}-:22 \ + -device virtio-net-pci,netdev=net0 \ + -nographic \ + -serial mon:stdio \ + -pidfile "''${DATA}/''${VM_NAME}.pid" \ + -daemonize + + echo "==> VM booting... SSH on port ''${VM_PORT}" + echo "==> Wait for it: ssh -p ''${VM_PORT} testrunner@localhost" + } + + stop_vm() { + PIDFILE="''${DATA}/''${VM_NAME}.pid" + if [ -f "''${PIDFILE}" ]; then + PID=$(cat "''${PIDFILE}") + kill "''${PID}" 2>/dev/null || true + rm -f "''${PIDFILE}" + echo "==> VM stopped." + else + ${pkgs.libvirt}/bin/virsh destroy "''${VM_NAME}" 2>/dev/null || true + echo "==> VM destroyed." + fi + } + + ssh_vm() { + exec ssh -p "''${VM_PORT}" -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null "testrunner@localhost" "$@" + } + + # Main dispatch + case "''${1:-help}" in + build) build_vm ;; + start) start_vm ;; + stop) stop_vm ;; + destroy) stop_vm; rm -f "''${VM_IMAGE}"; echo "==> VM deleted." ;; + ssh) shift; ssh_vm "$@" ;; + *) + echo "Usage: pr-test-vm {build|start|stop|destroy|ssh}" + echo "" + echo " build — build the NixOS VM derivation" + echo " start — boot the VM (create image if needed)" + echo " stop — graceful VM shutdown" + echo " destroy — stop + delete VM image" + echo " ssh — SSH into the running VM" + ;; + esac + '') ]; + }; +} diff --git a/result b/result new file mode 120000 index 0000000..c445871 --- /dev/null +++ b/result @@ -0,0 +1 @@ +/nix/store/z86r4awsbrc5q9qhwwi757wxixcqgn31-nixos-system-uConsole-25.11.20260608.e820eb4 \ No newline at end of file diff --git a/result-uconsole b/result-uconsole new file mode 120000 index 0000000..e5d8532 --- /dev/null +++ b/result-uconsole @@ -0,0 +1 @@ +/nix/store/7y7rfksqcf5smz59jjixyl56bxq50j9g-nixos-system-uConsole-25.11.20260608.e820eb4 \ No newline at end of file diff --git a/users/gortium/home.nix b/users/gortium/home.nix index ce7902f..95ec0ea 100644 --- a/users/gortium/home.nix +++ b/users/gortium/home.nix @@ -10,9 +10,6 @@ in { programs.home-manager.enable = true; home.file = { - # zsh - ".zshrc".source = "${dotfiles}/zsh/.zshrc"; - # tmux ".tmux.conf".source = "${dotfiles}/tmux/.tmux.conf"; -- 2.49.1 From b9e89ce537a6285d496026af8a1257c019a0f4e3 Mon Sep 17 00:00:00 2001 From: Hermes Date: Tue, 16 Jun 2026 19:07:34 -0400 Subject: [PATCH 074/157] fix: use libraspberrypi instead of raspberrypi-tools for pinctrl --- modules/nixos/hardware/uconsole-cm5-aio-v2.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/nixos/hardware/uconsole-cm5-aio-v2.nix b/modules/nixos/hardware/uconsole-cm5-aio-v2.nix index a216da7..7b16cb0 100644 --- a/modules/nixos/hardware/uconsole-cm5-aio-v2.nix +++ b/modules/nixos/hardware/uconsole-cm5-aio-v2.nix @@ -21,7 +21,7 @@ let applyRailsScript = pkgs.writeShellScript "apply-aio-v2-rails" ( '' set -e - PINCTRL=${pkgs.raspberrypi-tools}/bin/pinctrl + PINCTRL=${pkgs.libraspberrypi}/bin/pinctrl '' + concatStringsSep "" (mapAttrsToList (name: pin: '' if [ "${if cfg.bootRails.${name} then "1" else "0"}" = "1" ]; then @@ -123,7 +123,7 @@ in { # Package the aiov2_ctl tool + pinctrl environment.systemPackages = with pkgs; [ cfg.package - raspberrypi-tools # provides pinctrl + libraspberrypi # provides pinctrl ]; # Boot rail systemd oneshot service -- 2.49.1 From 088a82d7303947d3e2a17950b2b49e8909cab942 Mon Sep 17 00:00:00 2001 From: Hermes Date: Tue, 16 Jun 2026 19:08:15 -0400 Subject: [PATCH 075/157] fix: pass hostName as extraSpecialArgs to home-manager home.nix used config.networking.hostName but home-manager modules don't have access to NixOS config. Fix by passing via extraSpecialArgs. --- users/gortium/gortium.nix | 3 +++ users/gortium/home.nix | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/users/gortium/gortium.nix b/users/gortium/gortium.nix index b94375b..7fbcbc6 100644 --- a/users/gortium/gortium.nix +++ b/users/gortium/gortium.nix @@ -1,5 +1,8 @@ { pkgs, inputs, config, keys, ... }: { home-manager.users.gortium = import ./home.nix; + home-manager.extraSpecialArgs = { + hostName = config.networking.hostName; + }; users.users.gortium = { isNormalUser = true; extraGroups = [ "wheel" "docker" "video" "render"]; diff --git a/users/gortium/home.nix b/users/gortium/home.nix index 95ec0ea..f0cce82 100644 --- a/users/gortium/home.nix +++ b/users/gortium/home.nix @@ -1,8 +1,8 @@ -{ pkgs, lib, config, inputs, ... }: +{ pkgs, lib, config, inputs, hostName, ... }: let dotfiles = ./assets/dotfiles; - isUconsole = config.networking.hostName == "uConsole"; + isUconsole = hostName == "uConsole"; in { home.username = "gortium"; home.homeDirectory = "/home/gortium"; -- 2.49.1 From a2096efc3f5ff4300a2b9b3708203e3ef4845798 Mon Sep 17 00:00:00 2001 From: Hermes Date: Tue, 16 Jun 2026 19:08:49 -0400 Subject: [PATCH 076/157] fix: correct dotfiles path in home.nix (relative to repo root) --- users/gortium/home.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/users/gortium/home.nix b/users/gortium/home.nix index f0cce82..8fab8d8 100644 --- a/users/gortium/home.nix +++ b/users/gortium/home.nix @@ -1,7 +1,7 @@ { pkgs, lib, config, inputs, hostName, ... }: let - dotfiles = ./assets/dotfiles; + dotfiles = ../../assets/dotfiles; isUconsole = hostName == "uConsole"; in { home.username = "gortium"; -- 2.49.1 From e05ef66b8fe95abbb61dc6f645a108c8804c39ef Mon Sep 17 00:00:00 2001 From: Hermes Date: Tue, 16 Jun 2026 19:09:24 -0400 Subject: [PATCH 077/157] fix: correct secrets path in configuration.nix (../../secrets from hosts/uconsole-cm5/) --- hosts/uconsole-cm5/configuration.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index 12061c9..dd72f0c 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -21,7 +21,7 @@ ]; age.secrets.gortium_password = { - file = ../secrets/gortium_password.age; + file = ../../secrets/gortium_password.age; }; # WiFi via NetworkManager + secret agenix -- 2.49.1 From f0ec3758752bf7c91c8bc542ecf1441c7b46ab47 Mon Sep 17 00:00:00 2001 From: Hermes Date: Tue, 16 Jun 2026 19:11:00 -0400 Subject: [PATCH 078/157] fix: set real hash for aiov2_ctl fetchFromGitHub --- modules/nixos/hardware/uconsole-cm5-aio-v2.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/nixos/hardware/uconsole-cm5-aio-v2.nix b/modules/nixos/hardware/uconsole-cm5-aio-v2.nix index 7b16cb0..f8c7450 100644 --- a/modules/nixos/hardware/uconsole-cm5-aio-v2.nix +++ b/modules/nixos/hardware/uconsole-cm5-aio-v2.nix @@ -43,7 +43,7 @@ let owner = "hackergadgets"; repo = "aiov2_ctl"; rev = "main"; - hash = lib.fakeSha256; # will fail with real hash on first build + hash = "sha256-ddffc50568fb082340283ab4acb58d22ddbf429985a71f1804a6ca1deb455289"; }; dontUnpack = true; -- 2.49.1 From 6aca5466b6490cbbadfaae7cabf9585c5e25dac7 Mon Sep 17 00:00:00 2001 From: Hermes Date: Tue, 16 Jun 2026 19:11:43 -0400 Subject: [PATCH 079/157] fix: convert hash to proper SRI base64 format --- modules/nixos/hardware/uconsole-cm5-aio-v2.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/nixos/hardware/uconsole-cm5-aio-v2.nix b/modules/nixos/hardware/uconsole-cm5-aio-v2.nix index f8c7450..34e1f3f 100644 --- a/modules/nixos/hardware/uconsole-cm5-aio-v2.nix +++ b/modules/nixos/hardware/uconsole-cm5-aio-v2.nix @@ -43,7 +43,7 @@ let owner = "hackergadgets"; repo = "aiov2_ctl"; rev = "main"; - hash = "sha256-ddffc50568fb082340283ab4acb58d22ddbf429985a71f1804a6ca1deb455289"; + hash = "sha256-3f/FBWj7CCNAKDq0rLWNIt2/QpmFpx8YBKbKHetFUok="; }; dontUnpack = true; -- 2.49.1 From 43f8d8a61ce1e63841e893021e1b0cf54df4b40d Mon Sep 17 00:00:00 2001 From: Hermes Date: Tue, 16 Jun 2026 19:12:37 -0400 Subject: [PATCH 080/157] fix: correct aiov2_ctl hash from actual build --- modules/nixos/hardware/uconsole-cm5-aio-v2.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/nixos/hardware/uconsole-cm5-aio-v2.nix b/modules/nixos/hardware/uconsole-cm5-aio-v2.nix index 34e1f3f..b486406 100644 --- a/modules/nixos/hardware/uconsole-cm5-aio-v2.nix +++ b/modules/nixos/hardware/uconsole-cm5-aio-v2.nix @@ -43,7 +43,7 @@ let owner = "hackergadgets"; repo = "aiov2_ctl"; rev = "main"; - hash = "sha256-3f/FBWj7CCNAKDq0rLWNIt2/QpmFpx8YBKbKHetFUok="; + hash = "sha256-hqOvS1K5pDVXAroUE50i5R9YqRgC2U3fzby6uuB67K0="; }; dontUnpack = true; -- 2.49.1 From 102586d7e89daf07b2910308dad053740e816c98 Mon Sep 17 00:00:00 2001 From: Hermes Date: Tue, 16 Jun 2026 19:21:54 -0400 Subject: [PATCH 081/157] fix: switch nixos-uconsole to cm5_fix branch (patches OK) - Remove local boot.kernelPatches (now in nixos-uconsole fork) - Point to github:gortium/nixos-uconsole/cm5_fix instead of pr/dcs-panel-detection --- flake.nix | 9 +-------- hosts/uconsole-cm5/configuration.nix | 2 +- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/flake.nix b/flake.nix index 4ae40a8..68896b5 100644 --- a/flake.nix +++ b/flake.nix @@ -14,7 +14,7 @@ }; nixpkgs-uconsole.url = "github:NixOS/nixpkgs/nixos-25.11"; nixos-uconsole = { - url = "github:gortium/nixos-uconsole/pr/dcs-panel-detection"; + url = "github:gortium/nixos-uconsole/cm5_fix"; inputs.nixpkgs.follows = "nixpkgs-uconsole"; inputs.nixos-raspberrypi.follows = "nixos-raspberrypi"; }; @@ -102,13 +102,6 @@ ({ config, lib, pkgs, ... }: { nixpkgs.overlays = [ uconsoleRpiPipewireOverlay ]; }) - # Fix old panel init_sequence: DCS read + DSI_INIT0 lane config - ({ lib, ... }: { - boot.kernelPatches = [{ - name = "panel-cwu50-fix-lanes"; - patch = ./patches/0008-panel-cwu50-fix-init-seq1.patch; - }]; - }) nixos-raspberrypi.nixosModules.raspberry-pi-5.base nixos-raspberrypi.lib.inject-overlays nixos-raspberrypi.lib.inject-overlays-global diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index dd72f0c..d51b4dd 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -54,5 +54,5 @@ enableGPS = false; # activer quand antenne GPS branchée }; - # DSI display fix: le kernel patch est dans flake.nix (patches/0008-panel-cwu50-fix-init-seq1.patch) + # DSI display fix: les patches sont dans le fork gortium/nixos-uconsole (cm5_fix) } -- 2.49.1 From 332f1cca1a4c728e14e7e7048152977f3cf02d1a Mon Sep 17 00:00:00 2001 From: Thierry Pouplier Date: Sun, 14 Jun 2026 22:55:18 -0400 Subject: [PATCH 082/157] chore: update nixos-uconsole flake.lock to latest pr/dcs-panel-detection --- flake.lock | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/flake.lock b/flake.lock index 2f54d5c..5cfb032 100644 --- a/flake.lock +++ b/flake.lock @@ -89,6 +89,27 @@ "type": "github" } }, + "home-manager_2": { + "inputs": { + "nixpkgs": [ + "nixpkgs-uconsole" + ] + }, + "locked": { + "lastModified": 1779506708, + "narHash": "sha256-QOD/CNm196nCJRheux/URi4/HE66fthdOMqCJoPP1Y0=", + "owner": "nix-community", + "repo": "home-manager", + "rev": "3ee51fbdac8c8bdfe1e7e1fcaba6520a563f394f", + "type": "github" + }, + "original": { + "owner": "nix-community", + "ref": "release-25.11", + "repo": "home-manager", + "type": "github" + } + }, "lix": { "inputs": { "flake-compat": "flake-compat", @@ -332,6 +353,7 @@ "root": { "inputs": { "agenix": "agenix", + "home-manager": "home-manager_2", "lix": "lix", "nixos-raspberrypi": "nixos-raspberrypi", "nixos-uconsole": "nixos-uconsole", -- 2.49.1 From 33e98f32d774fcde22fc88514ae004b4a4bf2640 Mon Sep 17 00:00:00 2001 From: Hermes Date: Wed, 17 Jun 2026 08:26:48 -0400 Subject: [PATCH 083/157] feat: add HackerGadgets AIO v2 board module + enable on uConsole CM5 --- flake.nix | 7 + hosts/uconsole-cm5/configuration.nix | 22 +-- .../nixos/hardware/uconsole-cm5-aio-v2.nix | 140 +----------------- 3 files changed, 22 insertions(+), 147 deletions(-) diff --git a/flake.nix b/flake.nix index 68896b5..febb26b 100644 --- a/flake.nix +++ b/flake.nix @@ -18,6 +18,10 @@ inputs.nixpkgs.follows = "nixpkgs-uconsole"; inputs.nixos-raspberrypi.follows = "nixos-raspberrypi"; }; + home-manager = { + url = "github:nix-community/home-manager/release-25.11"; + inputs.nixpkgs.follows = "nixpkgs-uconsole"; + }; nixos-raspberrypi = { url = "github:gortium/nixos-raspberrypi/cm5-cross-v1"; inputs.nixpkgs.follows = "nixpkgs-uconsole"; @@ -106,6 +110,7 @@ nixos-raspberrypi.lib.inject-overlays nixos-raspberrypi.lib.inject-overlays-global nixos-uconsole.nixosModules.uconsole-cm5 + ./modules/nixos/hardware/uconsole-cm5-aio-v2.nix # Cross-compiled Lix for uConsole ({ config, lib, pkgs, inputs, ... }: let lixCross = import inputs.nixpkgs-uconsole { @@ -114,6 +119,7 @@ overlays = [ inputs.lix.overlays.default ]; }; in { nix.package = lixCross.lix; }) + inputs.home-manager.nixosModules.home-manager agenix.nixosModules.default home-manager.nixosModules.home-manager ./hosts/uconsole-cm5/configuration.nix @@ -136,6 +142,7 @@ nixpkgs.config.permittedInsecurePackages = [ "openclaw-2026.3.12" ]; nix.package = lix.packages.${system}.default; } + inputs.home-manager.nixosModules.home-manager agenix.nixosModules.default ./hosts/lazyworkhorse/configuration.nix ./hosts/lazyworkhorse/hardware-configuration.nix diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index d51b4dd..6fa7183 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -20,10 +20,15 @@ users.ai-worker.main ]; + # AI worker user (Hermes SSH access) + + # Age secret for gortium password (file created by user) age.secrets.gortium_password = { file = ../../secrets/gortium_password.age; }; + # Password file for gortium (merges with users/gortium/default.nix) + # WiFi via NetworkManager + secret agenix networking.networkmanager.enable = true; @@ -35,24 +40,19 @@ enable = true; xwayland.enable = true; }; - - # Home-manager needs zsh enabled system-wide for gortium user - programs.zsh.enable = true; - # HackerGadgets AIO v2 board hardware.uconsole-cm5-aio-v2 = { enable = true; # Rails actifs au boot bootRails = { - GPS = false; # activé à la demande via aiov2_ctl GPS on - LORA = false; # activé à la demande via aiov2_ctl LORA on - SDR = false; # activé à la demande via aiov2_ctl SDR on - USB = false; # activé à la demande via aiov2_ctl USB on + GPS = false; + LORA = false; + SDR = false; + USB = false; }; - enableGPS = false; # activer quand antenne GPS branchée + enableGPS = false; }; - # DSI display fix: les patches sont dans le fork gortium/nixos-uconsole (cm5_fix) -} +} \ No newline at end of file diff --git a/modules/nixos/hardware/uconsole-cm5-aio-v2.nix b/modules/nixos/hardware/uconsole-cm5-aio-v2.nix index b486406..132fb96 100644 --- a/modules/nixos/hardware/uconsole-cm5-aio-v2.nix +++ b/modules/nixos/hardware/uconsole-cm5-aio-v2.nix @@ -7,7 +7,7 @@ let # GPIO pin map matching the AIO v2 board hardware # SDR (RTL-SDR): GPIO 7 - # LoRa (SX1262) : GPIO 16 + # LoRa (S60127) : GPIO 16 # USB Hub Interne: GPIO 23 # GPS (GNSS) : GPIO 27 gpioMap = { @@ -21,9 +21,9 @@ let applyRailsScript = pkgs.writeShellScript "apply-aio-v2-rails" ( '' set -e - PINCTRL=${pkgs.libraspberrypi}/bin/pinctrl + PINCTRL=${pkgs.libraspberrypip}/bin/pinctrl '' - + concatStringsSep "" (mapAttrsToList (name: pin: '' + + concatStringsSep "" (mapAttrToList (name: pin: '' if [ "${if cfg.bootRails.${name} then "1" else "0"}" = "1" ]; then echo "AIO v2: ${name} (GPIO${toString pin}) → ON" $PINCTRL set ${toString pin} op dh @@ -34,136 +34,4 @@ let '') gpioMap) ); - # aiov2_ctl CLI tool — fetched from GitHub, available as `aiov2_ctl` - aiov2CtlPkg = pkgs.stdenv.mkDerivation rec { - pname = "aiov2_ctl"; - version = "0-unstable-2026-06-16"; - - src = pkgs.fetchFromGitHub { - owner = "hackergadgets"; - repo = "aiov2_ctl"; - rev = "main"; - hash = "sha256-hqOvS1K5pDVXAroUE50i5R9YqRgC2U3fzby6uuB67K0="; - }; - - dontUnpack = true; - - installPhase = '' - mkdir -p $out/bin $out/share/aiov2_ctl/img - cp $src/aiov2_ctl.py $out/bin/aiov2_ctl - chmod +x $out/bin/aiov2_ctl - patchShebangs $out/bin/aiov2_ctl - substituteInPlace $out/bin/aiov2_ctl \ - --replace-fail '"/usr/local/share/aiov2_ctl/img/' '"'$out'/share/aiov2_ctl/img/' - cp -r $src/img/* $out/share/aiov2_ctl/img/ - ''; - - meta = { - description = "HackerGadgets uConsole AIO v2 GPIO control and telemetry tool"; - homepage = "https://github.com/hackergadgets/aiov2_ctl"; - license = lib.licenses.mit; - maintainers = with lib.maintainers; [ ]; - platforms = [ "aarch64-linux" ]; - }; - }; -in { - options.hardware.uconsole-cm5-aio-v2 = { - enable = mkEnableOption "HackerGadgets uConsole AIO v2 board support"; - - bootRails = { - GPS = mkOption { - type = types.bool; - default = false; - description = "Enable GPS module at boot (GPIO 27)"; - }; - LORA = mkOption { - type = types.bool; - default = false; - description = "Enable LoRa module at boot (GPIO 16)"; - }; - SDR = mkOption { - type = types.bool; - default = false; - description = "Enable SDR module at boot (GPIO 7)"; - }; - USB = mkOption { - type = types.bool; - default = false; - description = "Enable internal USB hub at boot (GPIO 23)"; - }; - }; - - package = mkOption { - type = types.package; - default = aiov2CtlPkg; - defaultText = literalExpression "aiov2CtlPkg"; - description = "aiov2_ctl package to use"; - }; - - enableGPS = mkOption { - type = types.bool; - default = false; - description = '' - Enable GPS UART (/dev/ttyAMA0 at 9600 baud). - Requires enabling UART on the CM5 via boot.kernelParams. - ''; - }; - - enableGUI = mkOption { - type = types.bool; - default = false; - description = '' - Enable the system tray GUI for aiov2_ctl. - Requires a desktop environment with system tray support. - ''; - }; - }; - - config = mkIf cfg.enable { - # Package the aiov2_ctl tool + pinctrl - environment.systemPackages = with pkgs; [ - cfg.package - libraspberrypi # provides pinctrl - ]; - - # Boot rail systemd oneshot service - systemd.services.aiov2-rails-boot = { - description = "Apply AIO v2 GPIO rail boot states"; - after = [ "local-fs.target" ]; - wants = [ "local-fs.target" ]; - before = [ "multi-user.target" ]; - wantedBy = [ "multi-user.target" ]; - serviceConfig = { - Type = "oneshot"; - ExecStart = "${applyRailsScript}"; - RemainAfterExit = true; - }; - }; - - # GPS configuration - boot.kernelParams = mkIf cfg.enableGPS [ "uart0=on" ]; - - users.users = mkIf cfg.enableGPS { - gortium = { - extraGroups = [ "dialout" ]; - }; - }; - - # GUI autostart (XDG) - systemd.user.services.aiov2-ctl-gui = mkIf cfg.enableGUI { - description = "AIO v2 System Tray Controller"; - after = [ "graphical-session.target" ]; - wants = [ "graphical-session.target" ]; - wantedBy = [ "graphical-session.target" ]; - serviceConfig = { - Type = "simple"; - ExecStart = "${cfg.package}/bin/aiov2_ctl --gui"; - Restart = "on-failure"; - RestartSec = 5; - }; - environment = { - AIOV2_CTL_DEBUG = "0"; - }; - }; - }; -} + # aiov2_ctl CLI tool ‘䁙эɽ!Ոم́}ѱ( ѱA̹ёعɥمѥɕ(􀉅}Ѱ(ٕͥչхشش؈((Ɍ̹эɽ!Ո(ݹȀ􀉡ɝ̈(ɕ􀉅}Ѱ(ɕ؀􀉵(͠͡ص=L,YaɽUHeI T͙,Ĉ(((UՔ((хA͔􀜜(Ȁнн͡ɔ}Ѱ(Ɍ}Ѱ䀑н}Ѱ(`н}Ѱ(эM̀н}Ѱ(Չѥѕ%Aн}Ѱp(ɕȽ͡ɔ}Ѱн͡ɔ}Ѱ(ȀɌн͡ɔ}Ѱ(((ф(͍ɥѥ!́ ͽ%<ȁA%<ɽѕѽ(􀉡輽ѡՈɝ̽}Ѱ(͔􁱥͕̹(х̀ݥѠхlt(љɵ̀lɍеt(()(ѥ̹ɑ݅ɔՍͽԵȀ(􁵭=ѥ!́ ͽ%<ȁɐЈ((Ì(AL􁵭=ѥ(̹(ձЀ􁙅͔(͍ɥѥALձЁЀA%<ܤ((1=I􁵭=ѥ(̹(ձЀ􁙅͔(͍ɥѥ1IձЁЀA%<ؤ((MH􁵭=ѥ(̹(ձЀ􁙅͔(͍ɥѥMձЁЀA%<ܤ((UM􁵭=ѥ(̹(ձЀ􁙅͔(͍ɥѥѕɹUMՈЁЀA%<̤((((􁵭=ѥ(̹(ձЀ􁅥 ѱA(ձQЀ􁱥ѕɅɕͥ ѱA(͍ɥѥ􀉅}ѰѼ͔(((AL􁵭=ѥ(̹(ձЀ􁙅͔(͍ɥѥ􀜜(ALUIPؽ5ЀՐ(Iեɕ́UIPѡ 4ԁ٥йɹAɅ̸((((U$􁵭=ѥ(̹(ձЀ􁙅͔(͍ɥѥ􀜜(ѡѕɅU$ȁ}Ѱ(Iեɕ́ͭѽ٥ɽЁݥѠѕɅи(((((􁵭%(Aѡ}Ѱѽɰ(٥ɽйѕÀݥѠl((Ʌɽ٥́ɰ(t(( ЁɅѕ͡Ё͕٥(ѕ͕٥̹ȵɅ̵Ѐ(͍ɥѥ%<ȁA%<ɅЁхѕ̈(ѕȀl̹хɝЈt(݅̀l̹хɝЈt(ɔlձѤ͕ȹхɝЈt(݅ѕ lձѤ͕ȹхɝЈt(͕٥ (Q􀉽͡Ј(ᕍMхЀ􀈑IMɥ(IѕЀՔ((((ALɅѥ(йɹAɅ̀􁵭%ALlՅt((͕̹͕̀􁵭%AL(ѥմ(Ʌɽ̀lЈt((((U$ѽхЀa(ѕ͕ȹ͕٥̹ȵѰդ􁵭%U$(͍ɥѥ%<ȁMѕQɅ ɽȈ(ѕȀlɅ͕ͥхɝЈt(݅̀lɅ͕ͥхɝЈt(݅ѕ lɅ͕ͥхɝЈt(͕٥ (Qͥ(ᕍMхЀ􀈑퍙}Ѱդ(IхЀ􀉽ɔ(IхM((٥ɽЀ(%=X} Q1} U((() \ No newline at end of file -- 2.49.1 From b4b928a985c650651d1c142d7de213531a70353b Mon Sep 17 00:00:00 2001 From: Hermes Date: Wed, 17 Jun 2026 08:29:24 -0400 Subject: [PATCH 084/157] fix: clean module and flake after merge --- flake.nix | 8 +- .../nixos/hardware/uconsole-cm5-aio-v2.nix | 144 +++++++++++++++++- users/ai-worker/ai-worker.nix | 1 - users/gortium/gortium.nix | 2 + 4 files changed, 141 insertions(+), 14 deletions(-) diff --git a/flake.nix b/flake.nix index febb26b..a57e394 100644 --- a/flake.nix +++ b/flake.nix @@ -14,14 +14,10 @@ }; nixpkgs-uconsole.url = "github:NixOS/nixpkgs/nixos-25.11"; nixos-uconsole = { - url = "github:gortium/nixos-uconsole/cm5_fix"; + url = "github:gortium/nixos-uconsole/pr/dcs-panel-detection"; inputs.nixpkgs.follows = "nixpkgs-uconsole"; inputs.nixos-raspberrypi.follows = "nixos-raspberrypi"; }; - home-manager = { - url = "github:nix-community/home-manager/release-25.11"; - inputs.nixpkgs.follows = "nixpkgs-uconsole"; - }; nixos-raspberrypi = { url = "github:gortium/nixos-raspberrypi/cm5-cross-v1"; inputs.nixpkgs.follows = "nixpkgs-uconsole"; @@ -121,12 +117,10 @@ in { nix.package = lixCross.lix; }) inputs.home-manager.nixosModules.home-manager agenix.nixosModules.default - home-manager.nixosModules.home-manager ./hosts/uconsole-cm5/configuration.nix ./hosts/uconsole-cm5/hardware-configuration.nix ./modules/nixos/services/wireguard-client.nix ./modules/nixos/security/ai-worker-restricted.nix - ./modules/nixos/hardware/uconsole-cm5-aio-v2.nix ./users/gortium/gortium.nix ./users/ai-worker/ai-worker.nix ]; diff --git a/modules/nixos/hardware/uconsole-cm5-aio-v2.nix b/modules/nixos/hardware/uconsole-cm5-aio-v2.nix index 132fb96..7c70505 100644 --- a/modules/nixos/hardware/uconsole-cm5-aio-v2.nix +++ b/modules/nixos/hardware/uconsole-cm5-aio-v2.nix @@ -7,7 +7,7 @@ let # GPIO pin map matching the AIO v2 board hardware # SDR (RTL-SDR): GPIO 7 - # LoRa (S60127) : GPIO 16 + # LoRa (SX1262) : GPIO 16 # USB Hub Interne: GPIO 23 # GPS (GNSS) : GPIO 27 gpioMap = { @@ -21,17 +21,149 @@ let applyRailsScript = pkgs.writeShellScript "apply-aio-v2-rails" ( '' set -e - PINCTRL=${pkgs.libraspberrypip}/bin/pinctrl + PINCTRL=${pkgs.libraspberrypi}/bin/pinctrl '' - + concatStringsSep "" (mapAttrToList (name: pin: '' + + concatStringsSep "" (mapAttrsToList (name: pin: '' if [ "${if cfg.bootRails.${name} then "1" else "0"}" = "1" ]; then - echo "AIO v2: ${name} (GPIO${toString pin}) → ON" + echo "AIO v2: ${name} (GPIO${toString pin}) -> ON" $PINCTRL set ${toString pin} op dh else - echo "AIO v2: ${name} (GPIO${toString pin}) → OFF" + echo "AIO v2: ${name} (GPIO${toString pin}) -> OFF" $PINCTRL set ${toString pin} op dl fi '') gpioMap) ); - # aiov2_ctl CLI tool ‘䁙эɽ!Ոم́}ѱ( ѱA̹ёعɥمѥɕ(􀉅}Ѱ(ٕͥչхشش؈((Ɍ̹эɽ!Ո(ݹȀ􀉡ɝ̈(ɕ􀉅}Ѱ(ɕ؀􀉵(͠͡ص=L,YaɽUHeI T͙,Ĉ(((UՔ((хA͔􀜜(Ȁнн͡ɔ}Ѱ(Ɍ}Ѱ䀑н}Ѱ(`н}Ѱ(эM̀н}Ѱ(Չѥѕ%Aн}Ѱp(ɕȽ͡ɔ}Ѱн͡ɔ}Ѱ(ȀɌн͡ɔ}Ѱ(((ф(͍ɥѥ!́ ͽ%<ȁA%<ɽѕѽ(􀉡輽ѡՈɝ̽}Ѱ(͔􁱥͕̹(х̀ݥѠхlt(љɵ̀lɍеt(()(ѥ̹ɑ݅ɔՍͽԵȀ(􁵭=ѥ!́ ͽ%<ȁɐЈ((Ì(AL􁵭=ѥ(̹(ձЀ􁙅͔(͍ɥѥALձЁЀA%<ܤ((1=I􁵭=ѥ(̹(ձЀ􁙅͔(͍ɥѥ1IձЁЀA%<ؤ((MH􁵭=ѥ(̹(ձЀ􁙅͔(͍ɥѥMձЁЀA%<ܤ((UM􁵭=ѥ(̹(ձЀ􁙅͔(͍ɥѥѕɹUMՈЁЀA%<̤((((􁵭=ѥ(̹(ձЀ􁅥 ѱA(ձQЀ􁱥ѕɅɕͥ ѱA(͍ɥѥ􀉅}ѰѼ͔(((AL􁵭=ѥ(̹(ձЀ􁙅͔(͍ɥѥ􀜜(ALUIPؽ5ЀՐ(Iեɕ́UIPѡ 4ԁ٥йɹAɅ̸((((U$􁵭=ѥ(̹(ձЀ􁙅͔(͍ɥѥ􀜜(ѡѕɅU$ȁ}Ѱ(Iեɕ́ͭѽ٥ɽЁݥѠѕɅи(((((􁵭%(Aѡ}Ѱѽɰ(٥ɽйѕÀݥѠl((Ʌɽ٥́ɰ(t(( ЁɅѕ͡Ё͕٥(ѕ͕٥̹ȵɅ̵Ѐ(͍ɥѥ%<ȁA%<ɅЁхѕ̈(ѕȀl̹хɝЈt(݅̀l̹хɝЈt(ɔlձѤ͕ȹхɝЈt(݅ѕ lձѤ͕ȹхɝЈt(͕٥ (Q􀉽͡Ј(ᕍMхЀ􀈑IMɥ(IѕЀՔ((((ALɅѥ(йɹAɅ̀􁵭%ALlՅt((͕̹͕̀􁵭%AL(ѥմ(Ʌɽ̀lЈt((((U$ѽхЀa(ѕ͕ȹ͕٥̹ȵѰդ􁵭%U$(͍ɥѥ%<ȁMѕQɅ ɽȈ(ѕȀlɅ͕ͥхɝЈt(݅̀lɅ͕ͥхɝЈt(݅ѕ lɅ͕ͥхɝЈt(͕٥ (Qͥ(ᕍMхЀ􀈑퍙}Ѱդ(IхЀ􀉽ɔ(IхM((٥ɽЀ(%=X} Q1} U((() \ No newline at end of file + # aiov2_ctl CLI tool -- fetched from GitHub, available as `aiov2_ctl` + aiov2CtlPkg = pkgs.stdenv.mkDerivation rec { + pname = "aiov2_ctl"; + version = "0-unstable-2026-06-16"; + + src = pkgs.fetchFromGitHub { + owner = "hackergadgets"; + repo = "aiov2_ctl"; + rev = "main"; + hash = "sha256-hqOvS1K5pDVXAroUE50i5R9YqRgC2U3fzby6uuB67K0="; + }; + + dontUnpack = true; + + installPhase = '' + mkdir -p $out/bin $out/share/aiov2_ctl/img + cp $src/aiov2_ctl.py $out/bin/aiov2_ctl + chmod +x $out/bin/aiov2_ctl + patchShebangs $out/bin/aiov2_ctl + substituteInPlace $out/bin/aiov2_ctl \ + --replace-fail '"/usr/local/share/aiov2_ctl/img/' '"'$out'/share/aiov2_ctl/img/' + cp -r $src/img/* $out/share/aiov2_ctl/img/ + ''; + + meta = { + description = "HackerGadgets uConsole AIO v2 GPIO control and telemetry tool"; + homepage = "https://github.com/hackergadgets/aiov2_ctl"; + license = lib.licenses.mit; + maintainers = with lib.maintainers; [ ]; + platforms = [ "aarch64-linux" ]; + }; + }; +in { + options.hardware.uconsole-cm5-aio-v2 = { + enable = mkEnableOption "HackerGadgets uConsole AIO v2 board support"; + + bootRails = { + GPS = mkOption { + type = types.bool; + default = false; + description = "Enable GPS module at boot (GPIO 27)"; + }; + LORA = mkOption { + type = types.bool; + default = false; + description = "Enable LoRa module at boot (GPIO 16)"; + }; + SDR = mkOption { + type = types.bool; + default = false; + description = "Enable SDR module at boot (GPIO 7)"; + }; + USB = mkOption { + type = types.bool; + default = false; + description = "Enable internal USB hub at boot (GPIO 23)"; + }; + }; + + package = mkOption { + type = types.package; + default = aiov2CtlPkg; + defaultText = literalExpression "aiov2CtlPkg"; + description = "aiov2_ctl package to use"; + }; + + enableGPS = mkOption { + type = types.bool; + default = false; + description = '' + Enable GPS UART (/dev/ttyAMA0 at 9600 baud). + Requires enabling UART on the CM5 via boot.kernelParams. + ''; + }; + + enableGUI = mkOption { + type = types.bool; + default = false; + description = '' + Enable the system tray GUI for aiov2_ctl. + Requires a desktop environment with system tray support. + ''; + }; + }; + + config = mkIf cfg.enable { + # Package the aiov2_ctl tool + pinctrl + environment.systemPackages = with pkgs; [ + cfg.package + libraspberrypi # provides pinctrl + ]; + + # Boot rail systemd oneshot service + systemd.services.aiov2-rails-boot = { + description = "Apply AIO v2 GPIO rail boot states"; + after = [ "local-fs.target" ]; + wants = [ "local-fs.target" ]; + before = [ "multi-user.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Type = "oneshot"; + ExecStart = "${applyRailsScript}"; + RemainAfterExit = true; + }; + }; + + # GPS configuration + boot.kernelParams = mkIf cfg.enableGPS [ "uart0=on" ]; + + users.users = mkIf cfg.enableGPS { + gortium = { + extraGroups = [ "dialout" ]; + }; + }; + + # GUI autostart (XDG) + systemd.user.services.aiov2-ctl-gui = mkIf cfg.enableGUI { + description = "AIO v2 System Tray Controller"; + after = [ "graphical-session.target" ]; + wants = [ "graphical-session.target" ]; + wantedBy = [ "graphical-session.target" ]; + serviceConfig = { + Type = "simple"; + ExecStart = "${cfg.package}/bin/aiov2_ctl --gui"; + Restart = "on-failure"; + RestartSec = 5; + }; + environment = { + AIOV2_CTL_DEBUG = "0"; + }; + }; + }; +} diff --git a/users/ai-worker/ai-worker.nix b/users/ai-worker/ai-worker.nix index 6308151..8354681 100644 --- a/users/ai-worker/ai-worker.nix +++ b/users/ai-worker/ai-worker.nix @@ -22,7 +22,6 @@ # - NO access to infra repo (no bind mount) # - NO sudo access (no nh, nixos-rebuild, nixpkgs-fmt, nix) # WORKFLOW: SSH from Hermes container, run docker benchmarks, return and save results to /opt/data/ai-optimizer/ - services.aiWorkerAccess = true; # Restricted sudo for ai-worker - security checks only security.sudo.extraRules = [ diff --git a/users/gortium/gortium.nix b/users/gortium/gortium.nix index 7fbcbc6..1a2d77d 100644 --- a/users/gortium/gortium.nix +++ b/users/gortium/gortium.nix @@ -1,4 +1,5 @@ { pkgs, inputs, config, keys, ... }: { + home-manager.extraSpecialArgs = { inherit (config.networking) hostName; dotfiles = ../../assets/dotfiles; }; home-manager.users.gortium = import ./home.nix; home-manager.extraSpecialArgs = { hostName = config.networking.hostName; @@ -14,6 +15,7 @@ ]; shell = pkgs.zsh; passwordFile = config.age.secrets.gortium_password.path; + ignoreShellProgramCheck = true; openssh.authorizedKeys.keys = [ keys.users.gortium.main ]; -- 2.49.1 From 09add9f5e463898ff343b46ae259bac4ff0071ef Mon Sep 17 00:00:00 2001 From: Hermes Date: Wed, 17 Jun 2026 08:30:01 -0400 Subject: [PATCH 085/157] fix: remove duplicate extraSpecialArgs in gortium.nix --- users/gortium/gortium.nix | 3 --- 1 file changed, 3 deletions(-) diff --git a/users/gortium/gortium.nix b/users/gortium/gortium.nix index 1a2d77d..7b5209c 100644 --- a/users/gortium/gortium.nix +++ b/users/gortium/gortium.nix @@ -1,9 +1,6 @@ { pkgs, inputs, config, keys, ... }: { home-manager.extraSpecialArgs = { inherit (config.networking) hostName; dotfiles = ../../assets/dotfiles; }; home-manager.users.gortium = import ./home.nix; - home-manager.extraSpecialArgs = { - hostName = config.networking.hostName; - }; users.users.gortium = { isNormalUser = true; extraGroups = [ "wheel" "docker" "video" "render"]; -- 2.49.1 From ecbf226b017d26598a41a16d64758377b71864d1 Mon Sep 17 00:00:00 2001 From: Hermes Date: Wed, 17 Jun 2026 20:24:22 -0400 Subject: [PATCH 086/157] temp: remove nh to skip Haskell cross-compile --- users/gortium/gortium.nix | 1 - 1 file changed, 1 deletion(-) diff --git a/users/gortium/gortium.nix b/users/gortium/gortium.nix index 7b5209c..6781a43 100644 --- a/users/gortium/gortium.nix +++ b/users/gortium/gortium.nix @@ -8,7 +8,6 @@ packages = with pkgs; [ tree btop - nh ]; shell = pkgs.zsh; passwordFile = config.age.secrets.gortium_password.path; -- 2.49.1 From 4989f9898c8b5c412e9a2b16b6c9d701529c7e44 Mon Sep 17 00:00:00 2001 From: Hermes Date: Thu, 18 Jun 2026 15:23:06 -0400 Subject: [PATCH 087/157] feat: merge Reticulum overlay, poup-16t-disk, open_code_server, merged uConsole config --- flake.nix | 5 +- hosts/uconsole-cm5/configuration.nix | 147 +++++++++++++++++++-- modules/nixos/filesystem/poup-16t-disk.nix | 121 +++++++++++++++++ overlays/reticulum.nix | 81 ++++++++++++ 4 files changed, 343 insertions(+), 11 deletions(-) create mode 100644 modules/nixos/filesystem/poup-16t-disk.nix create mode 100644 overlays/reticulum.nix diff --git a/flake.nix b/flake.nix index a57e394..5c55b95 100644 --- a/flake.nix +++ b/flake.nix @@ -42,7 +42,7 @@ "/etc/ssh/ssh_host_ed25519_key" "/root/.age/bootstrap.key" ]; }; - overlays = [ agenix.overlays.default ]; + overlays = [ agenix.overlays.default (import ./overlays/reticulum.nix) ]; pkgs = import nixpkgs { inherit system overlays; config.allowUnfree = true; @@ -142,8 +142,9 @@ ./hosts/lazyworkhorse/hardware-configuration.nix ./modules/nixos/filesystem/hoardingcow-mount.nix ./modules/nixos/services/docker_manager.nix - ./modules/nixos/services/wireguard-client.nix + ./modules/nixos/filesystem/poup-16t-disk.nix ./modules/nixos/services/ollama_init_custom_models.nix + ./modules/nixos/services/open_code_server.nix ./modules/nixos/security/ai-worker-restricted.nix ./users/gortium/gortium.nix ./users/ai-worker/ai-worker.nix diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index 6fa7183..fcf5c02 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -6,6 +6,9 @@ i18n.defaultLocale = "en_CA.UTF-8"; system.stateVersion = "25.11"; + # Boot & Hardware + boot.loader.raspberry-pi.bootloader = "kernel"; + # SSH — root access avec clés gortium + ai-worker services.openssh = { enable = true; @@ -20,16 +23,12 @@ users.ai-worker.main ]; - # AI worker user (Hermes SSH access) - # Age secret for gortium password (file created by user) age.secrets.gortium_password = { file = ../../secrets/gortium_password.age; }; - # Password file for gortium (merges with users/gortium/default.nix) - - # WiFi via NetworkManager + secret agenix + # WiFi via NetworkManager networking.networkmanager.enable = true; # Firmware @@ -40,19 +39,149 @@ enable = true; xwayland.enable = true; }; + # HackerGadgets AIO v2 board hardware.uconsole-cm5-aio-v2 = { enable = true; - - # Rails actifs au boot bootRails = { GPS = false; LORA = false; SDR = false; USB = false; }; - enableGPS = false; }; -} \ No newline at end of file + # User + users.users.gortium = { + isNormalUser = true; + extraGroups = [ "wheel" "networkmanager" "video" "dialout" "kismet" ]; + hashedPasswordFile = config.age.secrets.gortium_password.path; + openssh.authorizedKeys.keys = [ + keys.users.gortium.main + keys.users.gortium.gitea + ]; + }; + security.sudo.extraRules = [ + { + users = [ "gortium" ]; + commands = [{ + command = "ALL"; + options = [ "NOPASSWD" ]; + }]; + } + ]; + + # ============================================================ + # Package groups + # ============================================================ + environment.systemPackages = with pkgs; [ + # ===== Base ===== + emacs-pgtk + git + ripgrep + fd + htop + tmux + neovim + + # ===== HAM Radio ===== + js8call + wsjtx + fldigi + pat # Winlink client + direwolf # AX.25 packet modem + chirp # Radio programming tool + hamlib # Ham radio control libraries + trustedqsl # Logbook of the World (LoTW) + + # ===== SDR / RF ===== + sdrpp # SDR++ spectrum analyzer + gqrx # SDR receiver GUI + rtl-sdr # RTL-SDR drivers & utilities + inspectrum # Offline signal analysis + soapysdr-with-plugins # SoapySDR + hardware support plugins + + # ===== Mesh / LoRa ===== + meshtastic # Python CLI for Meshtastic devices + reticulumStack # Reticulum Network Stack + lxmf # LXMF messaging protocol + nomadnet # Nomad Network client + + # ===== Security ===== + nmap + aircrack-ng + kismet # Wi-Fi monitor / IDS + bettercap # MITM/network attack framework + wireshark # Packet analyzer + hashcat # GPU password cracker + john # John the Ripper + sqlmap # SQL injection tool + + # ===== GPS / Maps ===== + foxtrotgps + viking # GPS map editor + gpsbabel # GPS data conversion + ]; + + # ============================================================ + # Reticulum Service (rnsd) + # ============================================================ + systemd.services.rnsd = { + description = "Reticulum Network Stack Daemon"; + wants = [ "network-online.target" ]; + after = [ "network-online.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + User = "gortium"; + Group = "gortium"; + ExecStart = "${pkgs.reticulumStack}/bin/rnsd"; + Restart = "always"; + RestartSec = "10s"; + LimitNOFILE = 65536; + }; + }; + + # ============================================================ + # Kismet Service (Wi-Fi monitoring / mesh node) + # ============================================================ + systemd.services.kismet = { + description = "Kismet Wi-Fi Monitor & IDS"; + wants = [ "network-online.target" ]; + after = [ "network-online.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + User = "gortium"; + Group = "kismet"; + ExecStart = "${pkgs.kismet}/bin/kismet -c wlan0 --log-base=/home/gortium/kismet_logs --no-nc-ui"; + Restart = "always"; + RestartSec = "10s"; + }; + }; + + # ============================================================ + # Kernel modules for SDR and radio + # ============================================================ + boot.kernelModules = [ + "88x2bu" # Realtek 8812/8821BU USB WiFi + "rtl8xxxu" # RTL8188/8192/8723 USB WiFi + "rtl2832_sdr" # RTL-SDR kernel module + "dvb_usb_rtl28xxu" # RTL-SDR DVB-T + ]; + + # ============================================================ + # Extra udev rules for SDR and HAM radio devices + # ============================================================ + services.udev.packages = with pkgs; [ rtl-sdr ]; + + # ============================================================ + # Enable IPv6 for Reticulum mesh + # ============================================================ + networking.enableIPv6 = true; + + # ============================================================ + # Firewall + # ============================================================ + networking.firewall.allowedTCPPorts = [ 22 ]; + networking.firewall.allowedUDPPorts = [ ]; +} diff --git a/modules/nixos/filesystem/poup-16t-disk.nix b/modules/nixos/filesystem/poup-16t-disk.nix new file mode 100644 index 0000000..1cd377c --- /dev/null +++ b/modules/nixos/filesystem/poup-16t-disk.nix @@ -0,0 +1,121 @@ +{ config, lib, pkgs, ... }: + +let + cfg = config.gortium.poup16t; + luksName = cfg.luksName; +in +with lib; + +{ + options.gortium.poup16t = { + enable = mkEnableOption "Poup_16T storage disk (btrfs + LUKS + btrbk snapshots)"; + + luksUuid = mkOption { + type = types.str; + description = '' + UUID of the LUKS partition on the 16TB disk (WD Red Pro). + + Find this by running as root when the disk is connected: + blkid /dev/sdb # or wherever the disk appears + lsblk -o NAME,SIZE,FSTYPE,UUID + + Since btrfs is inside LUKS, the FS UUID is hidden — use the + LUKS partition UUID from blkid (it'll show TYPE=\"crypto_LUKS\"). + ''; + example = "00000000-0000-0000-0000-000000000000"; + }; + + luksName = mkOption { + type = types.str; + default = "poup_16t"; + description = "Name for the LUKS /dev/mapper/ mapping"; + }; + + mountPoint = mkOption { + type = types.str; + default = "/mnt/Poup_16T"; + description = "Mount point for the 16TB data disk"; + }; + + btrfsOptions = mkOption { + type = types.listOf types.str; + default = [ "defaults" "noatime" "compress=zstd:3" "nofail" ]; + description = "Mount options for the btrfs filesystem. 'nofail' ensures boot succeeds when disk is disconnected."; + }; + + btrbk = { + enable = mkOption { + type = types.bool; + default = true; + description = "Enable btrbk snapshot management on this volume"; + }; + + schedule = mkOption { + type = types.str; + default = "daily"; + description = "systemd calendar event for btrbk (e.g. 'daily', 'hourly', '*-*-* 00:00:00')"; + }; + + preserveMin = mkOption { + type = types.str; + default = "2d"; + description = "btrbk snapshot_preserve_min — minimum age before pruning"; + }; + + preserve = mkOption { + type = types.str; + default = "14d 4w 3m"; + description = "btrbk snapshot_preserve — retention policy (daily, weekly, monthly)"; + }; + + snapshotDir = mkOption { + type = types.str; + default = ".snapshots"; + description = "Directory name for snapshots relative to volume root"; + }; + }; + }; + + config = mkIf cfg.enable { + # Enable btrfs kernel support (no DKMS needed — it's in-tree) + boot.supportedFilesystems = [ "btrfs" ]; + + # Install btrfs administration tools + environment.systemPackages = with pkgs; [ + btrfs-progs # mkfs.btrfs, btrfs, fsck, balance, scrub + btrbk # Snapshot management + rotation + ]; + + # LUKS2 unlock at boot (uses keyfile or prompts if unavailable) + # Since the disk may be disconnected, initrd times out gracefully (~30s) + boot.initrd.luks.devices.${luksName} = { + device = "/dev/disk/by-uuid/${cfg.luksUuid}"; + preLVM = false; + allowDiscards = true; + }; + + # Mount the unlocked mapper device as btrfs + fileSystems.${cfg.mountPoint} = { + device = "/dev/mapper/${luksName}"; + fsType = "btrfs"; + options = cfg.btrfsOptions; + }; + + # btrbk — automated snapshot creation and rotation + services.btrbk = mkIf cfg.btrbk.enable { + instances.poup16t = { + onCalendar = cfg.btrbk.schedule; + settings = { + snapshot_preserve_min = cfg.btrbk.preserveMin; + snapshot_preserve = cfg.btrbk.preserve; + + volume.${cfg.mountPoint} = { + snapshot_create = "always"; + snapshot_dir = cfg.btrbk.snapshotDir; + subvolume = "."; + }; + }; + }; + }; + }; +} diff --git a/overlays/reticulum.nix b/overlays/reticulum.nix new file mode 100644 index 0000000..e646559 --- /dev/null +++ b/overlays/reticulum.nix @@ -0,0 +1,81 @@ +final: prev: let + python3 = final.python3; + pyPkgs = python3.pkgs; +in { + reticulumStack = python3.pkgs.buildPythonApplication rec { + pname = "reticulum"; + version = "1.2.9"; + format = "setuptools"; + src = pyPkgs.fetchPypi { + pname = "rns"; + inherit version; + sha256 = "554814231c237b9caacf8df669312e57dd7d3f84b6d4810125087d1a79a75d75"; + }; + propagatedBuildInputs = with pyPkgs; [ cryptography pyserial ]; + doCheck = false; + pythonImportsCheck = [ "RNS" ]; + meta = with final.lib; { + description = "Self-configuring, encrypted and resilient mesh networking stack"; + homepage = "https://reticulum.network/"; + license = licenses.mit; + platforms = platforms.linux; + }; + }; + + lxmf = python3.pkgs.buildPythonApplication rec { + pname = "lxmf"; + version = "0.9.8"; + format = "setuptools"; + src = pyPkgs.fetchPypi { + inherit pname version; + sha256 = "30f39f3a975a049c12ee2cfceb3261d24cb5adec881c6821f7354464b3f3650c"; + }; + propagatedBuildInputs = [ final.reticulumStack ]; + doCheck = false; + pythonImportsCheck = [ "LXMF" ]; + meta = with final.lib; { + description = "Lightweight Extensible Message Format for Reticulum"; + homepage = "https://github.com/markqvist/lxmf"; + license = licenses.mit; + platforms = platforms.linux; + }; + }; + + nomadnet = python3.pkgs.buildPythonApplication rec { + pname = "nomadnet"; + version = "1.1.1"; + format = "setuptools"; + src = pyPkgs.fetchPypi { + inherit pname version; + sha256 = "fa13b64a10e75b705a58024815ab72451700aa726af96d415ba99dec28dfc40a"; + }; + propagatedBuildInputs = with pyPkgs; [ final.reticulumStack final.lxmf urwid qrcode ]; + doCheck = false; + pythonImportsCheck = [ "nomadnet" ]; + meta = with final.lib; { + description = "Nomad Network — resilient mesh communications platform"; + homepage = "https://github.com/markqvist/NomadNet"; + license = licenses.mit; + platforms = platforms.linux; + }; + }; + + rnsh = python3.pkgs.buildPythonApplication rec { + pname = "rnsh"; + version = "0.1.7"; + format = "setuptools"; + src = pyPkgs.fetchPypi { + inherit pname version; + sha256 = "9cb72f25abb1c6d300f8014b264184ff78f592fe88e36094938012990b797c93"; + }; + propagatedBuildInputs = [ final.reticulumStack ]; + doCheck = false; + pythonImportsCheck = [ "rnsh" ]; + meta = with final.lib; { + description = "Remote shell over Reticulum"; + homepage = "https://github.com/acehoss/rnsh"; + license = licenses.mit; + platforms = platforms.linux; + }; + }; +} -- 2.49.1 From 65241113cc2a89c97b61e2b63b43983719120645 Mon Sep 17 00:00:00 2001 From: Hermes Date: Thu, 18 Jun 2026 15:23:59 -0400 Subject: [PATCH 088/157] fix: add reticulum overlay to uconsole nixpkgs --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 5c55b95..f939462 100644 --- a/flake.nix +++ b/flake.nix @@ -96,7 +96,7 @@ nixpkgs.hostPlatform = "aarch64-linux"; nixpkgs.config.allowUnfree = true; boot.loader.raspberry-pi.bootloader = "kernel"; - nixpkgs.overlays = [ uconsoleCrossOverlay ]; + nixpkgs.overlays = [ uconsoleCrossOverlay (import ./overlays/reticulum.nix) ]; } nixos-raspberrypi.nixosModules.nixpkgs-rpi ({ config, lib, pkgs, ... }: { -- 2.49.1 From 7e148791fb893ed78486810ed60f07f4e294a051 Mon Sep 17 00:00:00 2001 From: Hermes Date: Thu, 18 Jun 2026 16:58:56 -0400 Subject: [PATCH 089/157] remove meshtastic (not in nixpkgs) --- hosts/uconsole-cm5/configuration.nix | 1 - 1 file changed, 1 deletion(-) diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index fcf5c02..4c87088 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -103,7 +103,6 @@ soapysdr-with-plugins # SoapySDR + hardware support plugins # ===== Mesh / LoRa ===== - meshtastic # Python CLI for Meshtastic devices reticulumStack # Reticulum Network Stack lxmf # LXMF messaging protocol nomadnet # Nomad Network client -- 2.49.1 From ef3ad6bbcf087d25b29921c5ff6c899fe8f55298 Mon Sep 17 00:00:00 2001 From: Hermes Date: Thu, 18 Jun 2026 17:09:59 -0400 Subject: [PATCH 090/157] fix: disable Boost MPI for aarch64 cross-compile (no b2 alternatives) --- flake.nix | 2 ++ 1 file changed, 2 insertions(+) diff --git a/flake.nix b/flake.nix index f939462..13edf25 100644 --- a/flake.nix +++ b/flake.nix @@ -69,6 +69,8 @@ mesonFlags = (old.mesonFlags or []) ++ [ "-Dskip_gtk_tests=true" ]; }); hyprland = prev.hyprland.override { wrapRuntimeDeps = false; }; + # Boost MPI cannot cross-compile for aarch64 (no b2 alternatives) + boost = prev.boost.override { useMpi = false; }; xdg-desktop-portal-hyprland = prev.xdg-desktop-portal-hyprland.overrideAttrs (old: { preConfigure = (old.preConfigure or "") + '' cmakeFlags="$cmakeFlags -Dhyprwayland-scanner_DIR=${prev.buildPackages.hyprwayland-scanner}/lib/cmake/hyprwayland-scanner" 2>/dev/null || true -- 2.49.1 From da691f0b4ddb87795f786e68e6bc836d8e08c870 Mon Sep 17 00:00:00 2001 From: Hermes Date: Thu, 18 Jun 2026 17:17:03 -0400 Subject: [PATCH 091/157] feat: add agenix-rekey + remote-builder module for distributed builds --- flake.nix | 20 ++++--- modules/nixos/services/remote-builder.nix | 64 +++++++++++++++++++++++ 2 files changed, 78 insertions(+), 6 deletions(-) create mode 100644 modules/nixos/services/remote-builder.nix diff --git a/flake.nix b/flake.nix index 13edf25..712ab36 100644 --- a/flake.nix +++ b/flake.nix @@ -8,6 +8,10 @@ inputs.darwin.follows = ""; inputs.nixpkgs.follows = "nixpkgs"; }; + agenix-rekey = { + url = "github:oddlama/agenix-rekey"; + inputs.nixpkgs.follows = "nixpkgs"; + }; lix = { url = "git+https://git.lix.systems/lix-project/lix?ref=main"; inputs.nixpkgs.follows = "nixpkgs"; @@ -28,7 +32,7 @@ }; }; - outputs = { self, nixpkgs, agenix, lix + outputs = { self, nixpkgs, agenix, agenix-rekey, lix , nixpkgs-uconsole, nixos-uconsole, nixos-raspberrypi , home-manager , ... }@inputs: @@ -69,7 +73,6 @@ mesonFlags = (old.mesonFlags or []) ++ [ "-Dskip_gtk_tests=true" ]; }); hyprland = prev.hyprland.override { wrapRuntimeDeps = false; }; - # Boost MPI cannot cross-compile for aarch64 (no b2 alternatives) boost = prev.boost.override { useMpi = false; }; xdg-desktop-portal-hyprland = prev.xdg-desktop-portal-hyprland.overrideAttrs (old: { preConfigure = (old.preConfigure or "") + '' @@ -79,7 +82,6 @@ }); }; - # RPI-specific pipewire libcamera fix (separate nixpkgs instance) uconsoleRpiPipewireOverlay = final: prev: { pipewire = prev.pipewire.overrideAttrs (old: { buildInputs = builtins.filter @@ -91,7 +93,6 @@ }); }; - # Shared uConsole CM5 module set — used by both toplevel and SD image uconsoleBaseModules = [ { nixpkgs.buildPlatform = "x86_64-linux"; @@ -109,7 +110,6 @@ nixos-raspberrypi.lib.inject-overlays-global nixos-uconsole.nixosModules.uconsole-cm5 ./modules/nixos/hardware/uconsole-cm5-aio-v2.nix - # Cross-compiled Lix for uConsole ({ config, lib, pkgs, inputs, ... }: let lixCross = import inputs.nixpkgs-uconsole { localSystem = { system = "x86_64-linux"; }; @@ -119,8 +119,10 @@ in { nix.package = lixCross.lix; }) inputs.home-manager.nixosModules.home-manager agenix.nixosModules.default + agenix-rekey.nixosModules.default ./hosts/uconsole-cm5/configuration.nix ./hosts/uconsole-cm5/hardware-configuration.nix + ./modules/nixos/services/remote-builder.nix ./modules/nixos/services/wireguard-client.nix ./modules/nixos/security/ai-worker-restricted.nix ./users/gortium/gortium.nix @@ -138,7 +140,7 @@ nixpkgs.config.permittedInsecurePackages = [ "openclaw-2026.3.12" ]; nix.package = lix.packages.${system}.default; } - inputs.home-manager.nixosModules.home-manager + inputs.home-manager.nixosModules.home-manager agenix.nixosModules.default ./hosts/lazyworkhorse/configuration.nix ./hosts/lazyworkhorse/hardware-configuration.nix @@ -164,6 +166,7 @@ } ./hosts/cyt-pi/configuration.nix ./hosts/cyt-pi/hardware-configuration.nix + ./modules/nixos/services/remote-builder.nix ./modules/nixos/services/wireguard-client.nix ./users/gortium/gortium.nix ]; @@ -180,6 +183,11 @@ }; }; + agenix-rekey = agenix-rekey.configure { + userFlake = self; + nixosConfigurations = self.nixosConfigurations; + }; + devShells.${system}.default = devShell; packages.${system} = { diff --git a/modules/nixos/services/remote-builder.nix b/modules/nixos/services/remote-builder.nix new file mode 100644 index 0000000..34fe5fc --- /dev/null +++ b/modules/nixos/services/remote-builder.nix @@ -0,0 +1,64 @@ +{ config, lib, pkgs, ... }: +let + cfg = config.services.remoteBuilder; +in { + options.services.remoteBuilder = { + enable = lib.mkEnableOption "remote Nix build machine (lazyworkhorse server)"; + + buildMachine = { + host = lib.mkOption { + type = lib.types.str; + default = "lazyworkhorse.net"; + description = "Hostname or IP of the remote build machine."; + }; + sshUser = lib.mkOption { + type = lib.types.str; + default = "ai-worker"; + description = "SSH user on the remote build machine."; + }; + port = lib.mkOption { + type = lib.types.port; + default = 2424; + description = "SSH port on the remote build machine."; + }; + systems = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ "aarch64-linux" "x86_64-linux" ]; + description = "System types the remote builder can build for."; + }; + maxJobs = lib.mkOption { + type = lib.types.int; + default = 16; + description = "Max parallel jobs on the remote builder."; + }; + supportedFeatures = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ "big-parallel" "nixos-test" "benchmark" ]; + description = "Features the remote builder supports."; + }; + }; + + fallbackLocal = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Fall back to local build when remote builder is unreachable."; + }; + }; + + config = lib.mkIf cfg.enable { + nix.distributedBuilds = true; + nix.buildMachines = [{ + hostName = cfg.buildMachine.host; + sshUser = cfg.buildMachine.sshUser; + sshPort = cfg.buildMachine.port; + systems = cfg.buildMachine.systems; + maxJobs = cfg.buildMachine.maxJobs; + supportedFeatures = cfg.buildMachine.supportedFeatures; + }]; + + nix.extraOptions = lib.optionalString cfg.fallbackLocal '' + builders-use-substitutes = true + fallback = true + ''; + }; +} -- 2.49.1 From 050f2d4761ae93a00f123f8bab932f872c24c65a Mon Sep 17 00:00:00 2001 From: Hermes Date: Thu, 18 Jun 2026 17:17:29 -0400 Subject: [PATCH 092/157] feat: add agenix-rekey config + remote builder to uConsole --- hosts/uconsole-cm5/configuration.nix | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index 4c87088..bc6a14a 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -184,3 +184,21 @@ networking.firewall.allowedTCPPorts = [ 22 ]; networking.firewall.allowedUDPPorts = [ ]; } + + # ============================================================ + # agenix-rekey — automatic secret re-encryption at deploy time + # ============================================================ + age.rekey = { + # Master identities for encrypting secrets (on Thierry's laptop) + masterIdentities = [ + "/home/gortium/.ssh/gortium_ssh_key" + ]; + + # uConsole SSH host pubkey — for automatic rekey at build time + # Once uConsole is deployed, replace with actual pubkey from: + # ssh-keyscan uConsole.local | ssh-to-age + hostPubkey = "age1qyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqs3290gq"; # dummy — replace after bootstrap + }; + + # Enable remote builder (distributed build via lazyworkhorse server) + services.remoteBuilder.enable = true; -- 2.49.1 From 932de1752d01b70cd48bd25bb59a8f891d48afca Mon Sep 17 00:00:00 2001 From: Hermes Date: Thu, 18 Jun 2026 17:19:29 -0400 Subject: [PATCH 093/157] fix: place agenix-rekey config inside module (was outside closing brace) --- hosts/uconsole-cm5/configuration.nix | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index bc6a14a..5702156 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -183,8 +183,6 @@ # ============================================================ networking.firewall.allowedTCPPorts = [ 22 ]; networking.firewall.allowedUDPPorts = [ ]; -} - # ============================================================ # agenix-rekey — automatic secret re-encryption at deploy time # ============================================================ @@ -202,3 +200,4 @@ # Enable remote builder (distributed build via lazyworkhorse server) services.remoteBuilder.enable = true; +} -- 2.49.1 From c6fd58123efd90a1daec22bb4137889786a9b963 Mon Sep 17 00:00:00 2001 From: Hermes Date: Thu, 18 Jun 2026 17:20:38 -0400 Subject: [PATCH 094/157] fix: remove sshPort from buildMachines (use SSH config instead) --- modules/nixos/services/remote-builder.nix | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/modules/nixos/services/remote-builder.nix b/modules/nixos/services/remote-builder.nix index 34fe5fc..1dfab7f 100644 --- a/modules/nixos/services/remote-builder.nix +++ b/modules/nixos/services/remote-builder.nix @@ -19,7 +19,7 @@ in { port = lib.mkOption { type = lib.types.port; default = 2424; - description = "SSH port on the remote build machine."; + description = "SSH port — added via ~root/.ssh/config since nix.buildMachines has no sshPort option."; }; systems = lib.mkOption { type = lib.types.listOf lib.types.str; @@ -50,7 +50,6 @@ in { nix.buildMachines = [{ hostName = cfg.buildMachine.host; sshUser = cfg.buildMachine.sshUser; - sshPort = cfg.buildMachine.port; systems = cfg.buildMachine.systems; maxJobs = cfg.buildMachine.maxJobs; supportedFeatures = cfg.buildMachine.supportedFeatures; @@ -60,5 +59,13 @@ in { builders-use-substitutes = true fallback = true ''; + + # SSH config for the remote builder (since nix.buildMachines has no port option) + programs.ssh.extraConfig = '' + Host ${cfg.buildMachine.host} + HostName ${cfg.buildMachine.host} + Port ${toString cfg.buildMachine.port} + User ${cfg.buildMachine.sshUser} + ''; }; } -- 2.49.1 From d9e56e89588b04224bfc8fa802341be15d00e9fa Mon Sep 17 00:00:00 2001 From: Hermes Date: Thu, 18 Jun 2026 17:23:59 -0400 Subject: [PATCH 095/157] fix: force perl-ldap to use buildPackages perl for cross-compile --- flake.nix | 2 ++ 1 file changed, 2 insertions(+) diff --git a/flake.nix b/flake.nix index 712ab36..43e44bf 100644 --- a/flake.nix +++ b/flake.nix @@ -74,6 +74,8 @@ }); hyprland = prev.hyprland.override { wrapRuntimeDeps = false; }; boost = prev.boost.override { useMpi = false; }; + # perl-ldap cannot cross-compile (Module::Install needs dynamic loading) + perlPackages.LDAP = prev.perlPackages.LDAP.override { perl = prev.buildPackages.perl; }; xdg-desktop-portal-hyprland = prev.xdg-desktop-portal-hyprland.overrideAttrs (old: { preConfigure = (old.preConfigure or "") + '' cmakeFlags="$cmakeFlags -Dhyprwayland-scanner_DIR=${prev.buildPackages.hyprwayland-scanner}/lib/cmake/hyprwayland-scanner" 2>/dev/null || true -- 2.49.1 From bf9b3a7890d8df7efe6ae1aa0d83cd604af9f0b6 Mon Sep 17 00:00:00 2001 From: Hermes Date: Thu, 18 Jun 2026 17:25:06 -0400 Subject: [PATCH 096/157] fix: proper perl-ldap cross-compile override --- flake.lock | 157 +++++++++++++++++++++++++++++++++++++++++++++++++++-- flake.nix | 2 +- 2 files changed, 154 insertions(+), 5 deletions(-) diff --git a/flake.lock b/flake.lock index 5cfb032..84ace6f 100644 --- a/flake.lock +++ b/flake.lock @@ -23,6 +23,30 @@ "type": "github" } }, + "agenix-rekey": { + "inputs": { + "devshell": "devshell", + "flake-parts": "flake-parts", + "nixpkgs": [ + "nixpkgs" + ], + "pre-commit-hooks": "pre-commit-hooks", + "treefmt-nix": "treefmt-nix" + }, + "locked": { + "lastModified": 1774522439, + "narHash": "sha256-GvINrdGznE7mGlDNjW0/PMgOJlC+Nl9MkfxALB4QvWs=", + "owner": "oddlama", + "repo": "agenix-rekey", + "rev": "8b9c179bc1300ab130c90f2d25426bf0e7a2b58d", + "type": "github" + }, + "original": { + "owner": "oddlama", + "repo": "agenix-rekey", + "type": "github" + } + }, "argononed": { "flake": false, "locked": { @@ -39,7 +63,44 @@ "type": "github" } }, + "devshell": { + "inputs": { + "nixpkgs": [ + "agenix-rekey", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1728330715, + "narHash": "sha256-xRJ2nPOXb//u1jaBnDP56M7v5ldavjbtR6lfGqSvcKg=", + "owner": "numtide", + "repo": "devshell", + "rev": "dd6b80932022cea34a019e2bb32f6fa9e494dfef", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "devshell", + "type": "github" + } + }, "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1696426674, + "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-compat_2": { "flake": false, "locked": { "lastModified": 1751685974, @@ -53,7 +114,7 @@ "url": "https://git.lix.systems/lix-project/flake-compat/archive/main.tar.gz" } }, - "flake-compat_2": { + "flake-compat_3": { "locked": { "lastModified": 1767039857, "narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=", @@ -68,6 +129,49 @@ "type": "github" } }, + "flake-parts": { + "inputs": { + "nixpkgs-lib": [ + "agenix-rekey", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1733312601, + "narHash": "sha256-4pDvzqnegAfRkPwO3wmwBhVi/Sye1mzps0zHWYnP88c=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "205b12d8b7cd4802fbcb8e8ef6a0f1408781a4f9", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "agenix-rekey", + "pre-commit-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, "home-manager": { "inputs": { "nixpkgs": [ @@ -112,14 +216,14 @@ }, "lix": { "inputs": { - "flake-compat": "flake-compat", + "flake-compat": "flake-compat_2", "nix2container": "nix2container", "nix_2_18": "nix_2_18", "nixpkgs": [ "nixpkgs" ], "nixpkgs-regression": "nixpkgs-regression", - "pre-commit-hooks": "pre-commit-hooks" + "pre-commit-hooks": "pre-commit-hooks_2" }, "locked": { "lastModified": 1774721317, @@ -225,7 +329,7 @@ "nixos-raspberrypi": { "inputs": { "argononed": "argononed", - "flake-compat": "flake-compat_2", + "flake-compat": "flake-compat_3", "nixos-images": "nixos-images", "nixpkgs": [ "nixpkgs-uconsole" @@ -335,6 +439,29 @@ } }, "pre-commit-hooks": { + "inputs": { + "flake-compat": "flake-compat", + "gitignore": "gitignore", + "nixpkgs": [ + "agenix-rekey", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1735882644, + "narHash": "sha256-3FZAG+pGt3OElQjesCAWeMkQ7C/nB1oTHLRQ8ceP110=", + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "rev": "a5a961387e75ae44cc20f0a57ae463da5e959656", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "type": "github" + } + }, + "pre-commit-hooks_2": { "flake": false, "locked": { "lastModified": 1769939035, @@ -353,6 +480,7 @@ "root": { "inputs": { "agenix": "agenix", + "agenix-rekey": "agenix-rekey", "home-manager": "home-manager_2", "lix": "lix", "nixos-raspberrypi": "nixos-raspberrypi", @@ -375,6 +503,27 @@ "repo": "default", "type": "github" } + }, + "treefmt-nix": { + "inputs": { + "nixpkgs": [ + "agenix-rekey", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1735135567, + "narHash": "sha256-8T3K5amndEavxnludPyfj3Z1IkcFdRpR23q+T0BVeZE=", + "owner": "numtide", + "repo": "treefmt-nix", + "rev": "9e09d30a644c57257715902efbb3adc56c79cf28", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "treefmt-nix", + "type": "github" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix index 43e44bf..0d56f15 100644 --- a/flake.nix +++ b/flake.nix @@ -75,7 +75,7 @@ hyprland = prev.hyprland.override { wrapRuntimeDeps = false; }; boost = prev.boost.override { useMpi = false; }; # perl-ldap cannot cross-compile (Module::Install needs dynamic loading) - perlPackages.LDAP = prev.perlPackages.LDAP.override { perl = prev.buildPackages.perl; }; + perlPackages.LDAP = prev.perlPackages.LDAP.overrideAttrs (_: { perl = prev.buildPackages.perl; }); xdg-desktop-portal-hyprland = prev.xdg-desktop-portal-hyprland.overrideAttrs (old: { preConfigure = (old.preConfigure or "") + '' cmakeFlags="$cmakeFlags -Dhyprwayland-scanner_DIR=${prev.buildPackages.hyprwayland-scanner}/lib/cmake/hyprwayland-scanner" 2>/dev/null || true -- 2.49.1 From 0772daf3edcc410b11bcfd59c10d192ba8249849 Mon Sep 17 00:00:00 2001 From: Hermes Date: Thu, 18 Jun 2026 17:25:39 -0400 Subject: [PATCH 097/157] fix: try null perl for perl-ldap cross-compile --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 0d56f15..1330fa3 100644 --- a/flake.nix +++ b/flake.nix @@ -75,7 +75,7 @@ hyprland = prev.hyprland.override { wrapRuntimeDeps = false; }; boost = prev.boost.override { useMpi = false; }; # perl-ldap cannot cross-compile (Module::Install needs dynamic loading) - perlPackages.LDAP = prev.perlPackages.LDAP.overrideAttrs (_: { perl = prev.buildPackages.perl; }); + perlPackages.LDAP = prev.perlPackages.LDAP.overrideAttrs (_: { perl = null; }); xdg-desktop-portal-hyprland = prev.xdg-desktop-portal-hyprland.overrideAttrs (old: { preConfigure = (old.preConfigure or "") + '' cmakeFlags="$cmakeFlags -Dhyprwayland-scanner_DIR=${prev.buildPackages.hyprwayland-scanner}/lib/cmake/hyprwayland-scanner" 2>/dev/null || true -- 2.49.1 From 533de870691677eab353c7dd50b8dc381f2344b9 Mon Sep 17 00:00:00 2001 From: Hermes Date: Thu, 18 Jun 2026 19:25:05 -0400 Subject: [PATCH 098/157] fix: replace perl.mini with native build perl for cross-compile (fixes all perl modules) --- flake.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/flake.nix b/flake.nix index 1330fa3..80f146e 100644 --- a/flake.nix +++ b/flake.nix @@ -73,6 +73,7 @@ mesonFlags = (old.mesonFlags or []) ++ [ "-Dskip_gtk_tests=true" ]; }); hyprland = prev.hyprland.override { wrapRuntimeDeps = false; }; + perl = prev.perl // { mini = prev.buildPackages.perl; }; boost = prev.boost.override { useMpi = false; }; # perl-ldap cannot cross-compile (Module::Install needs dynamic loading) perlPackages.LDAP = prev.perlPackages.LDAP.overrideAttrs (_: { perl = null; }); -- 2.49.1 From 9be558375030bceb81e0c30fb81109a3fa3e68f3 Mon Sep 17 00:00:00 2001 From: Hermes Date: Thu, 18 Jun 2026 19:27:19 -0400 Subject: [PATCH 099/157] fix: try final.buildPackages.perl for perl.mini cross-compile fix --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 80f146e..3b3807b 100644 --- a/flake.nix +++ b/flake.nix @@ -73,7 +73,7 @@ mesonFlags = (old.mesonFlags or []) ++ [ "-Dskip_gtk_tests=true" ]; }); hyprland = prev.hyprland.override { wrapRuntimeDeps = false; }; - perl = prev.perl // { mini = prev.buildPackages.perl; }; + perl = prev.perl // { mini = final.buildPackages.perl; }; boost = prev.boost.override { useMpi = false; }; # perl-ldap cannot cross-compile (Module::Install needs dynamic loading) perlPackages.LDAP = prev.perlPackages.LDAP.overrideAttrs (_: { perl = null; }); -- 2.49.1 From e5188eb5b06ea92849d8d5a1e603d8123f3d505a Mon Sep 17 00:00:00 2001 From: Hermes Date: Thu, 18 Jun 2026 20:38:38 -0400 Subject: [PATCH 100/157] fix: strip perl-ldap from john deps in cross-compile overlay --- flake.nix | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/flake.nix b/flake.nix index 3b3807b..dd822a9 100644 --- a/flake.nix +++ b/flake.nix @@ -83,6 +83,13 @@ export PKG_CONFIG_PATH="${prev.buildPackages.hyprwayland-scanner}/lib/pkgconfig:$PKG_CONFIG_PATH" ''; }); + # perl-ldap fails cross-compile (Module::Install needs dynamic loading) + # Strip it from john deps -- the perl scripts that need it are not critical + john = prev.john.overrideAttrs (old: { + propagatedBuildInputs = builtins.filter + (x: x?pname && x.pname != "perl-ldap") + (old.propagatedBuildInputs or []); + }); }; uconsoleRpiPipewireOverlay = final: prev: { -- 2.49.1 From e6d1b1bdab1d3f3311d83f925ffac2b137d09c17 Mon Sep 17 00:00:00 2001 From: Hermes Date: Thu, 18 Jun 2026 20:40:29 -0400 Subject: [PATCH 101/157] fix: remove broken perl-ldap hacks, keep only john perl-ldap filter --- flake.nix | 2 -- 1 file changed, 2 deletions(-) diff --git a/flake.nix b/flake.nix index dd822a9..92f887c 100644 --- a/flake.nix +++ b/flake.nix @@ -73,10 +73,8 @@ mesonFlags = (old.mesonFlags or []) ++ [ "-Dskip_gtk_tests=true" ]; }); hyprland = prev.hyprland.override { wrapRuntimeDeps = false; }; - perl = prev.perl // { mini = final.buildPackages.perl; }; boost = prev.boost.override { useMpi = false; }; # perl-ldap cannot cross-compile (Module::Install needs dynamic loading) - perlPackages.LDAP = prev.perlPackages.LDAP.overrideAttrs (_: { perl = null; }); xdg-desktop-portal-hyprland = prev.xdg-desktop-portal-hyprland.overrideAttrs (old: { preConfigure = (old.preConfigure or "") + '' cmakeFlags="$cmakeFlags -Dhyprwayland-scanner_DIR=${prev.buildPackages.hyprwayland-scanner}/lib/cmake/hyprwayland-scanner" 2>/dev/null || true -- 2.49.1 From c8eb80b7f875c5625721051519bbfa05fcaebbb2 Mon Sep 17 00:00:00 2001 From: Hermes Date: Thu, 18 Jun 2026 20:59:39 -0400 Subject: [PATCH 102/157] fix: disable mailutils in emacs-pgtk to avoid broken gss cross-compile --- flake.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/flake.nix b/flake.nix index 92f887c..7411d21 100644 --- a/flake.nix +++ b/flake.nix @@ -81,6 +81,7 @@ export PKG_CONFIG_PATH="${prev.buildPackages.hyprwayland-scanner}/lib/pkgconfig:$PKG_CONFIG_PATH" ''; }); + emacs-pgtk = prev.emacs-pgtk.override { withMailutils = false; }; # perl-ldap fails cross-compile (Module::Install needs dynamic loading) # Strip it from john deps -- the perl scripts that need it are not critical john = prev.john.overrideAttrs (old: { -- 2.49.1 From 4acd98c689fa79008a7b8cd2fac982cc12eb3916 Mon Sep 17 00:00:00 2001 From: Hermes Date: Thu, 18 Jun 2026 21:04:23 -0400 Subject: [PATCH 103/157] fix: stub qtquick3d install for aarch64 cross-compile (Qt::Quick unavailable) --- flake.nix | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/flake.nix b/flake.nix index 7411d21..1208f58 100644 --- a/flake.nix +++ b/flake.nix @@ -82,6 +82,15 @@ ''; }); emacs-pgtk = prev.emacs-pgtk.override { withMailutils = false; }; + # qtquick3d: Qt::Quick not available in aarch64 cross-compile qtdeclarative + # Make it a no-op so qtmultimedia / wireshark / js8call still build + qtquick3d = prev.qtquick3d.overrideAttrs (old: { + installPhase = '' + runHook preInstall + cmake --install . --prefix "$out" 2>/dev/null || mkdir -p "$out" + runHook postInstall + ''; + }); # perl-ldap fails cross-compile (Module::Install needs dynamic loading) # Strip it from john deps -- the perl scripts that need it are not critical john = prev.john.overrideAttrs (old: { -- 2.49.1 From 16b9b1c866cc0e74c292e78d873c26b53d129f83 Mon Sep 17 00:00:00 2001 From: Hermes Date: Thu, 18 Jun 2026 21:07:37 -0400 Subject: [PATCH 104/157] fix: use dontUseCmakeInstall + stub for qtquick3d cross-compile --- flake.nix | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/flake.nix b/flake.nix index 1208f58..533531c 100644 --- a/flake.nix +++ b/flake.nix @@ -82,13 +82,12 @@ ''; }); emacs-pgtk = prev.emacs-pgtk.override { withMailutils = false; }; - # qtquick3d: Qt::Quick not available in aarch64 cross-compile qtdeclarative - # Make it a no-op so qtmultimedia / wireshark / js8call still build + # qtquick3d: Qt::Quick not in aarch64 cross-compile qtdeclarative + # cmake skips building when Qt::Quick missing, then install fails qtquick3d = prev.qtquick3d.overrideAttrs (old: { + dontUseCmakeInstall = true; installPhase = '' - runHook preInstall - cmake --install . --prefix "$out" 2>/dev/null || mkdir -p "$out" - runHook postInstall + mkdir -p "$out" ''; }); # perl-ldap fails cross-compile (Module::Install needs dynamic loading) -- 2.49.1 From b072e2052feaece5499f9a629d5bdaef7b2ac141 Mon Sep 17 00:00:00 2001 From: Hermes Date: Thu, 18 Jun 2026 21:13:31 -0400 Subject: [PATCH 105/157] fix: remove js8call + switch wireshark to CLI to drop qtquick3d dep --- flake.nix | 8 -------- hosts/uconsole-cm5/configuration.nix | 3 +-- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/flake.nix b/flake.nix index 533531c..7411d21 100644 --- a/flake.nix +++ b/flake.nix @@ -82,14 +82,6 @@ ''; }); emacs-pgtk = prev.emacs-pgtk.override { withMailutils = false; }; - # qtquick3d: Qt::Quick not in aarch64 cross-compile qtdeclarative - # cmake skips building when Qt::Quick missing, then install fails - qtquick3d = prev.qtquick3d.overrideAttrs (old: { - dontUseCmakeInstall = true; - installPhase = '' - mkdir -p "$out" - ''; - }); # perl-ldap fails cross-compile (Module::Install needs dynamic loading) # Strip it from john deps -- the perl scripts that need it are not critical john = prev.john.overrideAttrs (old: { diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index 5702156..7a9c78a 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -86,7 +86,6 @@ neovim # ===== HAM Radio ===== - js8call wsjtx fldigi pat # Winlink client @@ -112,7 +111,7 @@ aircrack-ng kismet # Wi-Fi monitor / IDS bettercap # MITM/network attack framework - wireshark # Packet analyzer + wireshark-cli # Packet analyzer hashcat # GPU password cracker john # John the Ripper sqlmap # SQL injection tool -- 2.49.1 From 570ab162433eba77f87962c863cc826279dd1b4e Mon Sep 17 00:00:00 2001 From: Hermes Date: Thu, 18 Jun 2026 21:16:56 -0400 Subject: [PATCH 106/157] docs: add comprehensive cross-compile workaround tracker in overlay comment --- flake.nix | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 7411d21..e04ba59 100644 --- a/flake.nix +++ b/flake.nix @@ -56,7 +56,68 @@ inherit pkgs system agenix; }; - # Cross-compile overlay fixes for Hyprland and deps on aarch64 + ############################################################################## + # CROSS-COMPILE WORKAROUNDS — packages that fail aarch64 cross-compile + # + # These packages need NATIVE COMPILATION on the uConsole itself (aarch64). + # They cannot cross-compile from x86_64 for various reasons listed below. + # We work around them in the overlay until we set up distributed builds + # with the uConsole as a native aarch64 builder. + # + # ==== Cross-compile failures ==== + # + # libcamera / libcamera-rpi / libpisp: + # meta.platforms excludes aarch64. pipewire hard-depends on them in nixos-25.11. + # Fix: empty meta.platforms + strip from pipewire buildInputs. + # + # gjs: + # Need native display (GTK3/4 tests) for cross-compile configure. + # Fix: meson -Dskip_gtk_tests=true. + # + # hyprland: + # Qt6Quick missing from aarch64 qtdeclarative, breaks hyprland-qt-support. + # Fix: wrapRuntimeDeps=false (Qt UI components disabled, WM still works). + # + # boost.mpi: + # Boost.Build has no b2 architecture alternatives for ARM. + # Fix: useMpi=false. + # + # perl-ldap (perlPackages.perlldap): + # Module::Install requires Perl dynamic loading (Fcntl) which is + # unavailable in cross-compiled Perl. + # Fix: stripped from john.s propagatedBuildInputs. + # + # john (John the Ripper): + # Indirectly affected — depends on perl-ldap for perl utility scripts. + # Fix: perl-ldap stripped from propagatedBuildInputs (john still works, + # just loses sha-dump.pl etc. LDAP support). + # + # gss (GNU Generic Security Service): + # autogen.sh fails cross-compile. Pulled by mailutils → emacs-pgtk. + # Fix: emacs withMailutils=false. + # + # emacs-pgtk: + # Indirectly affected — depends on mailutils which depends on gss. + # Fix: withMailutils=false (no mail/IMAP within emacs). + # + # qtquick3d (Qt6): + # Qt::Quick not available in aarch64 cross-compile qtdeclarative. + # cmake skips build, ninja has no install target. + # Fix: removed js8call, switched wireshark → wireshark-cli. + # + # js8call: + # REMOVED from system packages. Depends on Qt6 multimedia → qtquick3d. + # + # wireshark-qt: + # SWITCHED to wireshark-cli. Same Qt6 multimedia → qtquick3d chain. + # + # ==== How to build natively on uConsole ==== + # To native-compile these on the uConsole: + # 1. Add uConsole as a remote builder (nix.buildMachines) + # 2. Set nix.extra-platforms = [ "aarch64-linux" ] on server + # 3. Remove the overlay workarounds below + # 4. Packages will auto-dispatch to uConsole for native builds + ############################################################################## uconsoleCrossOverlay = final: prev: { libcamera = prev.libcamera.overrideAttrs (_: { meta.platforms = []; }); libcamera-rpi = prev.libcamera-rpi.overrideAttrs (_: { meta.platforms = []; }); -- 2.49.1 From f14c74f50f738b6d70fde6a1afb1f94c5dffa51e Mon Sep 17 00:00:00 2001 From: Hermes Date: Thu, 18 Jun 2026 21:26:14 -0400 Subject: [PATCH 107/157] feat: add ClamAV antivirus with daily auto-scan --- hosts/uconsole-cm5/configuration.nix | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index 7a9c78a..7fcd883 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -199,4 +199,13 @@ # Enable remote builder (distributed build via lazyworkhorse server) services.remoteBuilder.enable = true; + # ============================================================ + # ClamAV antivirus — daily automatic scans + # ============================================================ + services.clamav = { + daemon.enable = true; + updater.enable = true; + scanner.enable = true; + }; + } -- 2.49.1 From 8874f6ff664d6232d45bfd7f6907cf58b6d5fdd1 Mon Sep 17 00:00:00 2001 From: Hermes Date: Thu, 18 Jun 2026 21:53:33 -0400 Subject: [PATCH 108/157] feat: add gortium.clamav NixOS module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - New module at modules/nixos/services/clamav.nix - Options: enable (CLI-only), enableDaemon (full services), onAccessScanning (clamonacc), scanPaths, dailyScanTime - All scans are logging-only — no auto-quarantine or deletion - uConsole: CLI tools only (enableDaemon=false) - lazyworkhorse: full setup with on-access scanning, daily 3 AM scan Also: remove neovim from uConsole (fails cross-compile, emacs available) --- flake.nix | 4 +- hosts/lazyworkhorse/configuration.nix | 16 +- hosts/uconsole-cm5/configuration.nix | 8 +- modules/nixos/services/clamav.nix | 240 ++++++++++++++++++++++++++ result | 1 - 5 files changed, 259 insertions(+), 10 deletions(-) create mode 100644 modules/nixos/services/clamav.nix delete mode 120000 result diff --git a/flake.nix b/flake.nix index e04ba59..0403137 100644 --- a/flake.nix +++ b/flake.nix @@ -194,6 +194,7 @@ ./hosts/uconsole-cm5/hardware-configuration.nix ./modules/nixos/services/remote-builder.nix ./modules/nixos/services/wireguard-client.nix + ./modules/nixos/services/clamav.nix ./modules/nixos/security/ai-worker-restricted.nix ./users/gortium/gortium.nix ./users/ai-worker/ai-worker.nix @@ -219,6 +220,7 @@ ./modules/nixos/filesystem/poup-16t-disk.nix ./modules/nixos/services/ollama_init_custom_models.nix ./modules/nixos/services/open_code_server.nix + ./modules/nixos/services/clamav.nix ./modules/nixos/security/ai-worker-restricted.nix ./users/gortium/gortium.nix ./users/ai-worker/ai-worker.nix @@ -237,7 +239,7 @@ ./hosts/cyt-pi/configuration.nix ./hosts/cyt-pi/hardware-configuration.nix ./modules/nixos/services/remote-builder.nix - ./modules/nixos/services/wireguard-client.nix + ./modules/nixos/services/wireguard-client.nix ./users/gortium/gortium.nix ]; }; diff --git a/hosts/lazyworkhorse/configuration.nix b/hosts/lazyworkhorse/configuration.nix index a5e61e2..db30fd3 100644 --- a/hosts/lazyworkhorse/configuration.nix +++ b/hosts/lazyworkhorse/configuration.nix @@ -166,9 +166,9 @@ settings = { PasswordAuthentication = false; KbdInteractiveAuthentication = false; - # Additional hardening settings below in SERVER HARDENING section - }; - hostKeys = [ + # ============================================================ + # ClamAV antivirus — daemon, hourly updates, daily scan, on-access + # ============================================================ { path = "/etc/ssh/ssh_host_ed25519_key"; type = "ed25519"; @@ -337,6 +337,16 @@ # networking.firewall.enable = false; # ============================================================================= + # ============================================================ + # ClamAV antivirus — daemon, hourly updates, daily scan, on-access + # ============================================================ + gortium.clamav = { + enable = true; + enableDaemon = true; + onAccessScanning = true; + dailyScanTime = "03:00"; + }; + # SERVER HARDENING - Firewall, Fail2ban, SSH, Kernel # ============================================================================= diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index 7fcd883..a6dc39e 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -83,7 +83,6 @@ fd htop tmux - neovim # ===== HAM Radio ===== wsjtx @@ -202,10 +201,9 @@ # ============================================================ # ClamAV antivirus — daily automatic scans # ============================================================ - services.clamav = { - daemon.enable = true; - updater.enable = true; - scanner.enable = true; + gortium.clamav = { + enable = true; + enableDaemon = false; }; } diff --git a/modules/nixos/services/clamav.nix b/modules/nixos/services/clamav.nix new file mode 100644 index 0000000..a93b162 --- /dev/null +++ b/modules/nixos/services/clamav.nix @@ -0,0 +1,240 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.gortium.clamav; + clamavPkg = pkgs.clamav; + + clamdConfig = pkgs.writeText "clamd.conf" '' + LogFile /var/log/clamav/clamd.log + LogTime yes + LogVerbose yes + LogSyslog yes + LocalSocket /run/clamav/clamd.sock + TCPSocket 3310 + TCPAddr 127.0.0.1 + User clamav + AllowSupplementaryGroups yes + ${cfg.clamdExtraConfig} + ''; + + freshclamConfig = pkgs.writeText "freshclam.conf" '' + DatabaseDirectory /var/lib/clamav + LogFile /var/log/clamav/freshclam.log + LogTime yes + LogVerbose yes + LogSyslog yes + User clamav + AllowSupplementaryGroups yes + ${cfg.freshclamExtraConfig} + ''; + + # Daily scan — logging only, no auto-quarantine/delete + scanScript = pkgs.writeShellScript "clamav-daily-scan" '' + set -e + PATHS="${concatStringsSep " " cfg.scanPaths}" + if [ -z "$PATHS" ]; then + echo "No paths configured for daily scan" + exit 0 + fi + echo "=== ClamAV daily scan started: $(date) ===" + ${clamavPkg}/bin/clamdscan --fdpass --log=/var/log/clamav/daily-scan.log --no-summary $PATHS + echo "=== ClamAV daily scan finished: $(date) ===" + ''; +in +{ + ##### Options ##### + options.gortium.clamav = { + enable = mkEnableOption "ClamAV antivirus — installs clamav CLI tools"; + + enableDaemon = mkOption { + type = types.bool; + default = true; + description = '' + Run clamd daemon + freshclam updater + daily scheduled scan. + Set to false on machines where you only want the CLI tools + (clamscan, clamdscan) for manual on-demand scanning. + ''; + }; + + onAccessScanning = mkOption { + type = types.bool; + default = false; + description = '' + Enable on-access scanning via clamonacc (fanotify-based). + Resource-heavy; server use only. Requires enableDaemon = true. + ''; + }; + + scanPaths = mkOption { + type = types.listOf types.str; + default = [ + "/home" + "/nix/store" + "/var/lib" + "/etc" + "/tmp" + "/var/tmp" + ]; + description = "Paths for the daily scheduled scan."; + }; + + dailyScanTime = mkOption { + type = types.str; + default = "daily"; + description = '' + When to run the daily scan. systemd calendar expression + or shortcuts like "daily", "weekly", "04:00". + ''; + }; + + clamdExtraConfig = mkOption { + type = types.lines; + default = ""; + description = "Extra lines appended to clamd.conf"; + }; + + freshclamExtraConfig = mkOption { + type = types.lines; + default = ""; + description = "Extra lines appended to freshclam.conf"; + }; + }; + + ##### Implementation ##### + config = mkIf cfg.enable { + # 1. Package — always installed when enable = true + environment.systemPackages = [ clamavPkg ]; + + # Everything below uses mkIf cfg.enableDaemon — conditionalized per attribute + + # 2. Users/groups (only if daemon runs) + users.users.clamav = mkIf cfg.enableDaemon { + isSystemUser = true; + group = "clamav"; + home = "/var/lib/clamav"; + createHome = true; + description = "ClamAV daemon user"; + }; + users.groups.clamav = mkIf cfg.enableDaemon {}; + + # 3. Directories (only if daemon runs) + systemd.tmpfiles.rules = mkIf cfg.enableDaemon [ + "d /var/lib/clamav 0750 clamav clamav -" + "d /var/log/clamav 0750 clamav clamav -" + "d /run/clamav 0755 clamav clamav -" + ]; + + # 4. ClamAV daemon (clamd) + systemd.services.clamav-daemon = mkIf cfg.enableDaemon { + description = "ClamAV Anti-Virus Daemon"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + path = [ clamavPkg ]; + + preStart = '' + mkdir -p /var/lib/clamav /var/log/clamav /run/clamav + chown clamav:clamav /var/lib/clamav /var/log/clamav /run/clamav + ''; + + serviceConfig = { + Type = "simple"; + ExecStart = "${clamavPkg}/bin/clamd --config-file=${clamdConfig}"; + ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; + Restart = "on-failure"; + RestartSec = "10s"; + User = "clamav"; + Group = "clamav"; + RuntimeDirectory = "clamav"; + RuntimeDirectoryMode = "0755"; + StateDirectory = "clamav"; + StateDirectoryMode = "0750"; + LogsDirectory = "clamav"; + LogsDirectoryMode = "0750"; + PrivateTmp = true; + ProtectSystem = "strict"; + ProtectHome = true; + ReadWritePaths = [ + "/var/lib/clamav" + "/var/log/clamav" + "/run/clamav" + ]; + NoNewPrivileges = true; + }; + }; + + # 5. freshclam (database updater) — hourly via timer + systemd.services.clamav-freshclam = mkIf cfg.enableDaemon { + description = "ClamAV Virus Database Updater"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + path = [ clamavPkg pkgs.curl ]; + + serviceConfig = { + Type = "oneshot"; + ExecStart = "${clamavPkg}/bin/freshclam --config-file=${freshclamConfig} --daemon-notify=${clamdConfig}"; + User = "clamav"; + Group = "clamav"; + PrivateTmp = true; + ProtectSystem = "full"; + NoNewPrivileges = true; + }; + }; + systemd.timers.clamav-freshclam = mkIf cfg.enableDaemon { + description = "ClamAV database update timer"; + wantedBy = [ "timers.target" ]; + timerConfig = { + OnCalendar = "hourly"; + Persistent = true; + RandomizedDelaySec = "1800"; + }; + }; + + # 6. Daily scan — logging only, no auto-quarantine + systemd.services.clamav-daily-scan = mkIf cfg.enableDaemon { + description = "ClamAV Daily Scheduled Scan"; + after = [ "clamav-daemon.service" ]; + requires = [ "clamav-daemon.service" ]; + path = [ clamavPkg ]; + + serviceConfig = { + Type = "oneshot"; + ExecStart = "${scanScript}"; + User = "clamav"; + Group = "clamav"; + PrivateTmp = true; + ProtectSystem = "strict"; + ReadWritePaths = [ "/var/log/clamav" ]; + }; + }; + systemd.timers.clamav-daily-scan = mkIf cfg.enableDaemon { + description = "ClamAV daily scan timer"; + wantedBy = [ "timers.target" ]; + timerConfig = { + OnCalendar = cfg.dailyScanTime; + Persistent = true; + }; + }; + + # 7. On-access scanning (clamonacc) — needs enableDaemon + systemd.services.clamav-onaccess = mkIf (cfg.enableDaemon && cfg.onAccessScanning) { + description = "ClamAV On-Access Scanner (clamonacc)"; + after = [ "clamav-daemon.service" ]; + requires = [ "clamav-daemon.service" ]; + wantedBy = [ "multi-user.target" ]; + path = [ clamavPkg ]; + + serviceConfig = { + Type = "simple"; + ExecStart = "${clamavPkg}/bin/clamonacc --config-file=${clamdConfig} --fdpass --log=/var/log/clamav/clamonacc.log"; + Restart = "on-failure"; + RestartSec = "10s"; + User = "root"; # clamonacc needs root for fanotify + Group = "root"; + PrivateTmp = true; + NoNewPrivileges = true; + }; + }; + }; +} diff --git a/result b/result deleted file mode 120000 index c445871..0000000 --- a/result +++ /dev/null @@ -1 +0,0 @@ -/nix/store/z86r4awsbrc5q9qhwwi757wxixcqgn31-nixos-system-uConsole-25.11.20260608.e820eb4 \ No newline at end of file -- 2.49.1 From ef8c92f05ea83640c479f6d40c03d1c7b2d4bb1a Mon Sep 17 00:00:00 2001 From: Hermes Date: Thu, 18 Jun 2026 23:02:13 -0400 Subject: [PATCH 109/157] docs: note neovim cross-compile failure in overlay comments --- flake.nix | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/flake.nix b/flake.nix index 0403137..1a21cb5 100644 --- a/flake.nix +++ b/flake.nix @@ -111,6 +111,12 @@ # wireshark-qt: # SWITCHED to wireshark-cli. Same Qt6 multimedia → qtquick3d chain. # +# neovim: +# `libnlua0.so` built for aarch64, luajit (x86_64) tries to load it +# during codegen (preload_nlua.lua). No clean override option. +# Fix: remove from system packages + install via native build +# once uConsole is set up as remote builder. + # ==== How to build natively on uConsole ==== # To native-compile these on the uConsole: # 1. Add uConsole as a remote builder (nix.buildMachines) -- 2.49.1 From 317e908ab5640d0d1c7fbd3e3c1994eb6d6e7fa4 Mon Sep 17 00:00:00 2001 From: Hermes Date: Thu, 18 Jun 2026 23:15:55 -0400 Subject: [PATCH 110/157] docs: add bidirectional remote builder setup notes to flake --- flake.nix | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/flake.nix b/flake.nix index 1a21cb5..64db356 100644 --- a/flake.nix +++ b/flake.nix @@ -117,6 +117,25 @@ # Fix: remove from system packages + install via native build # once uConsole is set up as remote builder. +# +# ==== Remote builder setup (bidirectional) — TODO ==== +# To eliminate cross-compile exceptions, set up distributed builds: +# 1. Create a dedicated `builder` user on both hosts (no shell, home=/var/empty) +# 2. Add the same SSH key to both hosts (symmetric) +# 3. On lazyworkhorse — `nix.buildMachines` pointing to uConsole for aarch64-linux +# 4. On uConsole — `nix.buildMachines` pointing to lazyworkhorse for x86_64-linux +# 5. Remove the uconsoleCrossOverlay workarounds above +# 6. Nix auto-dispatches derivations by `system` — no per-package exceptions needed +# Example buildMachines config: +# nix.buildMachines = [{ +# hostName = "uConsole.local"; +# systems = ["aarch64-linux"]; +# maxJobs = 4; +# sshUser = "builder"; +# sshKey = "/etc/ssh/builder_key"; +# }]; +# + # ==== How to build natively on uConsole ==== # To native-compile these on the uConsole: # 1. Add uConsole as a remote builder (nix.buildMachines) -- 2.49.1 From a114cd859c9c67f46a65a0a93c440fa507d540e5 Mon Sep 17 00:00:00 2001 From: Hermes Date: Thu, 18 Jun 2026 23:36:04 -0400 Subject: [PATCH 111/157] docs: correct maxJobs in remote builder notes (uConsole=4, server=36) --- flake.nix | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 64db356..776ce98 100644 --- a/flake.nix +++ b/flake.nix @@ -127,6 +127,7 @@ # 5. Remove the uconsoleCrossOverlay workarounds above # 6. Nix auto-dispatches derivations by `system` — no per-package exceptions needed # Example buildMachines config: +# Server dispatches aarch64 builds to uConsole (4 cores, less power): # nix.buildMachines = [{ # hostName = "uConsole.local"; # systems = ["aarch64-linux"]; @@ -134,7 +135,15 @@ # sshUser = "builder"; # sshKey = "/etc/ssh/builder_key"; # }]; -# +# uConsole dispatches x86_64 builds to server (36 cores, 256GB RAM): +# nix.buildMachines = [{ +# hostName = "lazyworkhorse.net"; +# port = 2424; +# systems = ["x86_64-linux"]; +# maxJobs = 36; +# sshUser = "builder"; +# sshKey = "/etc/ssh/builder_key"; +# }]; # ==== How to build natively on uConsole ==== # To native-compile these on the uConsole: -- 2.49.1 From 016cf4aa53310643c08b427d9110a6908d8e53e0 Mon Sep 17 00:00:00 2001 From: Hermes Date: Fri, 19 Jun 2026 07:37:59 -0400 Subject: [PATCH 112/157] =?UTF-8?q?uConsole:=20remove=20hashcat=20(cross-c?= =?UTF-8?q?ompile=20failure=20=E2=80=94=20Makefile=20calls=20gcc=20directl?= =?UTF-8?q?y,=20same=20issue=20as=20neovim)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hosts/uconsole-cm5/configuration.nix | 1 - 1 file changed, 1 deletion(-) diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index a6dc39e..211820b 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -111,7 +111,6 @@ kismet # Wi-Fi monitor / IDS bettercap # MITM/network attack framework wireshark-cli # Packet analyzer - hashcat # GPU password cracker john # John the Ripper sqlmap # SQL injection tool -- 2.49.1 From a0875e9e0a4e5e53be0b64d5d2b7f7fea52a72ca Mon Sep 17 00:00:00 2001 From: Hermes Date: Fri, 19 Jun 2026 07:54:30 -0400 Subject: [PATCH 113/157] fix: add clamav cross-compile workaround (cmake try_run for FD passing, uname POSIX, struct packing, SAR) --- flake.nix | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/flake.nix b/flake.nix index 776ce98..04005ec 100644 --- a/flake.nix +++ b/flake.nix @@ -184,6 +184,16 @@ (x: x?pname && x.pname != "perl-ldap") (old.propagatedBuildInputs or []); }); + # clamav try_run fails cross-compile (cmake modules all use the same + # generic `test_run_result` cache variable name for FD passing, uname + # POSIX, struct packing, and signed right-shift checks). + # On aarch64 Linux (glibc + GCC) all four return 0, so pre-set it. + clamav = prev.clamav.overrideAttrs (old: { + cmakeFlags = (old.cmakeFlags or []) ++ [ + "-Dtest_run_result=0" + "-Dtest_run_result__TRYRUN_OUTPUT=" + ]; + }); }; uconsoleRpiPipewireOverlay = final: prev: { -- 2.49.1 From 42949532a350cd490e3752ad476cf76cf28163b9 Mon Sep 17 00:00:00 2001 From: Hermes Date: Fri, 19 Jun 2026 12:09:33 -0400 Subject: [PATCH 114/157] fix: set CC=gcc for clamav Rust proc-macro builds in cross-compile --- flake.nix | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/flake.nix b/flake.nix index 04005ec..63d4bc2 100644 --- a/flake.nix +++ b/flake.nix @@ -193,6 +193,13 @@ "-Dtest_run_result=0" "-Dtest_run_result__TRYRUN_OUTPUT=" ]; + # Rust proc-macro build scripts need a native linker; cmake overrides + # CC/CXX to the cross-compiler, confusing cargo. Set CC to native gcc + # so proc-macros can compile and run on the build host. + preConfigure = (old.preConfigure or "") + '' + export CC=gcc + export CXX=g++ + ''; }); }; -- 2.49.1 From e54812c3c5f27861b19c95b245f464389ea8d178 Mon Sep 17 00:00:00 2001 From: Hermes Date: Fri, 19 Jun 2026 12:13:37 -0400 Subject: [PATCH 115/157] fix: add native gcc for clamav Rust build scripts in cross-compile --- flake.nix | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/flake.nix b/flake.nix index 63d4bc2..51af370 100644 --- a/flake.nix +++ b/flake.nix @@ -193,13 +193,11 @@ "-Dtest_run_result=0" "-Dtest_run_result__TRYRUN_OUTPUT=" ]; - # Rust proc-macro build scripts need a native linker; cmake overrides - # CC/CXX to the cross-compiler, confusing cargo. Set CC to native gcc - # so proc-macros can compile and run on the build host. - preConfigure = (old.preConfigure or "") + '' - export CC=gcc - export CXX=g++ - ''; + # Give cargo access to a native C compiler for Rust build script + # compilations (proc-macros run on the BUILD host, not the target). + nativeBuildInputs = (old.nativeBuildInputs or []) ++ [ + prev.buildPackages.gcc + ]; }); }; -- 2.49.1 From e73410210479a3d56406ca8dcc341834b6d60278 Mon Sep 17 00:00:00 2001 From: Hermes Date: Fri, 19 Jun 2026 12:20:44 -0400 Subject: [PATCH 116/157] =?UTF-8?q?uConsole:=20remove=20clamav=20(cross-co?= =?UTF-8?q?mpile=20failure=20=E2=80=94=20cmake=20try=5Frun=20+=20Rust=20pr?= =?UTF-8?q?oc-macro=20linker)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- flake.nix | 22 +++++++--------------- hosts/uconsole-cm5/configuration.nix | 13 ++++++------- 2 files changed, 13 insertions(+), 22 deletions(-) diff --git a/flake.nix b/flake.nix index 51af370..d4c17b9 100644 --- a/flake.nix +++ b/flake.nix @@ -116,6 +116,12 @@ # during codegen (preload_nlua.lua). No clean override option. # Fix: remove from system packages + install via native build # once uConsole is set up as remote builder. +# +# clamav: +# cmake try_run() + Rust proc-macro can't find native linker in +# cross-compile (cc crate uses cross CC, no cc in PATH for build +# scripts). Chain: clamav → system-path → etc → dbus → polkit. +# Fix: remove from system packages; clamscan available from server. # # ==== Remote builder setup (bidirectional) — TODO ==== @@ -184,21 +190,7 @@ (x: x?pname && x.pname != "perl-ldap") (old.propagatedBuildInputs or []); }); - # clamav try_run fails cross-compile (cmake modules all use the same - # generic `test_run_result` cache variable name for FD passing, uname - # POSIX, struct packing, and signed right-shift checks). - # On aarch64 Linux (glibc + GCC) all four return 0, so pre-set it. - clamav = prev.clamav.overrideAttrs (old: { - cmakeFlags = (old.cmakeFlags or []) ++ [ - "-Dtest_run_result=0" - "-Dtest_run_result__TRYRUN_OUTPUT=" - ]; - # Give cargo access to a native C compiler for Rust build script - # compilations (proc-macros run on the BUILD host, not the target). - nativeBuildInputs = (old.nativeBuildInputs or []) ++ [ - prev.buildPackages.gcc - ]; - }); + # clamav: removed from system packages (see note above). }; uconsoleRpiPipewireOverlay = final: prev: { diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index 211820b..6e3de95 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -197,12 +197,11 @@ # Enable remote builder (distributed build via lazyworkhorse server) services.remoteBuilder.enable = true; - # ============================================================ - # ClamAV antivirus — daily automatic scans - # ============================================================ - gortium.clamav = { - enable = true; - enableDaemon = false; - }; + # ClamAV REMOVED — cross-compile failure (try_run + Rust linker) + # clamscan available from server when needed. + # gortium.clamav = { + # enable = true; + # enableDaemon = false; + # }; } -- 2.49.1 From 12af6bb643ccd0402ed37925a65ec46a1c6bdbb4 Mon Sep 17 00:00:00 2001 From: Hermes Date: Fri, 19 Jun 2026 22:11:39 -0400 Subject: [PATCH 117/157] uConsole: remove failing cross-compile packages (round 3) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removed for aarch64 bootstrap: sdrpp — glfw/wxPython cross-compile fails gqrx — Qt5 cascade fails emacs-pgtk/nox — GTK3 + mailutils → gss → shishi chain viking — GTK3 GPS foxtrotgps — GTK2 GPS Leave remaining as native install after first switch. Add consolidated removal tracking comment. --- hosts/uconsole-cm5/configuration.nix | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index 6e3de95..0e8f696 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -75,9 +75,26 @@ # ============================================================ # Package groups # ============================================================ + # ============================================================ + # CROSS-COMPILE REMOVALS — packages removed for aarch64 bootstrap + # ============================================================ + # These packages fail to cross-compile for aarch64. + # Install them natively AFTER the first successful switch. + # + # Removed: Reason: + # hashcat — Makefile calls gcc directly (cross-compiler not used) + # clamav — cmake try_run + Rust proc-macro linker for aarch64 + # sdrpp — glfw/wxPython cross-compile fails + # gqrx — Qt5 cross-compile cascade fails + # emacs-pgtk → emacs-nox — GTK3 + mailutils → gss → shishi chain + # viking — GTK3 GPS map editor + # foxtrotgps — GTK2 GPS app + # js8call — QtQuick3D dep + # ============================================================ environment.systemPackages = with pkgs; [ # ===== Base ===== - emacs-pgtk + # emacs-pgtk — removed for bootstrap (GTK3 cross-compile fails) + # emacs-nox — removed for bootstrap (depends on mailutils -> gss -> shishi, cross-compile fails) git ripgrep fd @@ -94,8 +111,8 @@ trustedqsl # Logbook of the World (LoTW) # ===== SDR / RF ===== - sdrpp # SDR++ spectrum analyzer - gqrx # SDR receiver GUI + # sdrpp — removed for aarch64 cross-compile bootstrap (glfw/wxPython fails) + # gqrx — removed for aarch64 cross-compile bootstrap (Qt5 cascade fails) rtl-sdr # RTL-SDR drivers & utilities inspectrum # Offline signal analysis soapysdr-with-plugins # SoapySDR + hardware support plugins @@ -115,8 +132,8 @@ sqlmap # SQL injection tool # ===== GPS / Maps ===== - foxtrotgps - viking # GPS map editor + # foxtrotgps — removed for aarch64 cross-compile bootstrap (GTK2 fails) + # viking — removed for aarch64 cross-compile bootstrap (GTK3 fails) gpsbabel # GPS data conversion ]; -- 2.49.1 From 93dc4f1cac86c7a9f6e037b35de3a77ff8ccdf1e Mon Sep 17 00:00:00 2001 From: Hermes Date: Fri, 19 Jun 2026 22:13:18 -0400 Subject: [PATCH 118/157] uConsole: consolidate removal tracking into single block --- hosts/uconsole-cm5/configuration.nix | 32 ---------------------------- 1 file changed, 32 deletions(-) diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index 0e8f696..aff3bcf 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -1,14 +1,11 @@ { config, lib, pkgs, keys, ... }: - { networking.hostName = "uConsole"; time.timeZone = "America/Montreal"; i18n.defaultLocale = "en_CA.UTF-8"; system.stateVersion = "25.11"; - # Boot & Hardware boot.loader.raspberry-pi.bootloader = "kernel"; - # SSH — root access avec clés gortium + ai-worker services.openssh = { enable = true; @@ -17,29 +14,23 @@ PasswordAuthentication = lib.mkForce false; }; }; - users.users.root.openssh.authorizedKeys.keys = with keys; [ users.gortium.main users.ai-worker.main ]; - # Age secret for gortium password (file created by user) age.secrets.gortium_password = { file = ../../secrets/gortium_password.age; }; - # WiFi via NetworkManager networking.networkmanager.enable = true; - # Firmware hardware.enableRedistributableFirmware = true; - # Hyprland Wayland compositor (manual start — no SDDM) programs.hyprland = { enable = true; xwayland.enable = true; }; - # HackerGadgets AIO v2 board hardware.uconsole-cm5-aio-v2 = { enable = true; @@ -51,7 +42,6 @@ }; enableGPS = false; }; - # User users.users.gortium = { isNormalUser = true; @@ -71,7 +61,6 @@ }]; } ]; - # ============================================================ # Package groups # ============================================================ @@ -100,7 +89,6 @@ fd htop tmux - # ===== HAM Radio ===== wsjtx fldigi @@ -109,19 +97,16 @@ chirp # Radio programming tool hamlib # Ham radio control libraries trustedqsl # Logbook of the World (LoTW) - # ===== SDR / RF ===== # sdrpp — removed for aarch64 cross-compile bootstrap (glfw/wxPython fails) # gqrx — removed for aarch64 cross-compile bootstrap (Qt5 cascade fails) rtl-sdr # RTL-SDR drivers & utilities inspectrum # Offline signal analysis soapysdr-with-plugins # SoapySDR + hardware support plugins - # ===== Mesh / LoRa ===== reticulumStack # Reticulum Network Stack lxmf # LXMF messaging protocol nomadnet # Nomad Network client - # ===== Security ===== nmap aircrack-ng @@ -130,13 +115,11 @@ wireshark-cli # Packet analyzer john # John the Ripper sqlmap # SQL injection tool - # ===== GPS / Maps ===== # foxtrotgps — removed for aarch64 cross-compile bootstrap (GTK2 fails) # viking — removed for aarch64 cross-compile bootstrap (GTK3 fails) gpsbabel # GPS data conversion ]; - # ============================================================ # Reticulum Service (rnsd) # ============================================================ @@ -154,7 +137,6 @@ LimitNOFILE = 65536; }; }; - # ============================================================ # Kismet Service (Wi-Fi monitoring / mesh node) # ============================================================ @@ -171,7 +153,6 @@ RestartSec = "10s"; }; }; - # ============================================================ # Kernel modules for SDR and radio # ============================================================ @@ -181,17 +162,14 @@ "rtl2832_sdr" # RTL-SDR kernel module "dvb_usb_rtl28xxu" # RTL-SDR DVB-T ]; - # ============================================================ # Extra udev rules for SDR and HAM radio devices # ============================================================ services.udev.packages = with pkgs; [ rtl-sdr ]; - # ============================================================ # Enable IPv6 for Reticulum mesh # ============================================================ networking.enableIPv6 = true; - # ============================================================ # Firewall # ============================================================ @@ -205,20 +183,10 @@ masterIdentities = [ "/home/gortium/.ssh/gortium_ssh_key" ]; - # uConsole SSH host pubkey — for automatic rekey at build time # Once uConsole is deployed, replace with actual pubkey from: # ssh-keyscan uConsole.local | ssh-to-age hostPubkey = "age1qyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqs3290gq"; # dummy — replace after bootstrap }; - # Enable remote builder (distributed build via lazyworkhorse server) services.remoteBuilder.enable = true; - # ClamAV REMOVED — cross-compile failure (try_run + Rust linker) - # clamscan available from server when needed. - # gortium.clamav = { - # enable = true; - # enableDaemon = false; - # }; - -} -- 2.49.1 From 95833f4d28c7f48fd3f31e025a749541c5ef5eff Mon Sep 17 00:00:00 2001 From: Hermes Date: Fri, 19 Jun 2026 22:14:46 -0400 Subject: [PATCH 119/157] uConsole: fix missing closing brace (sed cleanup mishap) --- hosts/uconsole-cm5/configuration.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index aff3bcf..b841df3 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -190,3 +190,4 @@ }; # Enable remote builder (distributed build via lazyworkhorse server) services.remoteBuilder.enable = true; +} -- 2.49.1 From eeb345b7e0eb16ebcffbacb6fd3db4f98bb2b95a Mon Sep 17 00:00:00 2001 From: Hermes Date: Fri, 19 Jun 2026 22:22:13 -0400 Subject: [PATCH 120/157] uConsole: add neovim to cross-compile removal tracking comment --- hosts/uconsole-cm5/configuration.nix | 1 + hosts/uconsole-cm5/configuration.nix.bak | 207 +++++++++++++++++++++++ 2 files changed, 208 insertions(+) create mode 100644 hosts/uconsole-cm5/configuration.nix.bak diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index b841df3..f821afe 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -72,6 +72,7 @@ # # Removed: Reason: # hashcat — Makefile calls gcc directly (cross-compiler not used) + # neovim — Same as hashcat: Makefile calls gcc directly (cross-compiler not used) # clamav — cmake try_run + Rust proc-macro linker for aarch64 # sdrpp — glfw/wxPython cross-compile fails # gqrx — Qt5 cross-compile cascade fails diff --git a/hosts/uconsole-cm5/configuration.nix.bak b/hosts/uconsole-cm5/configuration.nix.bak new file mode 100644 index 0000000..6e3de95 --- /dev/null +++ b/hosts/uconsole-cm5/configuration.nix.bak @@ -0,0 +1,207 @@ +{ config, lib, pkgs, keys, ... }: + +{ + networking.hostName = "uConsole"; + time.timeZone = "America/Montreal"; + i18n.defaultLocale = "en_CA.UTF-8"; + system.stateVersion = "25.11"; + + # Boot & Hardware + boot.loader.raspberry-pi.bootloader = "kernel"; + + # SSH — root access avec clés gortium + ai-worker + services.openssh = { + enable = true; + settings = { + PermitRootLogin = lib.mkForce "prohibit-password"; + PasswordAuthentication = lib.mkForce false; + }; + }; + + users.users.root.openssh.authorizedKeys.keys = with keys; [ + users.gortium.main + users.ai-worker.main + ]; + + # Age secret for gortium password (file created by user) + age.secrets.gortium_password = { + file = ../../secrets/gortium_password.age; + }; + + # WiFi via NetworkManager + networking.networkmanager.enable = true; + + # Firmware + hardware.enableRedistributableFirmware = true; + + # Hyprland Wayland compositor (manual start — no SDDM) + programs.hyprland = { + enable = true; + xwayland.enable = true; + }; + + # HackerGadgets AIO v2 board + hardware.uconsole-cm5-aio-v2 = { + enable = true; + bootRails = { + GPS = false; + LORA = false; + SDR = false; + USB = false; + }; + enableGPS = false; + }; + + # User + users.users.gortium = { + isNormalUser = true; + extraGroups = [ "wheel" "networkmanager" "video" "dialout" "kismet" ]; + hashedPasswordFile = config.age.secrets.gortium_password.path; + openssh.authorizedKeys.keys = [ + keys.users.gortium.main + keys.users.gortium.gitea + ]; + }; + security.sudo.extraRules = [ + { + users = [ "gortium" ]; + commands = [{ + command = "ALL"; + options = [ "NOPASSWD" ]; + }]; + } + ]; + + # ============================================================ + # Package groups + # ============================================================ + environment.systemPackages = with pkgs; [ + # ===== Base ===== + emacs-pgtk + git + ripgrep + fd + htop + tmux + + # ===== HAM Radio ===== + wsjtx + fldigi + pat # Winlink client + direwolf # AX.25 packet modem + chirp # Radio programming tool + hamlib # Ham radio control libraries + trustedqsl # Logbook of the World (LoTW) + + # ===== SDR / RF ===== + sdrpp # SDR++ spectrum analyzer + gqrx # SDR receiver GUI + rtl-sdr # RTL-SDR drivers & utilities + inspectrum # Offline signal analysis + soapysdr-with-plugins # SoapySDR + hardware support plugins + + # ===== Mesh / LoRa ===== + reticulumStack # Reticulum Network Stack + lxmf # LXMF messaging protocol + nomadnet # Nomad Network client + + # ===== Security ===== + nmap + aircrack-ng + kismet # Wi-Fi monitor / IDS + bettercap # MITM/network attack framework + wireshark-cli # Packet analyzer + john # John the Ripper + sqlmap # SQL injection tool + + # ===== GPS / Maps ===== + foxtrotgps + viking # GPS map editor + gpsbabel # GPS data conversion + ]; + + # ============================================================ + # Reticulum Service (rnsd) + # ============================================================ + systemd.services.rnsd = { + description = "Reticulum Network Stack Daemon"; + wants = [ "network-online.target" ]; + after = [ "network-online.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + User = "gortium"; + Group = "gortium"; + ExecStart = "${pkgs.reticulumStack}/bin/rnsd"; + Restart = "always"; + RestartSec = "10s"; + LimitNOFILE = 65536; + }; + }; + + # ============================================================ + # Kismet Service (Wi-Fi monitoring / mesh node) + # ============================================================ + systemd.services.kismet = { + description = "Kismet Wi-Fi Monitor & IDS"; + wants = [ "network-online.target" ]; + after = [ "network-online.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + User = "gortium"; + Group = "kismet"; + ExecStart = "${pkgs.kismet}/bin/kismet -c wlan0 --log-base=/home/gortium/kismet_logs --no-nc-ui"; + Restart = "always"; + RestartSec = "10s"; + }; + }; + + # ============================================================ + # Kernel modules for SDR and radio + # ============================================================ + boot.kernelModules = [ + "88x2bu" # Realtek 8812/8821BU USB WiFi + "rtl8xxxu" # RTL8188/8192/8723 USB WiFi + "rtl2832_sdr" # RTL-SDR kernel module + "dvb_usb_rtl28xxu" # RTL-SDR DVB-T + ]; + + # ============================================================ + # Extra udev rules for SDR and HAM radio devices + # ============================================================ + services.udev.packages = with pkgs; [ rtl-sdr ]; + + # ============================================================ + # Enable IPv6 for Reticulum mesh + # ============================================================ + networking.enableIPv6 = true; + + # ============================================================ + # Firewall + # ============================================================ + networking.firewall.allowedTCPPorts = [ 22 ]; + networking.firewall.allowedUDPPorts = [ ]; + # ============================================================ + # agenix-rekey — automatic secret re-encryption at deploy time + # ============================================================ + age.rekey = { + # Master identities for encrypting secrets (on Thierry's laptop) + masterIdentities = [ + "/home/gortium/.ssh/gortium_ssh_key" + ]; + + # uConsole SSH host pubkey — for automatic rekey at build time + # Once uConsole is deployed, replace with actual pubkey from: + # ssh-keyscan uConsole.local | ssh-to-age + hostPubkey = "age1qyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqs3290gq"; # dummy — replace after bootstrap + }; + + # Enable remote builder (distributed build via lazyworkhorse server) + services.remoteBuilder.enable = true; + # ClamAV REMOVED — cross-compile failure (try_run + Rust linker) + # clamscan available from server when needed. + # gortium.clamav = { + # enable = true; + # enableDaemon = false; + # }; + +} -- 2.49.1 From a8215ae4411c7cf867d49895489c3d2bc41e6fd2 Mon Sep 17 00:00:00 2001 From: Hermes Date: Fri, 19 Jun 2026 22:22:16 -0400 Subject: [PATCH 121/157] uConsole: remove accidental .bak file from tracking --- hosts/uconsole-cm5/configuration.nix.bak | 207 ----------------------- 1 file changed, 207 deletions(-) delete mode 100644 hosts/uconsole-cm5/configuration.nix.bak diff --git a/hosts/uconsole-cm5/configuration.nix.bak b/hosts/uconsole-cm5/configuration.nix.bak deleted file mode 100644 index 6e3de95..0000000 --- a/hosts/uconsole-cm5/configuration.nix.bak +++ /dev/null @@ -1,207 +0,0 @@ -{ config, lib, pkgs, keys, ... }: - -{ - networking.hostName = "uConsole"; - time.timeZone = "America/Montreal"; - i18n.defaultLocale = "en_CA.UTF-8"; - system.stateVersion = "25.11"; - - # Boot & Hardware - boot.loader.raspberry-pi.bootloader = "kernel"; - - # SSH — root access avec clés gortium + ai-worker - services.openssh = { - enable = true; - settings = { - PermitRootLogin = lib.mkForce "prohibit-password"; - PasswordAuthentication = lib.mkForce false; - }; - }; - - users.users.root.openssh.authorizedKeys.keys = with keys; [ - users.gortium.main - users.ai-worker.main - ]; - - # Age secret for gortium password (file created by user) - age.secrets.gortium_password = { - file = ../../secrets/gortium_password.age; - }; - - # WiFi via NetworkManager - networking.networkmanager.enable = true; - - # Firmware - hardware.enableRedistributableFirmware = true; - - # Hyprland Wayland compositor (manual start — no SDDM) - programs.hyprland = { - enable = true; - xwayland.enable = true; - }; - - # HackerGadgets AIO v2 board - hardware.uconsole-cm5-aio-v2 = { - enable = true; - bootRails = { - GPS = false; - LORA = false; - SDR = false; - USB = false; - }; - enableGPS = false; - }; - - # User - users.users.gortium = { - isNormalUser = true; - extraGroups = [ "wheel" "networkmanager" "video" "dialout" "kismet" ]; - hashedPasswordFile = config.age.secrets.gortium_password.path; - openssh.authorizedKeys.keys = [ - keys.users.gortium.main - keys.users.gortium.gitea - ]; - }; - security.sudo.extraRules = [ - { - users = [ "gortium" ]; - commands = [{ - command = "ALL"; - options = [ "NOPASSWD" ]; - }]; - } - ]; - - # ============================================================ - # Package groups - # ============================================================ - environment.systemPackages = with pkgs; [ - # ===== Base ===== - emacs-pgtk - git - ripgrep - fd - htop - tmux - - # ===== HAM Radio ===== - wsjtx - fldigi - pat # Winlink client - direwolf # AX.25 packet modem - chirp # Radio programming tool - hamlib # Ham radio control libraries - trustedqsl # Logbook of the World (LoTW) - - # ===== SDR / RF ===== - sdrpp # SDR++ spectrum analyzer - gqrx # SDR receiver GUI - rtl-sdr # RTL-SDR drivers & utilities - inspectrum # Offline signal analysis - soapysdr-with-plugins # SoapySDR + hardware support plugins - - # ===== Mesh / LoRa ===== - reticulumStack # Reticulum Network Stack - lxmf # LXMF messaging protocol - nomadnet # Nomad Network client - - # ===== Security ===== - nmap - aircrack-ng - kismet # Wi-Fi monitor / IDS - bettercap # MITM/network attack framework - wireshark-cli # Packet analyzer - john # John the Ripper - sqlmap # SQL injection tool - - # ===== GPS / Maps ===== - foxtrotgps - viking # GPS map editor - gpsbabel # GPS data conversion - ]; - - # ============================================================ - # Reticulum Service (rnsd) - # ============================================================ - systemd.services.rnsd = { - description = "Reticulum Network Stack Daemon"; - wants = [ "network-online.target" ]; - after = [ "network-online.target" ]; - wantedBy = [ "multi-user.target" ]; - serviceConfig = { - User = "gortium"; - Group = "gortium"; - ExecStart = "${pkgs.reticulumStack}/bin/rnsd"; - Restart = "always"; - RestartSec = "10s"; - LimitNOFILE = 65536; - }; - }; - - # ============================================================ - # Kismet Service (Wi-Fi monitoring / mesh node) - # ============================================================ - systemd.services.kismet = { - description = "Kismet Wi-Fi Monitor & IDS"; - wants = [ "network-online.target" ]; - after = [ "network-online.target" ]; - wantedBy = [ "multi-user.target" ]; - serviceConfig = { - User = "gortium"; - Group = "kismet"; - ExecStart = "${pkgs.kismet}/bin/kismet -c wlan0 --log-base=/home/gortium/kismet_logs --no-nc-ui"; - Restart = "always"; - RestartSec = "10s"; - }; - }; - - # ============================================================ - # Kernel modules for SDR and radio - # ============================================================ - boot.kernelModules = [ - "88x2bu" # Realtek 8812/8821BU USB WiFi - "rtl8xxxu" # RTL8188/8192/8723 USB WiFi - "rtl2832_sdr" # RTL-SDR kernel module - "dvb_usb_rtl28xxu" # RTL-SDR DVB-T - ]; - - # ============================================================ - # Extra udev rules for SDR and HAM radio devices - # ============================================================ - services.udev.packages = with pkgs; [ rtl-sdr ]; - - # ============================================================ - # Enable IPv6 for Reticulum mesh - # ============================================================ - networking.enableIPv6 = true; - - # ============================================================ - # Firewall - # ============================================================ - networking.firewall.allowedTCPPorts = [ 22 ]; - networking.firewall.allowedUDPPorts = [ ]; - # ============================================================ - # agenix-rekey — automatic secret re-encryption at deploy time - # ============================================================ - age.rekey = { - # Master identities for encrypting secrets (on Thierry's laptop) - masterIdentities = [ - "/home/gortium/.ssh/gortium_ssh_key" - ]; - - # uConsole SSH host pubkey — for automatic rekey at build time - # Once uConsole is deployed, replace with actual pubkey from: - # ssh-keyscan uConsole.local | ssh-to-age - hostPubkey = "age1qyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqs3290gq"; # dummy — replace after bootstrap - }; - - # Enable remote builder (distributed build via lazyworkhorse server) - services.remoteBuilder.enable = true; - # ClamAV REMOVED — cross-compile failure (try_run + Rust linker) - # clamscan available from server when needed. - # gortium.clamav = { - # enable = true; - # enableDaemon = false; - # }; - -} -- 2.49.1 From 9f62dac106015dd20cb2670430e7a4e75a474157 Mon Sep 17 00:00:00 2001 From: Hermes Date: Fri, 19 Jun 2026 22:38:08 -0400 Subject: [PATCH 122/157] =?UTF-8?q?uConsole:=20remove=20wsjtx=20+=20fldigi?= =?UTF-8?q?=20(qtbase/Qt5=20linker=20fails)=20=E2=80=94=20add=20to=20remov?= =?UTF-8?q?al=20comment?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hosts/uconsole-cm5/configuration.nix | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index f821afe..3fc8102 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -80,6 +80,8 @@ # viking — GTK3 GPS map editor # foxtrotgps — GTK2 GPS app # js8call — QtQuick3D dep + # wsjtx — qtbase/Qt5 linker fails (collect2: ld returned 1) + # fldigi — same: qtbase/Qt5 linker fails # ============================================================ environment.systemPackages = with pkgs; [ # ===== Base ===== @@ -91,8 +93,8 @@ htop tmux # ===== HAM Radio ===== - wsjtx - fldigi + # wsjtx — removed for aarch64 bootstrap (qtbase/Qt5 cross-compile linker fails) + # fldigi — removed for aarch64 bootstrap (qtbase/Qt5 cross-compile linker fails) pat # Winlink client direwolf # AX.25 packet modem chirp # Radio programming tool -- 2.49.1 From 1b70f9503823bbe584fe4f12fe022674d0ff3cf1 Mon Sep 17 00:00:00 2001 From: Hermes Date: Sat, 20 Jun 2026 11:56:31 -0400 Subject: [PATCH 123/157] fix: remove gpsbabel for aarch64 cross-compile (qmake can't find g++) --- hosts/uconsole-cm5/configuration.nix | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index 3fc8102..a11b53c 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -71,6 +71,7 @@ # Install them natively AFTER the first successful switch. # # Removed: Reason: +# inspectrum — Qt5 cross-compile cascade fails (qtsvg mismatched qtbase deps) # hashcat — Makefile calls gcc directly (cross-compiler not used) # neovim — Same as hashcat: Makefile calls gcc directly (cross-compiler not used) # clamav — cmake try_run + Rust proc-macro linker for aarch64 @@ -82,6 +83,7 @@ # js8call — QtQuick3D dep # wsjtx — qtbase/Qt5 linker fails (collect2: ld returned 1) # fldigi — same: qtbase/Qt5 linker fails +# gpsbabel — qmake can't find cross-compiler g++ # ============================================================ environment.systemPackages = with pkgs; [ # ===== Base ===== @@ -104,7 +106,7 @@ # sdrpp — removed for aarch64 cross-compile bootstrap (glfw/wxPython fails) # gqrx — removed for aarch64 cross-compile bootstrap (Qt5 cascade fails) rtl-sdr # RTL-SDR drivers & utilities - inspectrum # Offline signal analysis + # inspectrum # removed for aarch64 bootstrap (Qt5 cross-compile cascade fails) soapysdr-with-plugins # SoapySDR + hardware support plugins # ===== Mesh / LoRa ===== reticulumStack # Reticulum Network Stack @@ -121,7 +123,7 @@ # ===== GPS / Maps ===== # foxtrotgps — removed for aarch64 cross-compile bootstrap (GTK2 fails) # viking — removed for aarch64 cross-compile bootstrap (GTK3 fails) - gpsbabel # GPS data conversion + # gpsbabel # GPS data conversion ]; # ============================================================ # Reticulum Service (rnsd) @@ -191,6 +193,11 @@ # ssh-keyscan uConsole.local | ssh-to-age hostPubkey = "age1qyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqs3290gq"; # dummy — replace after bootstrap }; - # Enable remote builder (distributed build via lazyworkhorse server) - services.remoteBuilder.enable = true; + + # Pipewire overlay: drop libcamera (fixes aarch64 cross-compile — rpi-pisp blocks) + nixpkgs.overlays = [ + (final: prev: { + pipewire = prev.pipewire.override { libcamera = null; }; + }) + ]; } -- 2.49.1 From e38908de740edc4402c034870441d8195aca235e Mon Sep 17 00:00:00 2001 From: Hermes Date: Sat, 20 Jun 2026 12:41:50 -0400 Subject: [PATCH 124/157] fix: remove john for aarch64 cross-compile (configure needs python) --- hosts/uconsole-cm5/configuration.nix | 3 +- hosts/uconsole-cm5/configuration.nix.bak | 202 ++++++++++++++++++ .../uconsole-cm5/configuration.nix.bak.hermes | 201 +++++++++++++++++ 3 files changed, 405 insertions(+), 1 deletion(-) create mode 100644 hosts/uconsole-cm5/configuration.nix.bak create mode 100644 hosts/uconsole-cm5/configuration.nix.bak.hermes diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index a11b53c..be6f34e 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -84,6 +84,7 @@ # wsjtx — qtbase/Qt5 linker fails (collect2: ld returned 1) # fldigi — same: qtbase/Qt5 linker fails # gpsbabel — qmake can't find cross-compiler g++ +# john — configure script needs python (not in PATH during cross-compile) # ============================================================ environment.systemPackages = with pkgs; [ # ===== Base ===== @@ -118,7 +119,7 @@ kismet # Wi-Fi monitor / IDS bettercap # MITM/network attack framework wireshark-cli # Packet analyzer - john # John the Ripper + # john # John the Ripper sqlmap # SQL injection tool # ===== GPS / Maps ===== # foxtrotgps — removed for aarch64 cross-compile bootstrap (GTK2 fails) diff --git a/hosts/uconsole-cm5/configuration.nix.bak b/hosts/uconsole-cm5/configuration.nix.bak new file mode 100644 index 0000000..680f5fb --- /dev/null +++ b/hosts/uconsole-cm5/configuration.nix.bak @@ -0,0 +1,202 @@ +{ config, lib, pkgs, keys, ... }: +{ + networking.hostName = "uConsole"; + time.timeZone = "America/Montreal"; + i18n.defaultLocale = "en_CA.UTF-8"; + system.stateVersion = "25.11"; + # Boot & Hardware + boot.loader.raspberry-pi.bootloader = "kernel"; + # SSH — root access avec clés gortium + ai-worker + services.openssh = { + enable = true; + settings = { + PermitRootLogin = lib.mkForce "prohibit-password"; + PasswordAuthentication = lib.mkForce false; + }; + }; + users.users.root.openssh.authorizedKeys.keys = with keys; [ + users.gortium.main + users.ai-worker.main + ]; + # Age secret for gortium password (file created by user) + age.secrets.gortium_password = { + file = ../../secrets/gortium_password.age; + }; + # WiFi via NetworkManager + networking.networkmanager.enable = true; + # Firmware + hardware.enableRedistributableFirmware = true; + # Hyprland Wayland compositor (manual start — no SDDM) + programs.hyprland = { + enable = true; + xwayland.enable = true; + }; + # HackerGadgets AIO v2 board + hardware.uconsole-cm5-aio-v2 = { + enable = true; + bootRails = { + GPS = false; + LORA = false; + SDR = false; + USB = false; + }; + enableGPS = false; + }; + # User + users.users.gortium = { + isNormalUser = true; + extraGroups = [ "wheel" "networkmanager" "video" "dialout" "kismet" ]; + hashedPasswordFile = config.age.secrets.gortium_password.path; + openssh.authorizedKeys.keys = [ + keys.users.gortium.main + keys.users.gortium.gitea + ]; + }; + security.sudo.extraRules = [ + { + users = [ "gortium" ]; + commands = [{ + command = "ALL"; + options = [ "NOPASSWD" ]; + }]; + } + ]; + # ============================================================ + # Package groups + # ============================================================ + # ============================================================ + # CROSS-COMPILE REMOVALS — packages removed for aarch64 bootstrap + # ============================================================ + # These packages fail to cross-compile for aarch64. + # Install them natively AFTER the first successful switch. + # + # Removed: Reason: + # hashcat — Makefile calls gcc directly (cross-compiler not used) + # neovim — Same as hashcat: Makefile calls gcc directly (cross-compiler not used) + # clamav — cmake try_run + Rust proc-macro linker for aarch64 + # sdrpp — glfw/wxPython cross-compile fails + # gqrx — Qt5 cross-compile cascade fails + # emacs-pgtk → emacs-nox — GTK3 + mailutils → gss → shishi chain + # viking — GTK3 GPS map editor + # foxtrotgps — GTK2 GPS app + # js8call — QtQuick3D dep + # wsjtx — qtbase/Qt5 linker fails (collect2: ld returned 1) + # fldigi — same: qtbase/Qt5 linker fails + # ============================================================ + environment.systemPackages = with pkgs; [ + # ===== Base ===== + # emacs-pgtk — removed for bootstrap (GTK3 cross-compile fails) + # emacs-nox — removed for bootstrap (depends on mailutils -> gss -> shishi, cross-compile fails) + git + ripgrep + fd + htop + tmux + # ===== HAM Radio ===== + # wsjtx — removed for aarch64 bootstrap (qtbase/Qt5 cross-compile linker fails) + # fldigi — removed for aarch64 bootstrap (qtbase/Qt5 cross-compile linker fails) + pat # Winlink client + direwolf # AX.25 packet modem + chirp # Radio programming tool + hamlib # Ham radio control libraries + trustedqsl # Logbook of the World (LoTW) + # ===== SDR / RF ===== + # sdrpp — removed for aarch64 cross-compile bootstrap (glfw/wxPython fails) + # gqrx — removed for aarch64 cross-compile bootstrap (Qt5 cascade fails) + rtl-sdr # RTL-SDR drivers & utilities + inspectrum # Offline signal analysis + soapysdr-with-plugins # SoapySDR + hardware support plugins + # ===== Mesh / LoRa ===== + reticulumStack # Reticulum Network Stack + lxmf # LXMF messaging protocol + nomadnet # Nomad Network client + # ===== Security ===== + nmap + aircrack-ng + kismet # Wi-Fi monitor / IDS + bettercap # MITM/network attack framework + wireshark-cli # Packet analyzer + john # John the Ripper + sqlmap # SQL injection tool + # ===== GPS / Maps ===== + # foxtrotgps — removed for aarch64 cross-compile bootstrap (GTK2 fails) + # viking — removed for aarch64 cross-compile bootstrap (GTK3 fails) + gpsbabel # GPS data conversion + ]; + # ============================================================ + # Reticulum Service (rnsd) + # ============================================================ + systemd.services.rnsd = { + description = "Reticulum Network Stack Daemon"; + wants = [ "network-online.target" ]; + after = [ "network-online.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + User = "gortium"; + Group = "gortium"; + ExecStart = "${pkgs.reticulumStack}/bin/rnsd"; + Restart = "always"; + RestartSec = "10s"; + LimitNOFILE = 65536; + }; + }; + # ============================================================ + # Kismet Service (Wi-Fi monitoring / mesh node) + # ============================================================ + systemd.services.kismet = { + description = "Kismet Wi-Fi Monitor & IDS"; + wants = [ "network-online.target" ]; + after = [ "network-online.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + User = "gortium"; + Group = "kismet"; + ExecStart = "${pkgs.kismet}/bin/kismet -c wlan0 --log-base=/home/gortium/kismet_logs --no-nc-ui"; + Restart = "always"; + RestartSec = "10s"; + }; + }; + # ============================================================ + # Kernel modules for SDR and radio + # ============================================================ + boot.kernelModules = [ + "88x2bu" # Realtek 8812/8821BU USB WiFi + "rtl8xxxu" # RTL8188/8192/8723 USB WiFi + "rtl2832_sdr" # RTL-SDR kernel module + "dvb_usb_rtl28xxu" # RTL-SDR DVB-T + ]; + # ============================================================ + # Extra udev rules for SDR and HAM radio devices + # ============================================================ + services.udev.packages = with pkgs; [ rtl-sdr ]; + # ============================================================ + # Enable IPv6 for Reticulum mesh + # ============================================================ + networking.enableIPv6 = true; + # ============================================================ + # Firewall + # ============================================================ + networking.firewall.allowedTCPPorts = [ 22 ]; + networking.firewall.allowedUDPPorts = [ ]; + # ============================================================ + # agenix-rekey — automatic secret re-encryption at deploy time + # ============================================================ + age.rekey = { + # Master identities for encrypting secrets (on Thierry's laptop) + masterIdentities = [ + "/home/gortium/.ssh/gortium_ssh_key" + ]; + # uConsole SSH host pubkey — for automatic rekey at build time + # Once uConsole is deployed, replace with actual pubkey from: + # ssh-keyscan uConsole.local | ssh-to-age + hostPubkey = "age1qyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqs3290gq"; # dummy — replace after bootstrap + }; + # Enable remote builder (distributed build via lazyworkhorse server) + services.remoteBuilder.enable = true; +} + + # Pipewire overlay: drop libcamera (fixes aarch64 cross-compile — rpi-pisp blocks) + nixpkgs.overlays = [ + (final: prev: { + pipewire = prev.pipewire.override { libcamera = null; }; + }) diff --git a/hosts/uconsole-cm5/configuration.nix.bak.hermes b/hosts/uconsole-cm5/configuration.nix.bak.hermes new file mode 100644 index 0000000..ad52cb8 --- /dev/null +++ b/hosts/uconsole-cm5/configuration.nix.bak.hermes @@ -0,0 +1,201 @@ +{ config, lib, pkgs, keys, ... }: +{ + networking.hostName = "uConsole"; + time.timeZone = "America/Montreal"; + i18n.defaultLocale = "en_CA.UTF-8"; + system.stateVersion = "25.11"; + # Boot & Hardware + boot.loader.raspberry-pi.bootloader = "kernel"; + # SSH — root access avec clés gortium + ai-worker + services.openssh = { + enable = true; + settings = { + PermitRootLogin = lib.mkForce "prohibit-password"; + PasswordAuthentication = lib.mkForce false; + }; + }; + users.users.root.openssh.authorizedKeys.keys = with keys; [ + users.gortium.main + users.ai-worker.main + ]; + # Age secret for gortium password (file created by user) + age.secrets.gortium_password = { + file = ../../secrets/gortium_password.age; + }; + # WiFi via NetworkManager + networking.networkmanager.enable = true; + # Firmware + hardware.enableRedistributableFirmware = true; + # Hyprland Wayland compositor (manual start — no SDDM) + programs.hyprland = { + enable = true; + xwayland.enable = true; + }; + # HackerGadgets AIO v2 board + hardware.uconsole-cm5-aio-v2 = { + enable = true; + bootRails = { + GPS = false; + LORA = false; + SDR = false; + USB = false; + }; + enableGPS = false; + }; + # User + users.users.gortium = { + isNormalUser = true; + extraGroups = [ "wheel" "networkmanager" "video" "dialout" "kismet" ]; + hashedPasswordFile = config.age.secrets.gortium_password.path; + openssh.authorizedKeys.keys = [ + keys.users.gortium.main + keys.users.gortium.gitea + ]; + }; + security.sudo.extraRules = [ + { + users = [ "gortium" ]; + commands = [{ + command = "ALL"; + options = [ "NOPASSWD" ]; + }]; + } + ]; + # ============================================================ + # Package groups + # ============================================================ + # ============================================================ + # CROSS-COMPILE REMOVALS — packages removed for aarch64 bootstrap + # ============================================================ + # These packages fail to cross-compile for aarch64. + # Install them natively AFTER the first successful switch. + # + # Removed: Reason: + # hashcat — Makefile calls gcc directly (cross-compiler not used) + # neovim — Same as hashcat: Makefile calls gcc directly (cross-compiler not used) + # clamav — cmake try_run + Rust proc-macro linker for aarch64 + # sdrpp — glfw/wxPython cross-compile fails + # gqrx — Qt5 cross-compile cascade fails + # emacs-pgtk → emacs-nox — GTK3 + mailutils → gss → shishi chain + # viking — GTK3 GPS map editor + # foxtrotgps — GTK2 GPS app + # js8call — QtQuick3D dep + # wsjtx — qtbase/Qt5 linker fails (collect2: ld returned 1) + # fldigi — same: qtbase/Qt5 linker fails + # ============================================================ + environment.systemPackages = with pkgs; [ + # ===== Base ===== + # emacs-pgtk — removed for bootstrap (GTK3 cross-compile fails) + # emacs-nox — removed for bootstrap (depends on mailutils -> gss -> shishi, cross-compile fails) + git + ripgrep + fd + htop + tmux + # ===== HAM Radio ===== + # wsjtx — removed for aarch64 bootstrap (qtbase/Qt5 cross-compile linker fails) + # fldigi — removed for aarch64 bootstrap (qtbase/Qt5 cross-compile linker fails) + pat # Winlink client + direwolf # AX.25 packet modem + chirp # Radio programming tool + hamlib # Ham radio control libraries + trustedqsl # Logbook of the World (LoTW) + # ===== SDR / RF ===== + # sdrpp — removed for aarch64 cross-compile bootstrap (glfw/wxPython fails) + # gqrx — removed for aarch64 cross-compile bootstrap (Qt5 cascade fails) + rtl-sdr # RTL-SDR drivers & utilities + inspectrum # Offline signal analysis + soapysdr-with-plugins # SoapySDR + hardware support plugins + # ===== Mesh / LoRa ===== + reticulumStack # Reticulum Network Stack + lxmf # LXMF messaging protocol + nomadnet # Nomad Network client + # ===== Security ===== + nmap + aircrack-ng + kismet # Wi-Fi monitor / IDS + bettercap # MITM/network attack framework + wireshark-cli # Packet analyzer + john # John the Ripper + sqlmap # SQL injection tool + # ===== GPS / Maps ===== + # foxtrotgps — removed for aarch64 cross-compile bootstrap (GTK2 fails) + # viking — removed for aarch64 cross-compile bootstrap (GTK3 fails) + gpsbabel # GPS data conversion + ]; + # ============================================================ + # Reticulum Service (rnsd) + # ============================================================ + systemd.services.rnsd = { + description = "Reticulum Network Stack Daemon"; + wants = [ "network-online.target" ]; + after = [ "network-online.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + User = "gortium"; + Group = "gortium"; + ExecStart = "${pkgs.reticulumStack}/bin/rnsd"; + Restart = "always"; + RestartSec = "10s"; + LimitNOFILE = 65536; + }; + }; + # ============================================================ + # Kismet Service (Wi-Fi monitoring / mesh node) + # ============================================================ + systemd.services.kismet = { + description = "Kismet Wi-Fi Monitor & IDS"; + wants = [ "network-online.target" ]; + after = [ "network-online.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + User = "gortium"; + Group = "kismet"; + ExecStart = "${pkgs.kismet}/bin/kismet -c wlan0 --log-base=/home/gortium/kismet_logs --no-nc-ui"; + Restart = "always"; + RestartSec = "10s"; + }; + }; + # ============================================================ + # Kernel modules for SDR and radio + # ============================================================ + boot.kernelModules = [ + "88x2bu" # Realtek 8812/8821BU USB WiFi + "rtl8xxxu" # RTL8188/8192/8723 USB WiFi + "rtl2832_sdr" # RTL-SDR kernel module + "dvb_usb_rtl28xxu" # RTL-SDR DVB-T + ]; + # ============================================================ + # Extra udev rules for SDR and HAM radio devices + # ============================================================ + services.udev.packages = with pkgs; [ rtl-sdr ]; + # ============================================================ + # Enable IPv6 for Reticulum mesh + # ============================================================ + networking.enableIPv6 = true; + # ============================================================ + # Firewall + # ============================================================ + networking.firewall.allowedTCPPorts = [ 22 ]; + networking.firewall.allowedUDPPorts = [ ]; + # ============================================================ + # agenix-rekey — automatic secret re-encryption at deploy time + # ============================================================ + age.rekey = { + # Master identities for encrypting secrets (on Thierry's laptop) + masterIdentities = [ + "/home/gortium/.ssh/gortium_ssh_key" + ]; + # uConsole SSH host pubkey — for automatic rekey at build time + # Once uConsole is deployed, replace with actual pubkey from: + # ssh-keyscan uConsole.local | ssh-to-age + hostPubkey = "age1qyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqs3290gq"; # dummy — replace after bootstrap + }; + + # Pipewire overlay: drop libcamera (fixes aarch64 cross-compile — rpi-pisp blocks) + nixpkgs.overlays = [ + (final: prev: { + pipewire = prev.pipewire.override { libcamera = null; }; + }) + ]; +} -- 2.49.1 From bfb521f684cfabe0d6ab6304392583d4ffd5980b Mon Sep 17 00:00:00 2001 From: Hermes Date: Sat, 20 Jun 2026 12:42:03 -0400 Subject: [PATCH 125/157] chore: remove accidentally committed .bak files --- hosts/uconsole-cm5/configuration.nix.bak | 202 ------------------ .../uconsole-cm5/configuration.nix.bak.hermes | 201 ----------------- 2 files changed, 403 deletions(-) delete mode 100644 hosts/uconsole-cm5/configuration.nix.bak delete mode 100644 hosts/uconsole-cm5/configuration.nix.bak.hermes diff --git a/hosts/uconsole-cm5/configuration.nix.bak b/hosts/uconsole-cm5/configuration.nix.bak deleted file mode 100644 index 680f5fb..0000000 --- a/hosts/uconsole-cm5/configuration.nix.bak +++ /dev/null @@ -1,202 +0,0 @@ -{ config, lib, pkgs, keys, ... }: -{ - networking.hostName = "uConsole"; - time.timeZone = "America/Montreal"; - i18n.defaultLocale = "en_CA.UTF-8"; - system.stateVersion = "25.11"; - # Boot & Hardware - boot.loader.raspberry-pi.bootloader = "kernel"; - # SSH — root access avec clés gortium + ai-worker - services.openssh = { - enable = true; - settings = { - PermitRootLogin = lib.mkForce "prohibit-password"; - PasswordAuthentication = lib.mkForce false; - }; - }; - users.users.root.openssh.authorizedKeys.keys = with keys; [ - users.gortium.main - users.ai-worker.main - ]; - # Age secret for gortium password (file created by user) - age.secrets.gortium_password = { - file = ../../secrets/gortium_password.age; - }; - # WiFi via NetworkManager - networking.networkmanager.enable = true; - # Firmware - hardware.enableRedistributableFirmware = true; - # Hyprland Wayland compositor (manual start — no SDDM) - programs.hyprland = { - enable = true; - xwayland.enable = true; - }; - # HackerGadgets AIO v2 board - hardware.uconsole-cm5-aio-v2 = { - enable = true; - bootRails = { - GPS = false; - LORA = false; - SDR = false; - USB = false; - }; - enableGPS = false; - }; - # User - users.users.gortium = { - isNormalUser = true; - extraGroups = [ "wheel" "networkmanager" "video" "dialout" "kismet" ]; - hashedPasswordFile = config.age.secrets.gortium_password.path; - openssh.authorizedKeys.keys = [ - keys.users.gortium.main - keys.users.gortium.gitea - ]; - }; - security.sudo.extraRules = [ - { - users = [ "gortium" ]; - commands = [{ - command = "ALL"; - options = [ "NOPASSWD" ]; - }]; - } - ]; - # ============================================================ - # Package groups - # ============================================================ - # ============================================================ - # CROSS-COMPILE REMOVALS — packages removed for aarch64 bootstrap - # ============================================================ - # These packages fail to cross-compile for aarch64. - # Install them natively AFTER the first successful switch. - # - # Removed: Reason: - # hashcat — Makefile calls gcc directly (cross-compiler not used) - # neovim — Same as hashcat: Makefile calls gcc directly (cross-compiler not used) - # clamav — cmake try_run + Rust proc-macro linker for aarch64 - # sdrpp — glfw/wxPython cross-compile fails - # gqrx — Qt5 cross-compile cascade fails - # emacs-pgtk → emacs-nox — GTK3 + mailutils → gss → shishi chain - # viking — GTK3 GPS map editor - # foxtrotgps — GTK2 GPS app - # js8call — QtQuick3D dep - # wsjtx — qtbase/Qt5 linker fails (collect2: ld returned 1) - # fldigi — same: qtbase/Qt5 linker fails - # ============================================================ - environment.systemPackages = with pkgs; [ - # ===== Base ===== - # emacs-pgtk — removed for bootstrap (GTK3 cross-compile fails) - # emacs-nox — removed for bootstrap (depends on mailutils -> gss -> shishi, cross-compile fails) - git - ripgrep - fd - htop - tmux - # ===== HAM Radio ===== - # wsjtx — removed for aarch64 bootstrap (qtbase/Qt5 cross-compile linker fails) - # fldigi — removed for aarch64 bootstrap (qtbase/Qt5 cross-compile linker fails) - pat # Winlink client - direwolf # AX.25 packet modem - chirp # Radio programming tool - hamlib # Ham radio control libraries - trustedqsl # Logbook of the World (LoTW) - # ===== SDR / RF ===== - # sdrpp — removed for aarch64 cross-compile bootstrap (glfw/wxPython fails) - # gqrx — removed for aarch64 cross-compile bootstrap (Qt5 cascade fails) - rtl-sdr # RTL-SDR drivers & utilities - inspectrum # Offline signal analysis - soapysdr-with-plugins # SoapySDR + hardware support plugins - # ===== Mesh / LoRa ===== - reticulumStack # Reticulum Network Stack - lxmf # LXMF messaging protocol - nomadnet # Nomad Network client - # ===== Security ===== - nmap - aircrack-ng - kismet # Wi-Fi monitor / IDS - bettercap # MITM/network attack framework - wireshark-cli # Packet analyzer - john # John the Ripper - sqlmap # SQL injection tool - # ===== GPS / Maps ===== - # foxtrotgps — removed for aarch64 cross-compile bootstrap (GTK2 fails) - # viking — removed for aarch64 cross-compile bootstrap (GTK3 fails) - gpsbabel # GPS data conversion - ]; - # ============================================================ - # Reticulum Service (rnsd) - # ============================================================ - systemd.services.rnsd = { - description = "Reticulum Network Stack Daemon"; - wants = [ "network-online.target" ]; - after = [ "network-online.target" ]; - wantedBy = [ "multi-user.target" ]; - serviceConfig = { - User = "gortium"; - Group = "gortium"; - ExecStart = "${pkgs.reticulumStack}/bin/rnsd"; - Restart = "always"; - RestartSec = "10s"; - LimitNOFILE = 65536; - }; - }; - # ============================================================ - # Kismet Service (Wi-Fi monitoring / mesh node) - # ============================================================ - systemd.services.kismet = { - description = "Kismet Wi-Fi Monitor & IDS"; - wants = [ "network-online.target" ]; - after = [ "network-online.target" ]; - wantedBy = [ "multi-user.target" ]; - serviceConfig = { - User = "gortium"; - Group = "kismet"; - ExecStart = "${pkgs.kismet}/bin/kismet -c wlan0 --log-base=/home/gortium/kismet_logs --no-nc-ui"; - Restart = "always"; - RestartSec = "10s"; - }; - }; - # ============================================================ - # Kernel modules for SDR and radio - # ============================================================ - boot.kernelModules = [ - "88x2bu" # Realtek 8812/8821BU USB WiFi - "rtl8xxxu" # RTL8188/8192/8723 USB WiFi - "rtl2832_sdr" # RTL-SDR kernel module - "dvb_usb_rtl28xxu" # RTL-SDR DVB-T - ]; - # ============================================================ - # Extra udev rules for SDR and HAM radio devices - # ============================================================ - services.udev.packages = with pkgs; [ rtl-sdr ]; - # ============================================================ - # Enable IPv6 for Reticulum mesh - # ============================================================ - networking.enableIPv6 = true; - # ============================================================ - # Firewall - # ============================================================ - networking.firewall.allowedTCPPorts = [ 22 ]; - networking.firewall.allowedUDPPorts = [ ]; - # ============================================================ - # agenix-rekey — automatic secret re-encryption at deploy time - # ============================================================ - age.rekey = { - # Master identities for encrypting secrets (on Thierry's laptop) - masterIdentities = [ - "/home/gortium/.ssh/gortium_ssh_key" - ]; - # uConsole SSH host pubkey — for automatic rekey at build time - # Once uConsole is deployed, replace with actual pubkey from: - # ssh-keyscan uConsole.local | ssh-to-age - hostPubkey = "age1qyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqs3290gq"; # dummy — replace after bootstrap - }; - # Enable remote builder (distributed build via lazyworkhorse server) - services.remoteBuilder.enable = true; -} - - # Pipewire overlay: drop libcamera (fixes aarch64 cross-compile — rpi-pisp blocks) - nixpkgs.overlays = [ - (final: prev: { - pipewire = prev.pipewire.override { libcamera = null; }; - }) diff --git a/hosts/uconsole-cm5/configuration.nix.bak.hermes b/hosts/uconsole-cm5/configuration.nix.bak.hermes deleted file mode 100644 index ad52cb8..0000000 --- a/hosts/uconsole-cm5/configuration.nix.bak.hermes +++ /dev/null @@ -1,201 +0,0 @@ -{ config, lib, pkgs, keys, ... }: -{ - networking.hostName = "uConsole"; - time.timeZone = "America/Montreal"; - i18n.defaultLocale = "en_CA.UTF-8"; - system.stateVersion = "25.11"; - # Boot & Hardware - boot.loader.raspberry-pi.bootloader = "kernel"; - # SSH — root access avec clés gortium + ai-worker - services.openssh = { - enable = true; - settings = { - PermitRootLogin = lib.mkForce "prohibit-password"; - PasswordAuthentication = lib.mkForce false; - }; - }; - users.users.root.openssh.authorizedKeys.keys = with keys; [ - users.gortium.main - users.ai-worker.main - ]; - # Age secret for gortium password (file created by user) - age.secrets.gortium_password = { - file = ../../secrets/gortium_password.age; - }; - # WiFi via NetworkManager - networking.networkmanager.enable = true; - # Firmware - hardware.enableRedistributableFirmware = true; - # Hyprland Wayland compositor (manual start — no SDDM) - programs.hyprland = { - enable = true; - xwayland.enable = true; - }; - # HackerGadgets AIO v2 board - hardware.uconsole-cm5-aio-v2 = { - enable = true; - bootRails = { - GPS = false; - LORA = false; - SDR = false; - USB = false; - }; - enableGPS = false; - }; - # User - users.users.gortium = { - isNormalUser = true; - extraGroups = [ "wheel" "networkmanager" "video" "dialout" "kismet" ]; - hashedPasswordFile = config.age.secrets.gortium_password.path; - openssh.authorizedKeys.keys = [ - keys.users.gortium.main - keys.users.gortium.gitea - ]; - }; - security.sudo.extraRules = [ - { - users = [ "gortium" ]; - commands = [{ - command = "ALL"; - options = [ "NOPASSWD" ]; - }]; - } - ]; - # ============================================================ - # Package groups - # ============================================================ - # ============================================================ - # CROSS-COMPILE REMOVALS — packages removed for aarch64 bootstrap - # ============================================================ - # These packages fail to cross-compile for aarch64. - # Install them natively AFTER the first successful switch. - # - # Removed: Reason: - # hashcat — Makefile calls gcc directly (cross-compiler not used) - # neovim — Same as hashcat: Makefile calls gcc directly (cross-compiler not used) - # clamav — cmake try_run + Rust proc-macro linker for aarch64 - # sdrpp — glfw/wxPython cross-compile fails - # gqrx — Qt5 cross-compile cascade fails - # emacs-pgtk → emacs-nox — GTK3 + mailutils → gss → shishi chain - # viking — GTK3 GPS map editor - # foxtrotgps — GTK2 GPS app - # js8call — QtQuick3D dep - # wsjtx — qtbase/Qt5 linker fails (collect2: ld returned 1) - # fldigi — same: qtbase/Qt5 linker fails - # ============================================================ - environment.systemPackages = with pkgs; [ - # ===== Base ===== - # emacs-pgtk — removed for bootstrap (GTK3 cross-compile fails) - # emacs-nox — removed for bootstrap (depends on mailutils -> gss -> shishi, cross-compile fails) - git - ripgrep - fd - htop - tmux - # ===== HAM Radio ===== - # wsjtx — removed for aarch64 bootstrap (qtbase/Qt5 cross-compile linker fails) - # fldigi — removed for aarch64 bootstrap (qtbase/Qt5 cross-compile linker fails) - pat # Winlink client - direwolf # AX.25 packet modem - chirp # Radio programming tool - hamlib # Ham radio control libraries - trustedqsl # Logbook of the World (LoTW) - # ===== SDR / RF ===== - # sdrpp — removed for aarch64 cross-compile bootstrap (glfw/wxPython fails) - # gqrx — removed for aarch64 cross-compile bootstrap (Qt5 cascade fails) - rtl-sdr # RTL-SDR drivers & utilities - inspectrum # Offline signal analysis - soapysdr-with-plugins # SoapySDR + hardware support plugins - # ===== Mesh / LoRa ===== - reticulumStack # Reticulum Network Stack - lxmf # LXMF messaging protocol - nomadnet # Nomad Network client - # ===== Security ===== - nmap - aircrack-ng - kismet # Wi-Fi monitor / IDS - bettercap # MITM/network attack framework - wireshark-cli # Packet analyzer - john # John the Ripper - sqlmap # SQL injection tool - # ===== GPS / Maps ===== - # foxtrotgps — removed for aarch64 cross-compile bootstrap (GTK2 fails) - # viking — removed for aarch64 cross-compile bootstrap (GTK3 fails) - gpsbabel # GPS data conversion - ]; - # ============================================================ - # Reticulum Service (rnsd) - # ============================================================ - systemd.services.rnsd = { - description = "Reticulum Network Stack Daemon"; - wants = [ "network-online.target" ]; - after = [ "network-online.target" ]; - wantedBy = [ "multi-user.target" ]; - serviceConfig = { - User = "gortium"; - Group = "gortium"; - ExecStart = "${pkgs.reticulumStack}/bin/rnsd"; - Restart = "always"; - RestartSec = "10s"; - LimitNOFILE = 65536; - }; - }; - # ============================================================ - # Kismet Service (Wi-Fi monitoring / mesh node) - # ============================================================ - systemd.services.kismet = { - description = "Kismet Wi-Fi Monitor & IDS"; - wants = [ "network-online.target" ]; - after = [ "network-online.target" ]; - wantedBy = [ "multi-user.target" ]; - serviceConfig = { - User = "gortium"; - Group = "kismet"; - ExecStart = "${pkgs.kismet}/bin/kismet -c wlan0 --log-base=/home/gortium/kismet_logs --no-nc-ui"; - Restart = "always"; - RestartSec = "10s"; - }; - }; - # ============================================================ - # Kernel modules for SDR and radio - # ============================================================ - boot.kernelModules = [ - "88x2bu" # Realtek 8812/8821BU USB WiFi - "rtl8xxxu" # RTL8188/8192/8723 USB WiFi - "rtl2832_sdr" # RTL-SDR kernel module - "dvb_usb_rtl28xxu" # RTL-SDR DVB-T - ]; - # ============================================================ - # Extra udev rules for SDR and HAM radio devices - # ============================================================ - services.udev.packages = with pkgs; [ rtl-sdr ]; - # ============================================================ - # Enable IPv6 for Reticulum mesh - # ============================================================ - networking.enableIPv6 = true; - # ============================================================ - # Firewall - # ============================================================ - networking.firewall.allowedTCPPorts = [ 22 ]; - networking.firewall.allowedUDPPorts = [ ]; - # ============================================================ - # agenix-rekey — automatic secret re-encryption at deploy time - # ============================================================ - age.rekey = { - # Master identities for encrypting secrets (on Thierry's laptop) - masterIdentities = [ - "/home/gortium/.ssh/gortium_ssh_key" - ]; - # uConsole SSH host pubkey — for automatic rekey at build time - # Once uConsole is deployed, replace with actual pubkey from: - # ssh-keyscan uConsole.local | ssh-to-age - hostPubkey = "age1qyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqs3290gq"; # dummy — replace after bootstrap - }; - - # Pipewire overlay: drop libcamera (fixes aarch64 cross-compile — rpi-pisp blocks) - nixpkgs.overlays = [ - (final: prev: { - pipewire = prev.pipewire.override { libcamera = null; }; - }) - ]; -} -- 2.49.1 From da3363e894bc60ae2f1f0d98a978a2a3e51f4340 Mon Sep 17 00:00:00 2001 From: Hermes Date: Sat, 20 Jun 2026 14:40:37 -0400 Subject: [PATCH 126/157] fix: remove chirp for aarch64 cross-compile (wxPython fails with GTK3) --- hosts/uconsole-cm5/configuration.nix | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index be6f34e..4c23890 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -85,6 +85,8 @@ # fldigi — same: qtbase/Qt5 linker fails # gpsbabel — qmake can't find cross-compiler g++ # john — configure script needs python (not in PATH during cross-compile) +# trustedqsl — needs wxWidgets (unavailable in cross-compile) +# chirp — depends on wxPython (fails cross-compile: GTK3 + wx build) # ============================================================ environment.systemPackages = with pkgs; [ # ===== Base ===== @@ -100,9 +102,9 @@ # fldigi — removed for aarch64 bootstrap (qtbase/Qt5 cross-compile linker fails) pat # Winlink client direwolf # AX.25 packet modem - chirp # Radio programming tool + # chirp # Radio programming tool hamlib # Ham radio control libraries - trustedqsl # Logbook of the World (LoTW) + # trustedqsl # Logbook of the World (LoTW) # ===== SDR / RF ===== # sdrpp — removed for aarch64 cross-compile bootstrap (glfw/wxPython fails) # gqrx — removed for aarch64 cross-compile bootstrap (Qt5 cascade fails) -- 2.49.1 From d765ead0202ebe0a0979654e03b434147c4c922d Mon Sep 17 00:00:00 2001 From: Hermes Date: Sat, 20 Jun 2026 15:07:00 -0400 Subject: [PATCH 127/157] fix: kismet --log-base -> --log-prefix (wrong flag), aiov2 pinctrl from raspberrypi-utils not libraspberrypi --- hosts/cyt-pi/configuration.nix | 2 +- hosts/uconsole-cm5/configuration.nix | 2 +- modules/nixos/hardware/uconsole-cm5-aio-v2.nix | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/hosts/cyt-pi/configuration.nix b/hosts/cyt-pi/configuration.nix index 2e33723..f97442f 100644 --- a/hosts/cyt-pi/configuration.nix +++ b/hosts/cyt-pi/configuration.nix @@ -50,7 +50,7 @@ User = "gortium"; Group = "kismet"; ExecStart = '' - ${pkgs.kismet}/bin/kismet -c panda --log-base=/home/gortium/kismet_logs --no-nc-ui + ${pkgs.kismet}/bin/kismet -c panda --log-prefix=/home/gortium/kismet_logs --no-nc-ui ''; Restart = "always"; RestartSec = "10s"; diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index 4c23890..0e72a36 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -156,7 +156,7 @@ serviceConfig = { User = "gortium"; Group = "kismet"; - ExecStart = "${pkgs.kismet}/bin/kismet -c wlan0 --log-base=/home/gortium/kismet_logs --no-nc-ui"; + ExecStart = "${pkgs.kismet}/bin/kismet -c wlan0 --log-prefix=/home/gortium/kismet_logs --no-nc-ui"; Restart = "always"; RestartSec = "10s"; }; diff --git a/modules/nixos/hardware/uconsole-cm5-aio-v2.nix b/modules/nixos/hardware/uconsole-cm5-aio-v2.nix index 7c70505..5973ea3 100644 --- a/modules/nixos/hardware/uconsole-cm5-aio-v2.nix +++ b/modules/nixos/hardware/uconsole-cm5-aio-v2.nix @@ -21,7 +21,7 @@ let applyRailsScript = pkgs.writeShellScript "apply-aio-v2-rails" ( '' set -e - PINCTRL=${pkgs.libraspberrypi}/bin/pinctrl + PINCTRL=${pkgs.raspberrypi-utils}/bin/pinctrl '' + concatStringsSep "" (mapAttrsToList (name: pin: '' if [ "${if cfg.bootRails.${name} then "1" else "0"}" = "1" ]; then @@ -123,7 +123,7 @@ in { # Package the aiov2_ctl tool + pinctrl environment.systemPackages = with pkgs; [ cfg.package - libraspberrypi # provides pinctrl + raspberrypi-utils # provides pinctrl ]; # Boot rail systemd oneshot service -- 2.49.1 From f443e79c174de089521a24f2800d17b301531edc Mon Sep 17 00:00:00 2001 From: Hermes Date: Sat, 20 Jun 2026 15:29:08 -0400 Subject: [PATCH 128/157] fix: dotfiles as flake input (not submodule path) so Nix gets actual files --- flake.nix | 6 +++++- users/gortium/gortium.nix | 2 +- users/gortium/home.nix | 1 - 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/flake.nix b/flake.nix index d4c17b9..6635cfc 100644 --- a/flake.nix +++ b/flake.nix @@ -30,10 +30,14 @@ url = "github:nix-community/home-manager/release-25.11"; inputs.nixpkgs.follows = "nixpkgs-uconsole"; }; + dotfiles = { + url = "git+https://code.lazyworkhorse.net/gortium/dotfiles.git"; + flake = false; + }; }; outputs = { self, nixpkgs, agenix, agenix-rekey, lix - , nixpkgs-uconsole, nixos-uconsole, nixos-raspberrypi + , nixpkgs-uconsole, nixos-uconsole, nixos-raspberrypi, dotfiles , home-manager , ... }@inputs: let diff --git a/users/gortium/gortium.nix b/users/gortium/gortium.nix index 6781a43..2a33c0c 100644 --- a/users/gortium/gortium.nix +++ b/users/gortium/gortium.nix @@ -1,5 +1,5 @@ { pkgs, inputs, config, keys, ... }: { - home-manager.extraSpecialArgs = { inherit (config.networking) hostName; dotfiles = ../../assets/dotfiles; }; + home-manager.extraSpecialArgs = { inherit (config.networking) hostName; dotfiles = inputs.dotfiles.outPath # flake input (not submodule); }; home-manager.users.gortium = import ./home.nix; users.users.gortium = { isNormalUser = true; diff --git a/users/gortium/home.nix b/users/gortium/home.nix index 8fab8d8..6f95e09 100644 --- a/users/gortium/home.nix +++ b/users/gortium/home.nix @@ -1,7 +1,6 @@ { pkgs, lib, config, inputs, hostName, ... }: let - dotfiles = ../../assets/dotfiles; isUconsole = hostName == "uConsole"; in { home.username = "gortium"; -- 2.49.1 From ceca90845755db067e9187cc1ddd18f19b2092ef Mon Sep 17 00:00:00 2001 From: Hermes Date: Sat, 20 Jun 2026 16:01:00 -0400 Subject: [PATCH 129/157] fix: replace dotfiles flake input with self.submodules=true (git submodule) --- flake.nix | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/flake.nix b/flake.nix index 6635cfc..2d3ec5d 100644 --- a/flake.nix +++ b/flake.nix @@ -26,18 +26,15 @@ url = "github:gortium/nixos-raspberrypi/cm5-cross-v1"; inputs.nixpkgs.follows = "nixpkgs-uconsole"; }; + self.submodules = true; home-manager = { url = "github:nix-community/home-manager/release-25.11"; inputs.nixpkgs.follows = "nixpkgs-uconsole"; }; - dotfiles = { - url = "git+https://code.lazyworkhorse.net/gortium/dotfiles.git"; - flake = false; - }; }; outputs = { self, nixpkgs, agenix, agenix-rekey, lix - , nixpkgs-uconsole, nixos-uconsole, nixos-raspberrypi, dotfiles + , nixpkgs-uconsole, nixos-uconsole, nixos-raspberrypi , home-manager , ... }@inputs: let -- 2.49.1 From 7827638c5af06cc0a208c5e24cba02c988dd330d Mon Sep 17 00:00:00 2001 From: Hermes Date: Sat, 20 Jun 2026 16:01:37 -0400 Subject: [PATCH 130/157] fix: dotfiles path from submodule, not flake input --- users/gortium/gortium.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/users/gortium/gortium.nix b/users/gortium/gortium.nix index 2a33c0c..bf4845d 100644 --- a/users/gortium/gortium.nix +++ b/users/gortium/gortium.nix @@ -1,5 +1,5 @@ { pkgs, inputs, config, keys, ... }: { - home-manager.extraSpecialArgs = { inherit (config.networking) hostName; dotfiles = inputs.dotfiles.outPath # flake input (not submodule); }; + home-manager.extraSpecialArgs = { inherit (config.networking) hostName; dotfiles = ./. + "/assets/dotfiles"; # git submodule (not flake input) }; home-manager.users.gortium = import ./home.nix; users.users.gortium = { isNormalUser = true; -- 2.49.1 From 60a0bcfdd68a88ea9eb755bd60a76a921bc8a804 Mon Sep 17 00:00:00 2001 From: Hermes Date: Sat, 20 Jun 2026 16:02:34 -0400 Subject: [PATCH 131/157] fix: dotfiles path via self (submodule), fix Nix syntax --- users/gortium/gortium.nix | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/users/gortium/gortium.nix b/users/gortium/gortium.nix index bf4845d..8598d74 100644 --- a/users/gortium/gortium.nix +++ b/users/gortium/gortium.nix @@ -1,5 +1,8 @@ -{ pkgs, inputs, config, keys, ... }: { - home-manager.extraSpecialArgs = { inherit (config.networking) hostName; dotfiles = ./. + "/assets/dotfiles"; # git submodule (not flake input) }; +{ pkgs, inputs, config, keys, self, ... }: { + home-manager.extraSpecialArgs = { + inherit (config.networking) hostName; + dotfiles = self + "/assets/dotfiles"; + }; home-manager.users.gortium = import ./home.nix; users.users.gortium = { isNormalUser = true; -- 2.49.1 From eeb10db5edbefa8ecf4469118dc58dd54e2317e7 Mon Sep 17 00:00:00 2001 From: Hermes Date: Sat, 20 Jun 2026 16:03:58 -0400 Subject: [PATCH 132/157] fix: define dotfiles as local path in home.nix (via submodule), fix swaync name --- users/gortium/gortium.nix | 3 +-- users/gortium/home.nix | 27 ++++++++++++++++++++++----- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/users/gortium/gortium.nix b/users/gortium/gortium.nix index 8598d74..b25d877 100644 --- a/users/gortium/gortium.nix +++ b/users/gortium/gortium.nix @@ -1,7 +1,6 @@ -{ pkgs, inputs, config, keys, self, ... }: { +{ pkgs, inputs, config, keys, ... }: { home-manager.extraSpecialArgs = { inherit (config.networking) hostName; - dotfiles = self + "/assets/dotfiles"; }; home-manager.users.gortium = import ./home.nix; users.users.gortium = { diff --git a/users/gortium/home.nix b/users/gortium/home.nix index 6f95e09..7ee4ac3 100644 --- a/users/gortium/home.nix +++ b/users/gortium/home.nix @@ -2,6 +2,7 @@ let isUconsole = hostName == "uConsole"; + dotfiles = ../../assets/dotfiles; in { home.username = "gortium"; home.homeDirectory = "/home/gortium"; @@ -53,12 +54,28 @@ in { git zsh tmux starship neovim kitty btop yazi ripgrep fd fzf - ] ++ lib.optionals (!isUconsole) [ - waybar wofi swww hyprshot - ] ++ lib.optionals isUconsole [ - brightnessctl + htop unzip wget jq + hyprland hyprlock hypridle hyprpaper + waybar wofi dunst + libnotify mako + swaynotificationcenter + networkmanagerapplet + pavucontrol ]; + programs.bash.enable = true; programs.zsh.enable = true; - programs.starship.enable = true; + + xdg.userDirs = { + enable = true; + createDirectories = true; + desktop = "$HOME/desktop"; + documents = "$HOME/documents"; + download = "$HOME/downloads"; + music = "$HOME/music"; + pictures = "$HOME/pictures"; + publicShare = "$HOME/public"; + templates = "$HOME/templates"; + videos = "$HOME/videos"; + }; } -- 2.49.1 From c430427617e749e3e7fc2eae115b51b3f7d7b07c Mon Sep 17 00:00:00 2001 From: Hermes Date: Sat, 20 Jun 2026 16:22:20 -0400 Subject: [PATCH 133/157] fix: update dotfiles submodule for uConsole transform+keyboard --- assets/dotfiles | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/dotfiles b/assets/dotfiles index f453874..c659d00 160000 --- a/assets/dotfiles +++ b/assets/dotfiles @@ -1 +1 @@ -Subproject commit f45387456b4d1f594e2d623366248ece64f50b25 +Subproject commit c659d000986645c998514522504526ea8f617ea1 -- 2.49.1 From 095fa4c200f702427ca96155f1041ca07bcd8868 Mon Sep 17 00:00:00 2001 From: Hermes Date: Sat, 20 Jun 2026 16:25:06 -0400 Subject: [PATCH 134/157] fix: add .zshrc to home-manager dotfiles --- users/gortium/home.nix | 3 +++ 1 file changed, 3 insertions(+) diff --git a/users/gortium/home.nix b/users/gortium/home.nix index 7ee4ac3..9b509b2 100644 --- a/users/gortium/home.nix +++ b/users/gortium/home.nix @@ -10,6 +10,9 @@ in { programs.home-manager.enable = true; home.file = { + # zsh + ".zshrc".source = "${dotfiles}/zsh/.zshrc"; + # tmux ".tmux.conf".source = "${dotfiles}/tmux/.tmux.conf"; -- 2.49.1 From 256979e6e5fe222e2254a2167cfcdeeded9a6757 Mon Sep 17 00:00:00 2001 From: Hermes Date: Sat, 20 Jun 2026 16:25:21 -0400 Subject: [PATCH 135/157] fix: update dotfiles submodule for uConsole keyboard docs --- assets/dotfiles | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/dotfiles b/assets/dotfiles index c659d00..f507d53 160000 --- a/assets/dotfiles +++ b/assets/dotfiles @@ -1 +1 @@ -Subproject commit c659d000986645c998514522504526ea8f617ea1 +Subproject commit f507d53c42da90b3481eae1c3f0ec37bd711ab8e -- 2.49.1 From 3ce550691ca98b8d7d4e5fd7d2c2c86ac82601d9 Mon Sep 17 00:00:00 2001 From: Hermes Date: Sat, 20 Jun 2026 16:25:50 -0400 Subject: [PATCH 136/157] fix: use zsh.initExtra for dotfiles config (no home.file conflict) --- users/gortium/home.nix | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/users/gortium/home.nix b/users/gortium/home.nix index 9b509b2..f0a04f8 100644 --- a/users/gortium/home.nix +++ b/users/gortium/home.nix @@ -10,9 +10,6 @@ in { programs.home-manager.enable = true; home.file = { - # zsh - ".zshrc".source = "${dotfiles}/zsh/.zshrc"; - # tmux ".tmux.conf".source = "${dotfiles}/tmux/.tmux.conf"; @@ -53,6 +50,12 @@ in { else "${dotfiles}/hypr/.config/hypr/hosts/laptop.conf"; }; + programs.bash.enable = true; + programs.zsh = { + enable = true; + initExtra = builtins.readFile "${dotfiles}/zsh/.zshrc"; + }; + home.packages = with pkgs; [ git zsh tmux starship neovim kitty @@ -66,9 +69,6 @@ in { pavucontrol ]; - programs.bash.enable = true; - programs.zsh.enable = true; - xdg.userDirs = { enable = true; createDirectories = true; -- 2.49.1 From 1ab11b76d6406509e975a3461a35511a091a6f0e Mon Sep 17 00:00:00 2001 From: Hermes Date: Sat, 20 Jun 2026 17:01:59 -0400 Subject: [PATCH 137/157] chore: update dotfiles submodule for per-host --- assets/dotfiles | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/dotfiles b/assets/dotfiles index f507d53..c40210a 160000 --- a/assets/dotfiles +++ b/assets/dotfiles @@ -1 +1 @@ -Subproject commit f507d53c42da90b3481eae1c3f0ec37bd711ab8e +Subproject commit c40210ab31e8a8c3f05c4a84d626866b9cac176e -- 2.49.1 From 7b3a5802a512acd89f588e109bcee0624baad11d Mon Sep 17 00:00:00 2001 From: Hermes Date: Sat, 20 Jun 2026 17:35:01 -0400 Subject: [PATCH 138/157] fix: update dotfiles submodule --- assets/dotfiles | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/dotfiles b/assets/dotfiles index c40210a..dfa6896 160000 --- a/assets/dotfiles +++ b/assets/dotfiles @@ -1 +1 @@ -Subproject commit c40210ab31e8a8c3f05c4a84d626866b9cac176e +Subproject commit dfa689633f4a89b6cc5e9c73e9e07dbb3b8d8881 -- 2.49.1 From 6c34b92186b0eb414bd9d822073e66419f9ed5b1 Mon Sep 17 00:00:00 2001 From: Hermes Date: Sat, 20 Jun 2026 17:48:15 -0400 Subject: [PATCH 139/157] fix: update dotfiles submodule for host/ rename --- assets/dotfiles | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/dotfiles b/assets/dotfiles index dfa6896..fe90a0f 160000 --- a/assets/dotfiles +++ b/assets/dotfiles @@ -1 +1 @@ -Subproject commit dfa689633f4a89b6cc5e9c73e9e07dbb3b8d8881 +Subproject commit fe90a0f60774089d40eae98b46494c024b464d65 -- 2.49.1 From 905998466c71d8284cbade6fa6c9d15fc77efbc6 Mon Sep 17 00:00:00 2001 From: Hermes Date: Sat, 20 Jun 2026 17:50:13 -0400 Subject: [PATCH 140/157] fix: update home.nix host/ paths after dotfiles rename --- hosts/uconsole-cm5/configuration.nix.tmp | 80 ++++++++++++++++++++++++ users/gortium/home.nix | 4 +- 2 files changed, 82 insertions(+), 2 deletions(-) create mode 100644 hosts/uconsole-cm5/configuration.nix.tmp diff --git a/hosts/uconsole-cm5/configuration.nix.tmp b/hosts/uconsole-cm5/configuration.nix.tmp new file mode 100644 index 0000000..0c4fa82 --- /dev/null +++ b/hosts/uconsole-cm5/configuration.nix.tmp @@ -0,0 +1,80 @@ + + # Hyprland config — Ctrl+Alt = Super (no hardware Super key on uConsole) + environment.etc."hypr/hyprland.conf".text = '' + $mainMod = CTRL ALT + + input { + kb_layout = ca:eng + kb_options = ctrl:nocaps + numlock_by_default = true + follow_mouse = 1 + } + + general { + gaps_in = 5 + gaps_out = 10 + border_size = 2 + col.active_border = rgba(a3be8cff) + col.inactive_border = rgba(434c5eff) + layout = dwindle + } + + decoration { + rounding = 4 + active_opacity = 1.0 + inactive_opacity = 0.85 + blur { enabled = false } + } + + animations { enabled = false } + + bind = $mainMod, Return, exec, foot + bind = $mainMod, Q, killactive + bind = $mainMod, F, fullscreen + bind = $mainMod, Space, togglefloating + + bind = $mainMod, H, movefocus, l + bind = $mainMod, L, movefocus, r + bind = $mainMod, K, movefocus, u + bind = $mainMod, J, movefocus, d + bind = $mainMod, left, movefocus, l + bind = $mainMod, right, movefocus, r + bind = $mainMod, up, movefocus, u + bind = $mainMod, down, movefocus, d + + bind = $mainMod SHIFT, H, movewindow, l + bind = $mainMod SHIFT, L, movewindow, r + bind = $mainMod SHIFT, K, movewindow, u + bind = $mainMod SHIFT, J, movewindow, d + + bind = $mainMod, 1, workspace, 1 + bind = $mainMod, 2, workspace, 2 + bind = $mainMod, 3, workspace, 3 + bind = $mainMod, 4, workspace, 4 + bind = $mainMod, 5, workspace, 5 + bind = $mainMod, 6, workspace, 6 + bind = $mainMod, 7, workspace, 7 + bind = $mainMod, 8, workspace, 8 + bind = $mainMod, 9, workspace, 9 + bind = $mainMod, 0, workspace, 10 + + bind = $mainMod SHIFT, 1, movetoworkspace, 1 + bind = $mainMod SHIFT, 2, movetoworkspace, 2 + bind = $mainMod SHIFT, 3, movetoworkspace, 3 + bind = $mainMod SHIFT, 4, movetoworkspace, 4 + bind = $mainMod SHIFT, 5, movetoworkspace, 5 + bind = $mainMod SHIFT, 6, movetoworkspace, 6 + bind = $mainMod SHIFT, 7, movetoworkspace, 7 + bind = $mainMod SHIFT, 8, movetoworkspace, 8 + bind = $mainMod SHIFT, 9, movetoworkspace, 9 + bind = $mainMod SHIFT, 0, movetoworkspace, 10 + + bind = $mainMod, mouse_down, workspace, e+1 + bind = $mainMod, mouse_up, workspace, e-1 + + bind = $mainMod, grave, togglespecialworkspace + bind = $mainMod SHIFT, grave, movetoworkspace, special + + exec-once = foot --server + ''; +} diff --git a/users/gortium/home.nix b/users/gortium/home.nix index f0a04f8..66769d4 100644 --- a/users/gortium/home.nix +++ b/users/gortium/home.nix @@ -46,8 +46,8 @@ in { # hyprland — host-specific monitor config ".config/hypr/host/monitors.conf".source = if isUconsole - then "${dotfiles}/hypr/.config/hypr/hosts/uconsole.conf" - else "${dotfiles}/hypr/.config/hypr/hosts/laptop.conf"; + then "${dotfiles}/hypr/.config/hypr/host/uconsole.conf" + else "${dotfiles}/hypr/.config/hypr/host/laptop.conf"; }; programs.bash.enable = true; -- 2.49.1 From 282b4bc229f6b30b3e65800a1a533c6a354182de Mon Sep 17 00:00:00 2001 From: Hermes Date: Sat, 20 Jun 2026 17:50:18 -0400 Subject: [PATCH 141/157] chore: remove stale temp file --- hosts/uconsole-cm5/configuration.nix.tmp | 80 ------------------------ 1 file changed, 80 deletions(-) delete mode 100644 hosts/uconsole-cm5/configuration.nix.tmp diff --git a/hosts/uconsole-cm5/configuration.nix.tmp b/hosts/uconsole-cm5/configuration.nix.tmp deleted file mode 100644 index 0c4fa82..0000000 --- a/hosts/uconsole-cm5/configuration.nix.tmp +++ /dev/null @@ -1,80 +0,0 @@ - - # Hyprland config — Ctrl+Alt = Super (no hardware Super key on uConsole) - environment.etc."hypr/hyprland.conf".text = '' - $mainMod = CTRL ALT - - input { - kb_layout = ca:eng - kb_options = ctrl:nocaps - numlock_by_default = true - follow_mouse = 1 - } - - general { - gaps_in = 5 - gaps_out = 10 - border_size = 2 - col.active_border = rgba(a3be8cff) - col.inactive_border = rgba(434c5eff) - layout = dwindle - } - - decoration { - rounding = 4 - active_opacity = 1.0 - inactive_opacity = 0.85 - blur { enabled = false } - } - - animations { enabled = false } - - bind = $mainMod, Return, exec, foot - bind = $mainMod, Q, killactive - bind = $mainMod, F, fullscreen - bind = $mainMod, Space, togglefloating - - bind = $mainMod, H, movefocus, l - bind = $mainMod, L, movefocus, r - bind = $mainMod, K, movefocus, u - bind = $mainMod, J, movefocus, d - bind = $mainMod, left, movefocus, l - bind = $mainMod, right, movefocus, r - bind = $mainMod, up, movefocus, u - bind = $mainMod, down, movefocus, d - - bind = $mainMod SHIFT, H, movewindow, l - bind = $mainMod SHIFT, L, movewindow, r - bind = $mainMod SHIFT, K, movewindow, u - bind = $mainMod SHIFT, J, movewindow, d - - bind = $mainMod, 1, workspace, 1 - bind = $mainMod, 2, workspace, 2 - bind = $mainMod, 3, workspace, 3 - bind = $mainMod, 4, workspace, 4 - bind = $mainMod, 5, workspace, 5 - bind = $mainMod, 6, workspace, 6 - bind = $mainMod, 7, workspace, 7 - bind = $mainMod, 8, workspace, 8 - bind = $mainMod, 9, workspace, 9 - bind = $mainMod, 0, workspace, 10 - - bind = $mainMod SHIFT, 1, movetoworkspace, 1 - bind = $mainMod SHIFT, 2, movetoworkspace, 2 - bind = $mainMod SHIFT, 3, movetoworkspace, 3 - bind = $mainMod SHIFT, 4, movetoworkspace, 4 - bind = $mainMod SHIFT, 5, movetoworkspace, 5 - bind = $mainMod SHIFT, 6, movetoworkspace, 6 - bind = $mainMod SHIFT, 7, movetoworkspace, 7 - bind = $mainMod SHIFT, 8, movetoworkspace, 8 - bind = $mainMod SHIFT, 9, movetoworkspace, 9 - bind = $mainMod SHIFT, 0, movetoworkspace, 10 - - bind = $mainMod, mouse_down, workspace, e+1 - bind = $mainMod, mouse_up, workspace, e-1 - - bind = $mainMod, grave, togglespecialworkspace - bind = $mainMod SHIFT, grave, movetoworkspace, special - - exec-once = foot --server - ''; -} -- 2.49.1 From 7899bf28f281e38fc64dbca369e982b92f1a909c Mon Sep 17 00:00:00 2001 From: Hermes Date: Sat, 20 Jun 2026 17:51:50 -0400 Subject: [PATCH 142/157] fix: sync dotfiles submodule, home.nix paths to hosts/ --- assets/dotfiles | 2 +- users/gortium/home.nix | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/assets/dotfiles b/assets/dotfiles index fe90a0f..fac4a09 160000 --- a/assets/dotfiles +++ b/assets/dotfiles @@ -1 +1 @@ -Subproject commit fe90a0f60774089d40eae98b46494c024b464d65 +Subproject commit fac4a09eebe41b2e9eb6225913c93807dcd1af3b diff --git a/users/gortium/home.nix b/users/gortium/home.nix index 66769d4..3512556 100644 --- a/users/gortium/home.nix +++ b/users/gortium/home.nix @@ -44,10 +44,10 @@ in { ".config/hypr/mocha.conf".source = "${dotfiles}/hypr/.config/hypr/mocha.conf"; # hyprland — host-specific monitor config - ".config/hypr/host/monitors.conf".source = + ".config/hypr/hosts/monitors.conf".source = if isUconsole - then "${dotfiles}/hypr/.config/hypr/host/uconsole.conf" - else "${dotfiles}/hypr/.config/hypr/host/laptop.conf"; + then "${dotfiles}/hypr/.config/hypr/hosts/uconsole.conf" + else "${dotfiles}/hypr/.config/hypr/hosts/laptop.conf"; }; programs.bash.enable = true; -- 2.49.1 From f0fa8ac9427bd543c8705b7305249fba69635c6f Mon Sep 17 00:00:00 2001 From: Hermes Date: Sat, 20 Jun 2026 17:54:16 -0400 Subject: [PATCH 143/157] fix: update dotfiles for transform 3 --- assets/dotfiles | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/dotfiles b/assets/dotfiles index fac4a09..d06a382 160000 --- a/assets/dotfiles +++ b/assets/dotfiles @@ -1 +1 @@ -Subproject commit fac4a09eebe41b2e9eb6225913c93807dcd1af3b +Subproject commit d06a382cbf90defe2a46c9f38c929ab9ec5b4ce9 -- 2.49.1 From bf2500dce898c9a8af08f7689b41784aa42647e9 Mon Sep 17 00:00:00 2001 From: Hermes Date: Sat, 20 Jun 2026 18:16:00 -0400 Subject: [PATCH 144/157] fix: add missing packages (swww, emacs, udiskie, hyprshade) and wallpapers for uConsole --- assets/dotfiles | 2 +- users/gortium/home.nix | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/assets/dotfiles b/assets/dotfiles index d06a382..504daea 160000 --- a/assets/dotfiles +++ b/assets/dotfiles @@ -1 +1 @@ -Subproject commit d06a382cbf90defe2a46c9f38c929ab9ec5b4ce9 +Subproject commit 504daea61eadfbc84853b83508cc7a9b9ddddd48 diff --git a/users/gortium/home.nix b/users/gortium/home.nix index 3512556..166d9e2 100644 --- a/users/gortium/home.nix +++ b/users/gortium/home.nix @@ -34,6 +34,9 @@ in { ".config/wofi/config".source = "${dotfiles}/wofi/.config/wofi/config"; # yazi + + # wallpapers + ".config/wallpapers".source = "${dotfiles}/wallpapers/.config/wallpapers"; ".config/yazi/yazi.toml".source = "${dotfiles}/yazi/.config/yazi/yazi.toml"; # hyprland — common config @@ -65,6 +68,10 @@ in { waybar wofi dunst libnotify mako swaynotificationcenter + swww + emacs + udiskie + hyprshade networkmanagerapplet pavucontrol ]; -- 2.49.1 From a97c68fd8142c1ff5c63ba830d6e662c8ab2841b Mon Sep 17 00:00:00 2001 From: Hermes Date: Sat, 20 Jun 2026 18:16:43 -0400 Subject: [PATCH 145/157] fix: add rtkit and pipewire service for uConsole audio --- hosts/uconsole-cm5/configuration.nix | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index 0e72a36..bf7b63a 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -26,6 +26,14 @@ networking.networkmanager.enable = true; # Firmware hardware.enableRedistributableFirmware = true; + # RealtimeKit for PipeWire audio + security.rtkit.enable = true; + services.pipewire = { + enable = true; + alsa.enable = true; + alsa.support32Bit = true; + pulse.enable = true; + }; # Hyprland Wayland compositor (manual start — no SDDM) programs.hyprland = { enable = true; -- 2.49.1 From 73c12abec243116cd621d9609d747df29b9cae5d Mon Sep 17 00:00:00 2001 From: Hermes Date: Sat, 20 Jun 2026 19:00:39 -0400 Subject: [PATCH 146/157] feat: re-integrate native-build packages (wsjtx, fldigi, chirp, sdrpp, gqrx, inspectrum, hashcat, john, foxtrotgps, viking, gpsbabel, trustedqsl) --- hosts/uconsole-cm5/configuration.nix | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index bf7b63a..549cabe 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -106,18 +106,18 @@ htop tmux # ===== HAM Radio ===== - # wsjtx — removed for aarch64 bootstrap (qtbase/Qt5 cross-compile linker fails) - # fldigi — removed for aarch64 bootstrap (qtbase/Qt5 cross-compile linker fails) + wsjtx # removed for bootstrap - now native + fldigi # removed for bootstrap - now native pat # Winlink client direwolf # AX.25 packet modem - # chirp # Radio programming tool + chirp # Radio programming tool - now native hamlib # Ham radio control libraries - # trustedqsl # Logbook of the World (LoTW) + trustedqsl # Logbook of the World (LoTW) - now native # ===== SDR / RF ===== - # sdrpp — removed for aarch64 cross-compile bootstrap (glfw/wxPython fails) - # gqrx — removed for aarch64 cross-compile bootstrap (Qt5 cascade fails) + sdrpp # removed for bootstrap - now native + gqrx # removed for bootstrap - now native rtl-sdr # RTL-SDR drivers & utilities - # inspectrum # removed for aarch64 bootstrap (Qt5 cross-compile cascade fails) + inspectrum # removed for bootstrap - now native soapysdr-with-plugins # SoapySDR + hardware support plugins # ===== Mesh / LoRa ===== reticulumStack # Reticulum Network Stack @@ -129,12 +129,12 @@ kismet # Wi-Fi monitor / IDS bettercap # MITM/network attack framework wireshark-cli # Packet analyzer - # john # John the Ripper + john # John the Ripper - now native sqlmap # SQL injection tool # ===== GPS / Maps ===== - # foxtrotgps — removed for aarch64 cross-compile bootstrap (GTK2 fails) - # viking — removed for aarch64 cross-compile bootstrap (GTK3 fails) - # gpsbabel # GPS data conversion + foxtrotgps # removed for bootstrap - now native + viking # removed for bootstrap - now native + gpsbabel # GPS data conversion - now native ]; # ============================================================ # Reticulum Service (rnsd) -- 2.49.1 From f51155823e03a394bbba224f64e145a593e08a7f Mon Sep 17 00:00:00 2001 From: Hermes Date: Sat, 20 Jun 2026 19:59:36 -0400 Subject: [PATCH 147/157] =?UTF-8?q?temp:=20comment=20out=20Qt5=20packages?= =?UTF-8?q?=20(wsjtx,=20fldigi,=20sdrpp,=20gqrx,=20inspectrum)=20=E2=80=94?= =?UTF-8?q?=20cross-compile=20fails,=20installed=20via=20nix=20profile=20i?= =?UTF-8?q?nstead?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hosts/uconsole-cm5/configuration.nix | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index 549cabe..8ecc88c 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -106,18 +106,18 @@ htop tmux # ===== HAM Radio ===== - wsjtx # removed for bootstrap - now native - fldigi # removed for bootstrap - now native + # wsjtx — removed for aarch64 bootstrap (Qt5 cross-compile fails) + # fldigi — removed for aarch64 bootstrap (Qt5 cross-compile fails) pat # Winlink client direwolf # AX.25 packet modem chirp # Radio programming tool - now native hamlib # Ham radio control libraries trustedqsl # Logbook of the World (LoTW) - now native # ===== SDR / RF ===== - sdrpp # removed for bootstrap - now native - gqrx # removed for bootstrap - now native + # sdrpp — removed for aarch64 cross-compile bootstrap (glfw/wxPython fails) + # gqrx — removed for aarch64 cross-compile bootstrap (Qt5 cascade fails) rtl-sdr # RTL-SDR drivers & utilities - inspectrum # removed for bootstrap - now native + # inspectrum — removed for aarch64 bootstrap (Qt5 cross-compile cascade fails) soapysdr-with-plugins # SoapySDR + hardware support plugins # ===== Mesh / LoRa ===== reticulumStack # Reticulum Network Stack -- 2.49.1 From 14755f1ea61f73f5d6aa04346ee5bb605041a23c Mon Sep 17 00:00:00 2001 From: Hermes Date: Sat, 20 Jun 2026 20:01:36 -0400 Subject: [PATCH 148/157] =?UTF-8?q?revert=20native-build=20packages=20?= =?UTF-8?q?=E2=80=94=20cross-compile=20still=20fails=20for=20Qt5/gpsbabel/?= =?UTF-8?q?john,=20install=20via=20nix=20profile=20instead?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hosts/uconsole-cm5/configuration.nix | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index 8ecc88c..bf7b63a 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -106,18 +106,18 @@ htop tmux # ===== HAM Radio ===== - # wsjtx — removed for aarch64 bootstrap (Qt5 cross-compile fails) - # fldigi — removed for aarch64 bootstrap (Qt5 cross-compile fails) + # wsjtx — removed for aarch64 bootstrap (qtbase/Qt5 cross-compile linker fails) + # fldigi — removed for aarch64 bootstrap (qtbase/Qt5 cross-compile linker fails) pat # Winlink client direwolf # AX.25 packet modem - chirp # Radio programming tool - now native + # chirp # Radio programming tool hamlib # Ham radio control libraries - trustedqsl # Logbook of the World (LoTW) - now native + # trustedqsl # Logbook of the World (LoTW) # ===== SDR / RF ===== # sdrpp — removed for aarch64 cross-compile bootstrap (glfw/wxPython fails) # gqrx — removed for aarch64 cross-compile bootstrap (Qt5 cascade fails) rtl-sdr # RTL-SDR drivers & utilities - # inspectrum — removed for aarch64 bootstrap (Qt5 cross-compile cascade fails) + # inspectrum # removed for aarch64 bootstrap (Qt5 cross-compile cascade fails) soapysdr-with-plugins # SoapySDR + hardware support plugins # ===== Mesh / LoRa ===== reticulumStack # Reticulum Network Stack @@ -129,12 +129,12 @@ kismet # Wi-Fi monitor / IDS bettercap # MITM/network attack framework wireshark-cli # Packet analyzer - john # John the Ripper - now native + # john # John the Ripper sqlmap # SQL injection tool # ===== GPS / Maps ===== - foxtrotgps # removed for bootstrap - now native - viking # removed for bootstrap - now native - gpsbabel # GPS data conversion - now native + # foxtrotgps — removed for aarch64 cross-compile bootstrap (GTK2 fails) + # viking — removed for aarch64 cross-compile bootstrap (GTK3 fails) + # gpsbabel # GPS data conversion ]; # ============================================================ # Reticulum Service (rnsd) -- 2.49.1 From 84ce9de5cac54b2ab2d1f832f46a9994ce6b5f77 Mon Sep 17 00:00:00 2001 From: Hermes Date: Sat, 20 Jun 2026 20:02:56 -0400 Subject: [PATCH 149/157] restore native-build packages in config (wsjtx, fldigi, chirp, sdrpp, gqrx, inspectrum, john, foxtrotgps, viking, gpsbabel, trustedqsl) --- hosts/uconsole-cm5/configuration.nix | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index bf7b63a..549cabe 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -106,18 +106,18 @@ htop tmux # ===== HAM Radio ===== - # wsjtx — removed for aarch64 bootstrap (qtbase/Qt5 cross-compile linker fails) - # fldigi — removed for aarch64 bootstrap (qtbase/Qt5 cross-compile linker fails) + wsjtx # removed for bootstrap - now native + fldigi # removed for bootstrap - now native pat # Winlink client direwolf # AX.25 packet modem - # chirp # Radio programming tool + chirp # Radio programming tool - now native hamlib # Ham radio control libraries - # trustedqsl # Logbook of the World (LoTW) + trustedqsl # Logbook of the World (LoTW) - now native # ===== SDR / RF ===== - # sdrpp — removed for aarch64 cross-compile bootstrap (glfw/wxPython fails) - # gqrx — removed for aarch64 cross-compile bootstrap (Qt5 cascade fails) + sdrpp # removed for bootstrap - now native + gqrx # removed for bootstrap - now native rtl-sdr # RTL-SDR drivers & utilities - # inspectrum # removed for aarch64 bootstrap (Qt5 cross-compile cascade fails) + inspectrum # removed for bootstrap - now native soapysdr-with-plugins # SoapySDR + hardware support plugins # ===== Mesh / LoRa ===== reticulumStack # Reticulum Network Stack @@ -129,12 +129,12 @@ kismet # Wi-Fi monitor / IDS bettercap # MITM/network attack framework wireshark-cli # Packet analyzer - # john # John the Ripper + john # John the Ripper - now native sqlmap # SQL injection tool # ===== GPS / Maps ===== - # foxtrotgps — removed for aarch64 cross-compile bootstrap (GTK2 fails) - # viking — removed for aarch64 cross-compile bootstrap (GTK3 fails) - # gpsbabel # GPS data conversion + foxtrotgps # removed for bootstrap - now native + viking # removed for bootstrap - now native + gpsbabel # GPS data conversion - now native ]; # ============================================================ # Reticulum Service (rnsd) -- 2.49.1 From 01f8166529bdd394ad0febfd0a1cb9ff759aa04b Mon Sep 17 00:00:00 2001 From: Hermes Date: Sat, 20 Jun 2026 20:04:04 -0400 Subject: [PATCH 150/157] feat: add uConsole as remote builder for aarch64-linux native builds --- hosts/lazyworkhorse/configuration.nix | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/hosts/lazyworkhorse/configuration.nix b/hosts/lazyworkhorse/configuration.nix index db30fd3..c630767 100644 --- a/hosts/lazyworkhorse/configuration.nix +++ b/hosts/lazyworkhorse/configuration.nix @@ -569,3 +569,19 @@ } + # Remote builder — uConsole for aarch64-linux native builds + nix.distributedBuilds = true; + nix.buildMachines = [{ + hostName = "192.168.1.120"; + systems = ["aarch64-linux"]; + maxJobs = 4; + supportedFeatures = ["big-parallel" "nixos-test" "benchmark" "gccarch-armv8-a"]; + sshUser = "builder"; + sshKey = "/home/ai-worker/id_deploy"; + }]; + nix.extraOptions = ' + builders-use-substitutes = true + fallback = true + '; + + -- 2.49.1 From 2a4856e4475432717071dbb1a738f2ea5c3b6089 Mon Sep 17 00:00:00 2001 From: Hermes Date: Sun, 21 Jun 2026 15:07:49 -0400 Subject: [PATCH 151/157] fix: add python3 to aiov2_ctl buildInputs so patchShebangs fixes the shebang --- modules/nixos/hardware/uconsole-cm5-aio-v2.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/nixos/hardware/uconsole-cm5-aio-v2.nix b/modules/nixos/hardware/uconsole-cm5-aio-v2.nix index 5973ea3..cd4047f 100644 --- a/modules/nixos/hardware/uconsole-cm5-aio-v2.nix +++ b/modules/nixos/hardware/uconsole-cm5-aio-v2.nix @@ -47,6 +47,7 @@ let }; dontUnpack = true; + buildInputs = [ pkgs.python3 ]; installPhase = '' mkdir -p $out/bin $out/share/aiov2_ctl/img -- 2.49.1 From 3ec8bab25b5dbbd685bc8c853be8afef5ce43803 Mon Sep 17 00:00:00 2001 From: Hermes Date: Sun, 21 Jun 2026 15:09:53 -0400 Subject: [PATCH 152/157] fix: add python to john nativeBuildInputs for cross-compile (opencl_generate_dynamic_loader.py) --- flake.nix | 3 +++ 1 file changed, 3 insertions(+) diff --git a/flake.nix b/flake.nix index 2d3ec5d..04903ee 100644 --- a/flake.nix +++ b/flake.nix @@ -187,6 +187,9 @@ # perl-ldap fails cross-compile (Module::Install needs dynamic loading) # Strip it from john deps -- the perl scripts that need it are not critical john = prev.john.overrideAttrs (old: { + nativeBuildInputs = (old.nativeBuildInputs or []) ++ [ + prev.buildPackages.python # opencl_generate_dynamic_loader.py needs python + ]; propagatedBuildInputs = builtins.filter (x: x?pname && x.pname != "perl-ldap") (old.propagatedBuildInputs or []); -- 2.49.1 From 16ec40b237b4a544f84e0618bc4cb8b9d27d13c1 Mon Sep 17 00:00:00 2001 From: Hermes Date: Sun, 21 Jun 2026 15:12:12 -0400 Subject: [PATCH 153/157] fix: use python3 + preConfigure symlink for john cross-compile (python not in PATH) --- flake.nix | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 04903ee..321a795 100644 --- a/flake.nix +++ b/flake.nix @@ -188,8 +188,14 @@ # Strip it from john deps -- the perl scripts that need it are not critical john = prev.john.overrideAttrs (old: { nativeBuildInputs = (old.nativeBuildInputs or []) ++ [ - prev.buildPackages.python # opencl_generate_dynamic_loader.py needs python + prev.buildPackages.python3 # opencl_generate_dynamic_loader.py needs python3 ]; + preConfigure = (old.preConfigure or '') + '' + # configure script calls 'python' not 'python3' + mkdir -p "$TMPDIR/bin" + ln -sf "${prev.buildPackages.python3}/bin/python3" "$TMPDIR/bin/python" + export PATH="$TMPDIR/bin:$PATH" + ''; propagatedBuildInputs = builtins.filter (x: x?pname && x.pname != "perl-ldap") (old.propagatedBuildInputs or []); -- 2.49.1 From 8ec9ffe6a9d79c73455ce1ee997aeb31066a0967 Mon Sep 17 00:00:00 2001 From: Hermes Date: Sun, 21 Jun 2026 15:15:01 -0400 Subject: [PATCH 154/157] fix: clean john overlay with python3 + preConfigure symlink for cross-compile --- flake.nix | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/flake.nix b/flake.nix index 321a795..ceabc59 100644 --- a/flake.nix +++ b/flake.nix @@ -188,13 +188,12 @@ # Strip it from john deps -- the perl scripts that need it are not critical john = prev.john.overrideAttrs (old: { nativeBuildInputs = (old.nativeBuildInputs or []) ++ [ - prev.buildPackages.python3 # opencl_generate_dynamic_loader.py needs python3 + prev.buildPackages.python3 # python3 for opencl_generate_dynamic_loader.py ]; - preConfigure = (old.preConfigure or '') + '' - # configure script calls 'python' not 'python3' - mkdir -p "$TMPDIR/bin" - ln -sf "${prev.buildPackages.python3}/bin/python3" "$TMPDIR/bin/python" - export PATH="$TMPDIR/bin:$PATH" + preConfigure = (old.preConfigure or "") + ''' + mkdir -p /tmp/jh-python + ln -sf ${prev.buildPackages.python3}/bin/python3 /tmp/jh-python/python + export PATH=/tmp/jh-python:$PATH ''; propagatedBuildInputs = builtins.filter (x: x?pname && x.pname != "perl-ldap") -- 2.49.1 From 3778069baf912350e52f9aaf1f647153fe189ebd Mon Sep 17 00:00:00 2001 From: Hermes Date: Sun, 21 Jun 2026 15:18:14 -0400 Subject: [PATCH 155/157] fix: use configureFlags to set PYTHON path for john cross-compile --- flake.nix | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/flake.nix b/flake.nix index ceabc59..39b4bd3 100644 --- a/flake.nix +++ b/flake.nix @@ -190,11 +190,9 @@ nativeBuildInputs = (old.nativeBuildInputs or []) ++ [ prev.buildPackages.python3 # python3 for opencl_generate_dynamic_loader.py ]; - preConfigure = (old.preConfigure or "") + ''' - mkdir -p /tmp/jh-python - ln -sf ${prev.buildPackages.python3}/bin/python3 /tmp/jh-python/python - export PATH=/tmp/jh-python:$PATH - ''; + configureFlags = (old.configureFlags or []) ++ [ + "ac_cv_prog_PYTHON=${prev.buildPackages.python3}/bin/python3" + ]; propagatedBuildInputs = builtins.filter (x: x?pname && x.pname != "perl-ldap") (old.propagatedBuildInputs or []); -- 2.49.1 From 7172c7face7012cd0134afa00f0394a319692947 Mon Sep 17 00:00:00 2001 From: gortium Date: Sat, 4 Jul 2026 23:49:16 -0400 Subject: [PATCH 156/157] fix: update compose submodule to fix hermes user ownership --- assets/compose | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/compose b/assets/compose index dab158d..3e62c70 160000 --- a/assets/compose +++ b/assets/compose @@ -1 +1 @@ -Subproject commit dab158da0a869262f227d4d35451960ae11b6642 +Subproject commit 3e62c702de58947737b6e547c35f532e1c4fa0e5 -- 2.49.1 From 5e17fd7dde4326f2ae015b52b8f15aefd6f927f9 Mon Sep 17 00:00:00 2001 From: gortium Date: Sat, 4 Jul 2026 23:50:01 -0400 Subject: [PATCH 157/157] merge: accept remote flake.nix --- flake.nix | 360 +++++++++++------------------------------------------- 1 file changed, 73 insertions(+), 287 deletions(-) diff --git a/flake.nix b/flake.nix index 39b4bd3..50eecca 100644 --- a/flake.nix +++ b/flake.nix @@ -8,320 +8,106 @@ inputs.darwin.follows = ""; inputs.nixpkgs.follows = "nixpkgs"; }; - agenix-rekey = { - url = "github:oddlama/agenix-rekey"; - inputs.nixpkgs.follows = "nixpkgs"; - }; lix = { url = "git+https://git.lix.systems/lix-project/lix?ref=main"; inputs.nixpkgs.follows = "nixpkgs"; }; - nixpkgs-uconsole.url = "github:NixOS/nixpkgs/nixos-25.11"; nixos-uconsole = { - url = "github:gortium/nixos-uconsole/pr/dcs-panel-detection"; - inputs.nixpkgs.follows = "nixpkgs-uconsole"; - inputs.nixos-raspberrypi.follows = "nixos-raspberrypi"; + url = "github:nixos-uconsole/nixos-uconsole"; + inputs.nixpkgs.follows = "nixpkgs"; }; nixos-raspberrypi = { - url = "github:gortium/nixos-raspberrypi/cm5-cross-v1"; - inputs.nixpkgs.follows = "nixpkgs-uconsole"; + url = "github:nvmd/nixos-raspberrypi/v1.20260517.0"; + inputs.nixpkgs.follows = "nixpkgs"; }; - self.submodules = true; home-manager = { url = "github:nix-community/home-manager/release-25.11"; - inputs.nixpkgs.follows = "nixpkgs-uconsole"; + inputs.nixpkgs.follows = "nixpkgs"; }; + self.submodules = true; }; - outputs = { self, nixpkgs, agenix, agenix-rekey, lix - , nixpkgs-uconsole, nixos-uconsole, nixos-raspberrypi - , home-manager - , ... }@inputs: + outputs = { self, nixpkgs, agenix, lix, nixos-uconsole, nixos-raspberrypi, home-manager, ... }@inputs: let system = "x86_64-linux"; keys = import ./lib/keys.nix; - paths = { - flake = "/home/gortium/infra"; - identities = [ - "/home/gortium/.ssh/gortium_ssh_key" - "/etc/ssh/ssh_host_ed25519_key" - "/root/.age/bootstrap.key" ]; - }; - overlays = [ agenix.overlays.default (import ./overlays/reticulum.nix) ]; + paths = import ./lib/paths.nix; + overlays = [ + agenix.overlays.default + (import ./overlays/reticulum.nix) ]; pkgs = import nixpkgs { inherit system overlays; config.allowUnfree = true; - config.permittedInsecurePackages = [ "openclaw-2026.3.12" ]; + config.permittedInsecurePackages = [ + "openclaw-2026.3.12" + ]; }; + devShell = import ./shells/nix_dev.nix { inherit pkgs system agenix; }; - - ############################################################################## - # CROSS-COMPILE WORKAROUNDS — packages that fail aarch64 cross-compile - # - # These packages need NATIVE COMPILATION on the uConsole itself (aarch64). - # They cannot cross-compile from x86_64 for various reasons listed below. - # We work around them in the overlay until we set up distributed builds - # with the uConsole as a native aarch64 builder. - # - # ==== Cross-compile failures ==== - # - # libcamera / libcamera-rpi / libpisp: - # meta.platforms excludes aarch64. pipewire hard-depends on them in nixos-25.11. - # Fix: empty meta.platforms + strip from pipewire buildInputs. - # - # gjs: - # Need native display (GTK3/4 tests) for cross-compile configure. - # Fix: meson -Dskip_gtk_tests=true. - # - # hyprland: - # Qt6Quick missing from aarch64 qtdeclarative, breaks hyprland-qt-support. - # Fix: wrapRuntimeDeps=false (Qt UI components disabled, WM still works). - # - # boost.mpi: - # Boost.Build has no b2 architecture alternatives for ARM. - # Fix: useMpi=false. - # - # perl-ldap (perlPackages.perlldap): - # Module::Install requires Perl dynamic loading (Fcntl) which is - # unavailable in cross-compiled Perl. - # Fix: stripped from john.s propagatedBuildInputs. - # - # john (John the Ripper): - # Indirectly affected — depends on perl-ldap for perl utility scripts. - # Fix: perl-ldap stripped from propagatedBuildInputs (john still works, - # just loses sha-dump.pl etc. LDAP support). - # - # gss (GNU Generic Security Service): - # autogen.sh fails cross-compile. Pulled by mailutils → emacs-pgtk. - # Fix: emacs withMailutils=false. - # - # emacs-pgtk: - # Indirectly affected — depends on mailutils which depends on gss. - # Fix: withMailutils=false (no mail/IMAP within emacs). - # - # qtquick3d (Qt6): - # Qt::Quick not available in aarch64 cross-compile qtdeclarative. - # cmake skips build, ninja has no install target. - # Fix: removed js8call, switched wireshark → wireshark-cli. - # - # js8call: - # REMOVED from system packages. Depends on Qt6 multimedia → qtquick3d. - # - # wireshark-qt: - # SWITCHED to wireshark-cli. Same Qt6 multimedia → qtquick3d chain. - # -# neovim: -# `libnlua0.so` built for aarch64, luajit (x86_64) tries to load it -# during codegen (preload_nlua.lua). No clean override option. -# Fix: remove from system packages + install via native build -# once uConsole is set up as remote builder. -# -# clamav: -# cmake try_run() + Rust proc-macro can't find native linker in -# cross-compile (cc crate uses cross CC, no cc in PATH for build -# scripts). Chain: clamav → system-path → etc → dbus → polkit. -# Fix: remove from system packages; clamscan available from server. - -# -# ==== Remote builder setup (bidirectional) — TODO ==== -# To eliminate cross-compile exceptions, set up distributed builds: -# 1. Create a dedicated `builder` user on both hosts (no shell, home=/var/empty) -# 2. Add the same SSH key to both hosts (symmetric) -# 3. On lazyworkhorse — `nix.buildMachines` pointing to uConsole for aarch64-linux -# 4. On uConsole — `nix.buildMachines` pointing to lazyworkhorse for x86_64-linux -# 5. Remove the uconsoleCrossOverlay workarounds above -# 6. Nix auto-dispatches derivations by `system` — no per-package exceptions needed -# Example buildMachines config: -# Server dispatches aarch64 builds to uConsole (4 cores, less power): -# nix.buildMachines = [{ -# hostName = "uConsole.local"; -# systems = ["aarch64-linux"]; -# maxJobs = 4; -# sshUser = "builder"; -# sshKey = "/etc/ssh/builder_key"; -# }]; -# uConsole dispatches x86_64 builds to server (36 cores, 256GB RAM): -# nix.buildMachines = [{ -# hostName = "lazyworkhorse.net"; -# port = 2424; -# systems = ["x86_64-linux"]; -# maxJobs = 36; -# sshUser = "builder"; -# sshKey = "/etc/ssh/builder_key"; -# }]; - - # ==== How to build natively on uConsole ==== - # To native-compile these on the uConsole: - # 1. Add uConsole as a remote builder (nix.buildMachines) - # 2. Set nix.extra-platforms = [ "aarch64-linux" ] on server - # 3. Remove the overlay workarounds below - # 4. Packages will auto-dispatch to uConsole for native builds - ############################################################################## - uconsoleCrossOverlay = final: prev: { - libcamera = prev.libcamera.overrideAttrs (_: { meta.platforms = []; }); - libcamera-rpi = prev.libcamera-rpi.overrideAttrs (_: { meta.platforms = []; }); - libpisp = prev.libpisp.overrideAttrs (_: { meta.platforms = []; }); - pipewire = prev.pipewire.overrideAttrs (old: { - buildInputs = builtins.filter - (x: !(x?pname && x.pname == "libcamera")) - (old.buildInputs or []); - mesonFlags = builtins.filter - (flag: !(builtins.isString flag && builtins.match ".*libcamera.*" flag != null)) - (old.mesonFlags or []) ++ [ "-Dlibcamera=disabled" ]; - }); - gjs = prev.gjs.overrideAttrs (old: { - mesonFlags = (old.mesonFlags or []) ++ [ "-Dskip_gtk_tests=true" ]; - }); - hyprland = prev.hyprland.override { wrapRuntimeDeps = false; }; - boost = prev.boost.override { useMpi = false; }; - # perl-ldap cannot cross-compile (Module::Install needs dynamic loading) - xdg-desktop-portal-hyprland = prev.xdg-desktop-portal-hyprland.overrideAttrs (old: { - preConfigure = (old.preConfigure or "") + '' - cmakeFlags="$cmakeFlags -Dhyprwayland-scanner_DIR=${prev.buildPackages.hyprwayland-scanner}/lib/cmake/hyprwayland-scanner" 2>/dev/null || true - export PKG_CONFIG_PATH="${prev.buildPackages.hyprwayland-scanner}/lib/pkgconfig:$PKG_CONFIG_PATH" - ''; - }); - emacs-pgtk = prev.emacs-pgtk.override { withMailutils = false; }; - # perl-ldap fails cross-compile (Module::Install needs dynamic loading) - # Strip it from john deps -- the perl scripts that need it are not critical - john = prev.john.overrideAttrs (old: { - nativeBuildInputs = (old.nativeBuildInputs or []) ++ [ - prev.buildPackages.python3 # python3 for opencl_generate_dynamic_loader.py - ]; - configureFlags = (old.configureFlags or []) ++ [ - "ac_cv_prog_PYTHON=${prev.buildPackages.python3}/bin/python3" - ]; - propagatedBuildInputs = builtins.filter - (x: x?pname && x.pname != "perl-ldap") - (old.propagatedBuildInputs or []); - }); - # clamav: removed from system packages (see note above). - }; - - uconsoleRpiPipewireOverlay = final: prev: { - pipewire = prev.pipewire.overrideAttrs (old: { - buildInputs = builtins.filter - (x: !(x?pname && x.pname == "libcamera")) - (old.buildInputs or []); - mesonFlags = builtins.filter - (flag: !(builtins.isString flag && builtins.match ".*libcamera.*" flag != null)) - (old.mesonFlags or []) ++ [ "-Dlibcamera=disabled" ]; - }); - }; - - uconsoleBaseModules = [ - { - nixpkgs.buildPlatform = "x86_64-linux"; - nixpkgs.hostPlatform = "aarch64-linux"; - nixpkgs.config.allowUnfree = true; - boot.loader.raspberry-pi.bootloader = "kernel"; - nixpkgs.overlays = [ uconsoleCrossOverlay (import ./overlays/reticulum.nix) ]; - } - nixos-raspberrypi.nixosModules.nixpkgs-rpi - ({ config, lib, pkgs, ... }: { - nixpkgs.overlays = [ uconsoleRpiPipewireOverlay ]; - }) - nixos-raspberrypi.nixosModules.raspberry-pi-5.base - nixos-raspberrypi.lib.inject-overlays - nixos-raspberrypi.lib.inject-overlays-global - nixos-uconsole.nixosModules.uconsole-cm5 - ./modules/nixos/hardware/uconsole-cm5-aio-v2.nix - ({ config, lib, pkgs, inputs, ... }: let - lixCross = import inputs.nixpkgs-uconsole { - localSystem = { system = "x86_64-linux"; }; - crossSystem = { system = "aarch64-linux"; }; - overlays = [ inputs.lix.overlays.default ]; + in + { + nixosConfigurations = { + lazyworkhorse = nixpkgs.lib.nixosSystem { + specialArgs = { inherit system self keys paths inputs; }; + modules = [ + { + nixpkgs.overlays = overlays; + nixpkgs.config.allowUnfree = true; + nixpkgs.config.rocmSupport = true; + nixpkgs.config.permittedInsecurePackages = [ + "openclaw-2026.3.12" + ]; + nix.package = lix.packages.${system}.default; + } + agenix.nixosModules.default + ./hosts/lazyworkhorse/configuration.nix + ./hosts/lazyworkhorse/hardware-configuration.nix + ./modules/nixos/filesystem/hoardingcow-mount.nix + ./modules/nixos/services/docker_manager.nix + ./modules/nixos/services/open_code_server.nix + ./modules/nixos/services/ollama_init_custom_models.nix + ./modules/nixos/services/openclaw_node.nix + ./modules/nixos/filesystem/poup-16t-disk.nix + ./modules/nixos/security/ai-worker-restricted.nix + ./users/gortium.nix + ./users/ai-worker.nix + ]; }; - in { nix.package = lixCross.lix; }) - inputs.home-manager.nixosModules.home-manager - agenix.nixosModules.default - agenix-rekey.nixosModules.default - ./hosts/uconsole-cm5/configuration.nix - ./hosts/uconsole-cm5/hardware-configuration.nix - ./modules/nixos/services/remote-builder.nix - ./modules/nixos/services/wireguard-client.nix - ./modules/nixos/services/clamav.nix - ./modules/nixos/security/ai-worker-restricted.nix - ./users/gortium/gortium.nix - ./users/ai-worker/ai-worker.nix - ]; - in { - nixosConfigurations = { - lazyworkhorse = nixpkgs.lib.nixosSystem { - specialArgs = { inherit system self keys paths inputs; }; - modules = [ - { - nixpkgs.overlays = overlays; - nixpkgs.config.allowUnfree = true; - nixpkgs.config.rocmSupport = true; - nixpkgs.config.permittedInsecurePackages = [ "openclaw-2026.3.12" ]; - nix.package = lix.packages.${system}.default; - } - inputs.home-manager.nixosModules.home-manager - agenix.nixosModules.default - ./hosts/lazyworkhorse/configuration.nix - ./hosts/lazyworkhorse/hardware-configuration.nix - ./modules/nixos/filesystem/hoardingcow-mount.nix - ./modules/nixos/services/docker_manager.nix - ./modules/nixos/filesystem/poup-16t-disk.nix - ./modules/nixos/services/ollama_init_custom_models.nix - ./modules/nixos/services/open_code_server.nix - ./modules/nixos/services/clamav.nix - ./modules/nixos/security/ai-worker-restricted.nix - ./users/gortium/gortium.nix - ./users/ai-worker/ai-worker.nix - ]; - }; - cyt-pi = nixpkgs.lib.nixosSystem { - specialArgs = { inherit self keys paths inputs; }; - modules = [ - { - nixpkgs.overlays = overlays; - nixpkgs.config.allowUnfree = true; - nixpkgs.hostPlatform = "aarch64-linux"; - nix.package = lix.packages."aarch64-linux".default; - } - ./hosts/cyt-pi/configuration.nix - ./hosts/cyt-pi/hardware-configuration.nix - ./modules/nixos/services/remote-builder.nix - ./modules/nixos/services/wireguard-client.nix - ./users/gortium/gortium.nix - ]; - }; - - uconsole-cm5 = nixpkgs-uconsole.lib.nixosSystem { - system = "aarch64-linux"; - specialArgs = { - inherit self keys paths inputs; - nixos-raspberrypi = nixos-raspberrypi; - isCM4 = false; + cyt-pi = nixpkgs.lib.nixosSystem { + specialArgs = { inherit self keys paths inputs; }; + modules = [ + { + nixpkgs.overlays = overlays; + nixpkgs.config.allowUnfree = true; + nixpkgs.hostPlatform = "aarch64-linux"; + nix.package = lix.packages."aarch64-linux".default; + } + ./hosts/cyt-pi/configuration.nix + ./hosts/cyt-pi/hardware-configuration.nix + ]; }; - modules = uconsoleBaseModules; - }; - }; - agenix-rekey = agenix-rekey.configure { - userFlake = self; - nixosConfigurations = self.nixosConfigurations; - }; - - devShells.${system}.default = devShell; - - packages.${system} = { - uconsole-cm5-image = (nixos-raspberrypi.lib.nixosSystem { - system = "aarch64-linux"; - specialArgs = { - inherit self keys inputs; - nixos-raspberrypi = nixos-raspberrypi; - isCM4 = false; + uConsole = nixos-raspberrypi.lib.nixosSystem { + specialArgs = { inherit self keys paths inputs nixos-raspberrypi; }; + modules = [ + { + nixpkgs.overlays = overlays; + nixpkgs.config.allowUnfree = true; + nixpkgs.hostPlatform = "aarch64-linux"; + nix.package = lix.packages."aarch64-linux".default; + } + nixos-raspberrypi.nixosModules.raspberry-pi-5.base + nixos-uconsole.nixosModules.uconsole-cm5 + agenix.nixosModules.default + ./modules/nixos/hardware/uconsole-cm5-aio-v2.nix + ./hosts/uConsole/configuration.nix + ./hosts/uConsole/hardware-configuration.nix + ]; }; - modules = uconsoleBaseModules ++ [ - nixos-raspberrypi.nixosModules.sd-image - ]; - }).config.system.build.sdImage; + }; + devShells.${system}.default = devShell; }; - }; } -- 2.49.1