From 3e7465192fb4067b08673a9cdd7f1bca04aa6968 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 28 Mar 2026 10:25:37 +0000 Subject: [PATCH 1/8] make shell config customizable in base module Add omnix.base.shell options so consumers can control: - defaultShell: choose bash/zsh/nushell with auto program enablement - bash.viMode: opt out of hardcoded vi keybindings - nushell.manageConfig: choose whether omnix or home-manager owns config - shellPackage: read-only derivation for use in users.users..shell https://claude.ai/code/session_01QYnXiuNMQ9aCbqbu7j7tKH --- modules/base.nix | 71 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 66 insertions(+), 5 deletions(-) diff --git a/modules/base.nix b/modules/base.nix index e8fae91..8d122c3 100644 --- a/modules/base.nix +++ b/modules/base.nix @@ -1,6 +1,10 @@ { lib, config, pkgs, ... }: -let cfg = config.omnix.base; +let + cfg = config.omnix.base; + shellCfg = cfg.shell; + isNushell = shellCfg.defaultShell == "nushell"; + isZsh = shellCfg.defaultShell == "zsh"; in { options.omnix.base = { enable = lib.mkEnableOption "omnix base NixOS settings"; @@ -21,6 +25,40 @@ in { default = "24.11"; description = "NixOS state version"; }; + + shell = { + defaultShell = lib.mkOption { + type = lib.types.enum [ "bash" "zsh" "nushell" ]; + default = "bash"; + description = '' + Default interactive shell. Ensures the corresponding shell program + is enabled at the system level. Use `shellPackage` to set as a + user's login shell. + ''; + }; + + shellPackage = lib.mkOption { + type = lib.types.package; + readOnly = true; + description = "The package for the selected default shell, for use in users.users..shell"; + }; + + bash.viMode = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Enable vi keybindings for interactive bash sessions"; + }; + + nushell.manageConfig = lib.mkOption { + type = lib.types.bool; + default = true; + description = '' + Whether omnix manages nushell configuration via + environment.etc. Set to false to manage nushell config + via home-manager or manually. + ''; + }; + }; }; config = lib.mkIf cfg.enable { @@ -48,13 +86,36 @@ in { }; }; - programs.bash.interactiveShellInit = "set -o vi"; + omnix.base.shell.shellPackage = + if isNushell then pkgs.nushell + else if isZsh then pkgs.zsh + else pkgs.bash; - system.activationScripts.per-service-profiles.text = - "mkdir -p /nix/var/nix/profiles/per-service"; + programs.bash.interactiveShellInit = + lib.mkIf shellCfg.bash.viMode "set -o vi"; + + programs.zsh.enable = lib.mkIf isZsh true; environment.systemPackages = with pkgs; - [ bat curl htop rage zellij ] ++ cfg.extraPackages; + [ bat curl htop rage zellij ] + ++ lib.optional isNushell pkgs.nushell + ++ cfg.extraPackages; + + environment.shells = lib.mkIf isNushell [ pkgs.nushell ]; + + environment.etc = lib.mkIf (isNushell && shellCfg.nushell.manageConfig) { + "nushell/config.nu".text = '' + $env.config = { + show_banner: false + } + ''; + "nushell/env.nu".text = '' + # omnix managed nushell environment + ''; + }; + + system.activationScripts.per-service-profiles.text = + "mkdir -p /nix/var/nix/profiles/per-service"; system.stateVersion = cfg.stateVersion; }; From f1c808e7cc7907f44b3075ba7cca33c5e13cadd7 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 29 Mar 2026 09:49:02 +0000 Subject: [PATCH 2/8] use mkDefault for programs.zsh.enable to allow consumer overrides lib.mkIf prevents downstream overrides; mkDefault lets consumers set programs.zsh.enable independently of the defaultShell choice. https://claude.ai/code/session_01QYnXiuNMQ9aCbqbu7j7tKH --- modules/base.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/base.nix b/modules/base.nix index 8d122c3..1d3cd45 100644 --- a/modules/base.nix +++ b/modules/base.nix @@ -94,7 +94,7 @@ in { programs.bash.interactiveShellInit = lib.mkIf shellCfg.bash.viMode "set -o vi"; - programs.zsh.enable = lib.mkIf isZsh true; + programs.zsh.enable = lib.mkDefault isZsh; environment.systemPackages = with pkgs; [ bat curl htop rage zellij ] From 3cbe3734329afbe6c387f211273429431ebe8348 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 29 Mar 2026 10:00:30 +0000 Subject: [PATCH 3/8] use bashInteractive for shellPackage so login shells have readline pkgs.bash lacks readline support; pkgs.bashInteractive includes it, which is needed for proper line editing in login shells. https://claude.ai/code/session_01QYnXiuNMQ9aCbqbu7j7tKH --- modules/base.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/base.nix b/modules/base.nix index 1d3cd45..5d9660a 100644 --- a/modules/base.nix +++ b/modules/base.nix @@ -89,7 +89,7 @@ in { omnix.base.shell.shellPackage = if isNushell then pkgs.nushell else if isZsh then pkgs.zsh - else pkgs.bash; + else pkgs.bashInteractive; programs.bash.interactiveShellInit = lib.mkIf shellCfg.bash.viMode "set -o vi"; From 4354f28c094b0065a956ecf004e9e2f4f3d20759 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 29 Mar 2026 10:02:44 +0000 Subject: [PATCH 4/8] add flake checks and CI workflow for module evaluation Add checks output to flake.nix that evaluates each NixOS module in isolation, catching evaluation errors before merge. Add GitHub Actions workflow that runs nix flake check on PRs and pushes to master. https://claude.ai/code/session_01QYnXiuNMQ9aCbqbu7j7tKH --- .github/workflows/ci.yml | 16 ++++++++++++++++ flake.nix | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..de9bbaa --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,16 @@ +name: CI + +on: + pull_request: + push: + branches: [master] + +jobs: + flake-check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: cachix/install-nix-action@v30 + with: + nix_path: nixpkgs=channel:nixos-25.11 + - run: nix flake check --no-build diff --git a/flake.nix b/flake.nix index e6d595f..c2e023e 100644 --- a/flake.nix +++ b/flake.nix @@ -53,10 +53,43 @@ default = self.templates.do-service; }; } // flake-utils.lib.eachDefaultSystem (system: - let pkgs = import nixpkgs { inherit system; }; + let + pkgs = import nixpkgs { inherit system; }; + + # Evaluate a single omnix module in isolation and produce a + # derivation that succeeds when the module evaluates cleanly + evalModule = name: module: + let + eval = nixpkgs.lib.nixosSystem { + inherit system; + modules = [ + module + { + boot.loader.grub.device = "nodev"; + fileSystems."/" = { device = "none"; fsType = "tmpfs"; }; + nixpkgs.hostPlatform = system; + } + ]; + }; + in pkgs.runCommand "eval-${name}" { } '' + # Force evaluation of the module option definitions + cat ${eval.config.system.build.toplevel.drvPath} > /dev/null + touch $out + ''; + in { # Expose disko and ragenix modules for consumer nixosSystem calls packages.disko = disko.packages.${system}.default or null; packages.ragenix = ragenix.packages.${system}.default; + + checks = { + # Verify each module evaluates without errors in isolation + eval-base = evalModule "base" self.nixosModules.base; + eval-firewall = evalModule "firewall" self.nixosModules.firewall; + eval-storage = evalModule "storage" self.nixosModules.storage; + eval-digitalocean = evalModule "digitalocean" self.nixosModules.digitalocean; + eval-services = evalModule "services" self.nixosModules.services; + eval-disko = evalModule "disko" self.nixosModules.disko; + }; }); } From 43f9ca54c2c95663a4cba5df47b37333445d06f6 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 29 Mar 2026 10:03:41 +0000 Subject: [PATCH 5/8] use determinate systems installer and magic cache for CI builds Switch from cachix/install-nix-action to DeterminateSystems installer with magic-nix-cache, and drop --no-build so checks fully build. https://claude.ai/code/session_01QYnXiuNMQ9aCbqbu7j7tKH --- .github/workflows/ci.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index de9bbaa..183cdb9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,7 +10,6 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: cachix/install-nix-action@v30 - with: - nix_path: nixpkgs=channel:nixos-25.11 - - run: nix flake check --no-build + - uses: DeterminateSystems/nix-installer-action@main + - uses: DeterminateSystems/magic-nix-cache-action@main + - run: nix flake check From 577fcdd3c2a18d7da72669ce1b5e9344c453cb46 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 29 Mar 2026 10:04:11 +0000 Subject: [PATCH 6/8] build full NixOS toplevel in checks instead of just evaluating Each check now builds system.build.toplevel, catching real build failures rather than just evaluation errors. https://claude.ai/code/session_01QYnXiuNMQ9aCbqbu7j7tKH --- flake.nix | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/flake.nix b/flake.nix index c2e023e..f09ffd9 100644 --- a/flake.nix +++ b/flake.nix @@ -56,26 +56,20 @@ let pkgs = import nixpkgs { inherit system; }; - # Evaluate a single omnix module in isolation and produce a - # derivation that succeeds when the module evaluates cleanly + # Build a minimal NixOS system with a single omnix module to + # verify it evaluates and builds without errors in isolation evalModule = name: module: - let - eval = nixpkgs.lib.nixosSystem { - inherit system; - modules = [ - module - { - boot.loader.grub.device = "nodev"; - fileSystems."/" = { device = "none"; fsType = "tmpfs"; }; - nixpkgs.hostPlatform = system; - } - ]; - }; - in pkgs.runCommand "eval-${name}" { } '' - # Force evaluation of the module option definitions - cat ${eval.config.system.build.toplevel.drvPath} > /dev/null - touch $out - ''; + (nixpkgs.lib.nixosSystem { + inherit system; + modules = [ + module + { + boot.loader.grub.device = "nodev"; + fileSystems."/" = { device = "none"; fsType = "tmpfs"; }; + nixpkgs.hostPlatform = system; + } + ]; + }).config.system.build.toplevel; in { # Expose disko and ragenix modules for consumer nixosSystem calls From 1b79a6ae3d486439695b1169dc1b354cc78f145c Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 29 Mar 2026 10:14:17 +0000 Subject: [PATCH 7/8] fix eval-disko check by importing upstream disko NixOS module The omnix disko module sets disko.devices which requires the upstream disko NixOS module to define that option. Add extraModules parameter to evalModule so checks can include external dependencies. https://claude.ai/code/session_01QYnXiuNMQ9aCbqbu7j7tKH --- flake.nix | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/flake.nix b/flake.nix index f09ffd9..0015ed2 100644 --- a/flake.nix +++ b/flake.nix @@ -58,7 +58,7 @@ # Build a minimal NixOS system with a single omnix module to # verify it evaluates and builds without errors in isolation - evalModule = name: module: + evalModule = name: module: extraModules: (nixpkgs.lib.nixosSystem { inherit system; modules = [ @@ -68,7 +68,7 @@ fileSystems."/" = { device = "none"; fsType = "tmpfs"; }; nixpkgs.hostPlatform = system; } - ]; + ] ++ extraModules; }).config.system.build.toplevel; in { @@ -77,13 +77,15 @@ packages.ragenix = ragenix.packages.${system}.default; checks = { - # Verify each module evaluates without errors in isolation - eval-base = evalModule "base" self.nixosModules.base; - eval-firewall = evalModule "firewall" self.nixosModules.firewall; - eval-storage = evalModule "storage" self.nixosModules.storage; - eval-digitalocean = evalModule "digitalocean" self.nixosModules.digitalocean; - eval-services = evalModule "services" self.nixosModules.services; - eval-disko = evalModule "disko" self.nixosModules.disko; + # Verify each module evaluates and builds without errors in isolation + eval-base = evalModule "base" self.nixosModules.base [ ]; + eval-firewall = evalModule "firewall" self.nixosModules.firewall [ ]; + eval-storage = evalModule "storage" self.nixosModules.storage [ ]; + eval-digitalocean = evalModule "digitalocean" self.nixosModules.digitalocean [ ]; + eval-services = evalModule "services" self.nixosModules.services [ ]; + eval-disko = evalModule "disko" self.nixosModules.disko [ + disko.nixosModules.disko + ]; }; }); } From 2a4b7495076dd57d5bd06b667b31f97dedd4320f Mon Sep 17 00:00:00 2001 From: 0xgleb Date: Sun, 10 May 2026 01:11:00 +0700 Subject: [PATCH 8/8] address PR feedback: pin actions, add CI timeout, set NU_VENDOR_AUTOLOAD_DIR --- .github/workflows/ci.yml | 5 +++-- modules/base.nix | 4 ++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1cc25fa..99d51f8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,8 +12,9 @@ jobs: flake-check: name: Flake check runs-on: ubuntu-latest + timeout-minutes: 20 steps: - uses: actions/checkout@v4 - - uses: DeterminateSystems/nix-installer-action@main - - uses: DeterminateSystems/magic-nix-cache-action@main + - uses: DeterminateSystems/nix-installer-action@v22 + - uses: DeterminateSystems/magic-nix-cache-action@v13 - run: nix flake check diff --git a/modules/base.nix b/modules/base.nix index 7678d9b..92580cc 100644 --- a/modules/base.nix +++ b/modules/base.nix @@ -124,6 +124,10 @@ in environment.shells = lib.mkIf isNushell [ pkgs.nushell ]; + environment.variables = lib.mkIf (isNushell && shellCfg.nushell.manageConfig) { + NU_VENDOR_AUTOLOAD_DIR = "/etc/nushell"; + }; + environment.etc = lib.mkIf (isNushell && shellCfg.nushell.manageConfig) { "nushell/config.nu".text = '' $env.config = {