greenhouse

kore

my public infrastructure monorepo

git clone [email protected]:kore.git

feat(*): dual boot

commit5153a34c50dd1b9c98be6687f24ab7b01c6c4ef9
parentc9d730b6e0827e16d1dfe9bc9d168b5e24c5881b
authorlostduk <[email protected]>
date2026-03-02 16:26 +0000
flake.lock76+++++++++++++++++-----
flake.nix5+-
home/features/global.nix15+++++
home/features/wayland/dwl.nix5++
home/features/wayland/foot.nix11++++
home/profiles/sunflower.nix19+-----
nixos/features/global.nix66++++++++++++++++++-
nixos/hosts/sunflower.nix74+++++++++++++++++++---
nixos/roles/workstation.nix140++++++++++++++++++++++++++++++----------
overlays/default.nix10+++
overlays/dwl_config.h118++++++++++++++++++++++++++++++++++

11 files changed, -87/+452

flake.lock

@@ -1,18 +1,22 @@ {   "nodes": {-    "flake-compat": {-      "flake": false,+    "disko": {+      "inputs": {+        "nixpkgs": [+          "nixpkgs"+        ]+      },       "locked": {-        "lastModified": 1767039857,-        "narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=",-        "owner": "edolstra",-        "repo": "flake-compat",-        "rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab",+        "lastModified": 1772420042,+        "narHash": "sha256-naZz40TUFMa0E0CutvwWsSPhgD5JldyTUDEgP9ADpfU=",+        "owner": "nix-community",+        "repo": "disko",+        "rev": "5af7af10f14706e4095bd6bc0d9373eb097283c6",         "type": "github"       },       "original": {-        "owner": "edolstra",-        "repo": "flake-compat",+        "owner": "nix-community",+        "repo": "disko",         "type": "github"       }     },@@ -36,29 +40,64 @@         "type": "sourcehut"       }     },-    "nixos-wsl": {+    "home-manager_2": {       "inputs": {-        "flake-compat": "flake-compat",         "nixpkgs": [+          "impermanence",           "nixpkgs"         ]       },       "locked": {-        "lastModified": 1769217863,-        "narHash": "sha256-RY9kJDXD6+2Td/59LkZ0PFSereCXHdBX9wIkbYjRKCY=",+        "lastModified": 1768598210,+        "narHash": "sha256-kkgA32s/f4jaa4UG+2f8C225Qvclxnqs76mf8zvTVPg=",+        "owner": "nix-community",+        "repo": "home-manager",+        "rev": "c47b2cc64a629f8e075de52e4742de688f930dc6",+        "type": "github"+      },+      "original": {+        "owner": "nix-community",+        "repo": "home-manager",+        "type": "github"+      }+    },+    "impermanence": {+      "inputs": {+        "home-manager": "home-manager_2",+        "nixpkgs": "nixpkgs"+      },+      "locked": {+        "lastModified": 1769548169,+        "narHash": "sha256-03+JxvzmfwRu+5JafM0DLbxgHttOQZkUtDWBmeUkN8Y=",         "owner": "nix-community",-        "repo": "NixOS-WSL",-        "rev": "38a5250e57f583662eac3b944830e4b9e169e965",+        "repo": "impermanence",+        "rev": "7b1d382faf603b6d264f58627330f9faa5cba149",         "type": "github"       },       "original": {         "owner": "nix-community",-        "repo": "NixOS-WSL",+        "repo": "impermanence",         "type": "github"       }     },     "nixpkgs": {       "locked": {+        "lastModified": 1768564909,+        "narHash": "sha256-Kell/SpJYVkHWMvnhqJz/8DqQg2b6PguxVWOuadbHCc=",+        "owner": "nixos",+        "repo": "nixpkgs",+        "rev": "e4bae1bd10c9c57b2cf517953ab70060a828ee6f",+        "type": "github"+      },+      "original": {+        "owner": "nixos",+        "ref": "nixos-unstable",+        "repo": "nixpkgs",+        "type": "github"+      }+    },+    "nixpkgs_2": {+      "locked": {         "lastModified": 1770197578,         "narHash": "sha256-AYqlWrX09+HvGs8zM6ebZ1pwUqjkfpnv8mewYwAo+iM=",         "owner": "nixos",@@ -75,9 +114,10 @@     },     "root": {       "inputs": {+        "disko": "disko",         "home-manager": "home-manager",-        "nixos-wsl": "nixos-wsl",-        "nixpkgs": "nixpkgs"+        "impermanence": "impermanence",+        "nixpkgs": "nixpkgs_2"       }     }   },

flake.nix

@@ -1,9 +1,10 @@ {   inputs = {     nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";+    impermanence.url = "github:nix-community/impermanence"; -    nixos-wsl.url = "github:nix-community/NixOS-WSL";-    nixos-wsl.inputs.nixpkgs.follows = "nixpkgs";+    disko.url = "github:nix-community/disko";+    disko.inputs.nixpkgs.follows = "nixpkgs";          home-manager.url = "sourcehut:~rycee/home-manager";     home-manager.inputs.nixpkgs.follows = "nixpkgs";

home/features/global.nix

@@ -14,6 +14,19 @@       GOTOOLCHAIN = "local";     }; -    packages = with pkgs; [ pass ];+    packages = with pkgs; [ pass vesktop ];++    persistence."/persist" = {+      files = [+        ".local/share/opencode/auth.json"+      ];+      directories = [+        "documents"+        ".mozilla"+        ".gnupg"+        ".password-store"+        ".config/vesktop"+      ];+    };   }; }

home/features/wayland/dwl.nix

@@ -0,0 +1,5 @@+{ pkgs, ... }:++{+  home.packages = with pkgs; [ dwl dmenu wl-clipboard xdg-utils ];+}

home/features/wayland/foot.nix

@@ -0,0 +1,11 @@+{+  programs.foot = {+    enable = true;+    settings = {+      main = {+        font = "ComicShannsMono Nerd Font:size=11";+        line-height = "16px";+      };+    };+  };+}

home/profiles/sunflower.nix

@@ -9,21 +9,8 @@     ../features/cli/opencode.nix      ../features/misc/xdg.nix-  ]; -  # TMP: neovim suck tbh but it work-  programs.neovim.extraConfig = ''-    let g:clipboard = {-      \   'name': 'WslClipboard',-      \   'copy': {-      \      '+': 'clip.exe',-      \      '*': 'clip.exe',-      \    },-      \   'paste': {-      \      '+': 'powershell.exe -NoLogo -NoProfile -c [Console]::Out.Write($(Get-Clipboard -Raw).tostring().replace("`r", ""))',-      \      '*': 'powershell.exe -NoLogo -NoProfile -c [Console]::Out.Write($(Get-Clipboard -Raw).tostring().replace("`r", ""))',-      \   },-      \   'cache_enabled': 0,-      \ }-  '';+    ../features/wayland/dwl.nix+    ../features/wayland/foot.nix+  ]; }

nixos/features/global.nix

@@ -1,6 +1,8 @@-{ inputs, outputs, lib, pkgs, ... }:+{ inputs, outputs, config, lib, pkgs, ... }:  {+  imports = [ inputs.impermanence.nixosModules.impermanence ];+   i18n.defaultLocale = "en_US.UTF-8";   time.timeZone = "UTC"; @@ -9,7 +11,7 @@      gc = {       automatic = true;-      dates = "weekly";+      dates = "daily";       options = "--delete-older-than 7d";     }; @@ -18,7 +20,7 @@       keep-derivations = false;       auto-optimise-store = true; -      trusted-users = [ "@wheel" ];+      trusted-users = [ "root" "@wheel" ];       experimental-features = [ "nix-command" "flakes" ];     };   };@@ -68,7 +70,7 @@      audit = {       enable = true;-      rules = [ "-a exit,always, -F arch=b64 -S execve" ];+      rules = [ "-a exit,always -F arch=b64 -S execve" ];     };      sudo = {@@ -86,5 +88,59 @@     users.root.hashedPassword = lib.mkForce "!";   }; -  environment.defaultPackages = lib.mkForce [];+  environment = {+    defaultPackages = lib.mkForce [];++    persistence."/persist" = {+      hideMounts = false;++      directories = [+        "/srv"+        "/var/lib/nixos"+        "/var/lib/systemd"+      ];+    };+  };++  boot.initrd = let+    rootDevice = config.fileSystems."/".device;+    systemdStage1 = config.boot.initrd.systemd.enable;++    script = ''+      mkdir -p /tmp+      MNTPOINT=$(mktemp -d)+      (+        mount ${rootDevice} "$MNTPOINT"+        trap 'umount "$MNTPOINT"' EXIT++        echo "Moving old root..."+        mv "$MNTPOINT/@" "$MNTPOINT/@_old"++        echo "Creating a blank root subvolume..."+        btrfs sub cre "$MNTPOINT/@"++        echo "Cleaning old root..."+        btrfs sub del -R "$MNTPOINT/@_old"+        rm -rf "$MNTPOINT/@_old"+      )+    '';+  in {+    supportedFilesystems = [ "btrfs" ];+    postDeviceCommands = lib.mkIf (!systemdStage1) (lib.mkBefore script);++    systemd.services.wipe-root = lib.mkIf (systemdStage1) {+      wantedBy = [ "initrd.target" ];+      requires = [ "dev-mapper-crypted.device" ];+      before = [ "sysroot.mount" ];+      after = [ "dev-mapper-crypted.device" "[email protected]" ];+      unitConfig.DefaultDependencies = "no";+      serviceConfig = {+        Type = "oneshot";+        RemainAfterExit = true;+      };+      script = script;+    };+  };++  fileSystems."/persist".neededForBoot = true; }

nixos/hosts/sunflower.nix

@@ -1,20 +1,23 @@-{ pkgs, inputs, modulesPath, ... }:+{ inputs, modulesPath, pkgs, ... }:  {   imports = [-    inputs.nixos-wsl.nixosModules.default+    inputs.disko.nixosModules.disko      ( modulesPath + "/installer/scan/not-detected.nix" )   ]; -  wsl = {-    enable = true;-    defaultUser = "lostduk";-    useWindowsDriver = true;+  boot = {+    kernelModules = [ "kvm-intel" ]; -    usbip = {-      enable = true;-      autoAttach = [ "1-14" ];+    loader = {+      systemd-boot.enable = true;+      efi.canTouchEfiVariables = true;+    };++    initrd = {+      systemd.enable = true;+      availableKernelModules = [ "xhci_pci" "ahci" "usbhid" "usb_storage" "sd_mod" ];     };   }; @@ -28,7 +31,58 @@   };    hardware = {-    graphics.enable = true;+    graphics = {+      enable = true;+      extraPackages = with pkgs; [ libGL ];+    };     cpu.intel.updateMicrocode = true;   };++  disko.devices.disk.main = {+    type = "disk";+    device = "/dev/sda";+    content = {+      type = "gpt";+      partitions = {+        ESP = {+          size = "512M";+          type = "EF00";+          content = {+            type = "filesystem";+            format = "vfat";+            mountpoint = "/boot";+            mountOptions = [ "defaults" "uid=0" "gid=0" "fmask=0077" "dmask=0077" ];+          };+        };+        luks = {+          size = "100%";+          content = {+            name = "crypted";+            type = "luks";+            extraFormatArgs = [ "--type luks2" ];+            content = {+              type = "btrfs";+              extraArgs = [ "-f" ];+              subvolumes = let+                options = [ "compress=zstd" "noatime" "space_cache=v2" "discard=async" "ssd" ];+              in {+                "/@" = {+                  mountpoint = "/";+                  mountOptions = options;+                };+                "/@nix" = {+                  mountpoint = "/nix";+                  mountOptions = options;+                };+                "/@persist" = {+                  mountpoint = "/persist";+                  mountOptions = options;+                };+              };+            };+          };+        };+      };+    };+  }; }

nixos/roles/workstation.nix

@@ -15,42 +15,112 @@ in {       users.lostduk = outputs.homeConfigurations.${config.networking.hostName};     }; -    systemd.services.wipe-trash = {-      restartIfChanged = false;-      wantedBy = [ "multi-user.target" ];-      serviceConfig = {-        Type = "oneshot";-        RemainAfterExit = true;-        ExecStart = pkgs.writeShellScript "" ''-          set -e--          TARGET="/home/lostduk"--          find "$TARGET" -mindepth 1 -maxdepth 1 \-            ! -name 'documents' \-            ! -name '.gnupg' \-            ! -name '.password-store' \-            ! -name '.local' \-            -exec rm -r {} +--          if [ -d "$TARGET/.local" ]; then-            find "$TARGET/.local" -mindepth 1 -maxdepth 1 \-              ! -name 'share' \-              -exec rm -r {} +-          fi--          if [ -d "$TARGET/.local/share" ]; then-            find "$TARGET/.local/share" -mindepth 1 -maxdepth 1 \-              ! -name 'opencode' \-              -exec rm -r {} +-          fi--          if [ -d "$TARGET/.local/share/opencode" ]; then-            find "$TARGET/.local/share/opencode" -mindepth 1 -maxdepth 1 \-              ! -name 'auth.json' \-              -exec rm -r {} +-          fi+    programs.fuse.userAllowOther = true;++    xdg.portal = {+      enable = true;+      extraPortals = [ pkgs.xdg-desktop-portal-wlr ];+      configPackages = [ pkgs.xdg-desktop-portal-gtk pkgs.xdg-desktop-portal-wlr ];++      wlr.enable = true;++      config.common = {+        default = [ "wlr" ];+      };+    };++    system.activationScripts.persistent-dirs.text =+      let+        mkHomePersist = user: lib.optionalString user.createHome ''+          mkdir -p /persist/${user.home}+          chown ${user.name}:${user.group} /persist/${user.home}+          chmod ${user.homeMode} /persist/${user.home}         '';+        users = lib.attrValues config.users.users;+      in+        lib.concatLines (map mkHomePersist users);++    fonts = {+      enableDefaultPackages = false;++      packages = with pkgs; [+        noto-fonts+        noto-fonts-cjk-sans+        noto-fonts-cjk-serif+        noto-fonts-color-emoji++        #(nerdfonts.override { fonts = [ "ComicShannsMono" ]; })+        nerd-fonts.comic-shanns-mono+      ];++      fontconfig = {+        hinting.autohint = true;++        defaultFonts = {+          serif = [ "Noto Serif" "Noto Color Emoji" ];+          sansSerif = [ "Noto Sans" "Noto Color Emoji" ];+          monospace = [ "ComicShannsMono Nerd Font" "Noto Color Emoji" ];+          emoji = [ "Noto Color Emoji" ];+        };+      };+    };++    services = {+      udisks2.enable = true;++      pipewire = {+        enable = true;++        alsa.enable = true;+        alsa.support32Bit = true;++        pulse.enable = true;+        jack.enable = true;++        wireplumber = {+          enable = true;++          # https://github.com/NixOS/nixpkgs/pull/292115+          extraConfig."alsa-lowlatency" = {+            "monitor.alsa.rules" = [{+              matches = [{ "node.name" = "~alsa_output.*"; }];++              actions.update-props = {+                "audio.format" = "S32LE";+                "audio.rate" = "96000";+                "api.alsa.period-size" = 2;+              };+            }];+          };+        };++        extraConfig.pipewire."92-low-latency" = {+          context = {+            properties.default.clock = {+              rate = 48000;+              quantum = 64;+            };++            modules = [{+              name = "libpipewire-module-protocol-pulse";++              args.pulse = {+                min = {+                  req = "64/48000";+                  quantum = "64/48000";+                  frag = "64/48000";+                };++                default.req = "64/48000";+              };+            }];+          };+          +          stream.properties = {+            node.latency = "64/48000";+            resample.quality = 1;+          };+        };       };     };   })];

overlays/default.nix

@@ -13,4 +13,14 @@       )       inputs;   };++  modifications = final: prev: {+    dwl = prev.dwl.overrideAttrs (oldAttrs: {+      enableXWayland = true;+      +      postPatch = ''+        cp ${./dwl_config.h} config.h+      '';+    });+  }; }

overlays/dwl_config.h

@@ -0,0 +1,118 @@+/* general */+#define TAGCOUNT (6)++static int log_level                       = WLR_ERROR;+static const int sloppyfocus               = 1;+static const int bypass_surface_visibility = 0;++/* appearance */+static const unsigned int borderpx         = 1;+static const float rootcolor[]             = {0.1f, 0.1f, 0.1f, 1.0f};+static const float bordercolor[]           = {0.2f, 0.2f, 0.2f, 1.0f};+static const float focuscolor[]            = {0.0f, 0.3f, 0.4f, 1.0f};+static const float urgentcolor[]           = {0.1f, 0.0f, 0.0f, 1.0f};+static const float fullscreen_bg[]         = {0.1f, 0.1f, 0.1f, 1.0f};++/* rules */+static const Rule rules[] = {+	{ "Gimp_EXAMPLE", NULL, 0, 1, -1 },+};++/* layouts */+static const Layout layouts[] = {+	{ "[T]", tile },+	{ "[F]", NULL },+	{ "[M]", monocle },+};++/* monitors */+static const MonitorRule monrules[] = {+	{ NULL, 0.55f, 1, 1, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 },+};++/* keyboard */+static const int repeat_rate = 25;+static const int repeat_delay = 600;++static const struct xkb_rule_names xkb_rules = {+	.layout = "us,th",+	.options = "grp:alt_shift_toggle",+};+++/* trackpad */+static const int tap_to_click = 1;+static const int tap_and_drag = 1;+static const int drag_lock = 1;+static const int natural_scrolling = 0;+static const int disable_while_typing = 1;+static const int left_handed = 0;+static const int middle_button_emulation = 0;++static const enum libinput_config_scroll_method scroll_method = LIBINPUT_CONFIG_SCROLL_2FG;+static const enum libinput_config_click_method click_method = LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS;+static const uint32_t send_events_mode = LIBINPUT_CONFIG_SEND_EVENTS_ENABLED;+static const enum libinput_config_accel_profile accel_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE;+static const double accel_speed = 0.0;+static const enum libinput_config_tap_button_map button_map = LIBINPUT_CONFIG_TAP_MAP_LRM;++/* commands */+#define MODKEY WLR_MODIFIER_LOGO+#define MODALT WLR_MODIFIER_ALT+#define MODCTRL WLR_MODIFIER_CTRL+#define MODSHIFT WLR_MODIFIER_SHIFT++#define TAGKEYS(KEY, SKEY, TAG) \+	{ MODKEY, KEY, view, {.ui = 1 << TAG} }, \+	{ MODKEY|MODCTRL, KEY, toggleview, {.ui = 1 << TAG} }, \+	{ MODKEY|MODSHIFT, SKEY, tag, {.ui = 1 << TAG} }, \+	{ MODKEY|MODCTRL|MODSHIFT, SKEY, toggletag, {.ui = 1 << TAG} }++#define CHVT(n) { MODCTRL|MODALT, XKB_KEY_XF86Switch_VT_##n, chvt, {.ui = (n)} }++static const char *termcmd[] = { "foot", NULL };+static const char *menucmd[] = { "dmenu_run", NULL };++static const Key keys[] = {+	{ MODKEY, XKB_KEY_d, spawn, {.v = menucmd} },+	{ MODKEY, XKB_KEY_Return, spawn, {.v = termcmd} },+	{ MODKEY, XKB_KEY_j, focusstack, {.i = +1} },+	{ MODKEY, XKB_KEY_h, setmfact, {.f = -0.05f} },+	{ MODKEY, XKB_KEY_l, setmfact, {.f = +0.05f} },+	{ MODKEY, XKB_KEY_i, incnmaster, {.i = +1} },+	{ MODKEY, XKB_KEY_o, incnmaster, {.i = -1} },+	{ MODKEY, XKB_KEY_k, focusstack, {.i = -1} },+	{ MODKEY, XKB_KEY_q, killclient, {0} },+	{ MODKEY|MODSHIFT, XKB_KEY_Tab, view, {0} },+	{ MODKEY|MODSHIFT, XKB_KEY_Return, zoom, {0} },+	{ MODKEY|MODSHIFT, XKB_KEY_T, setlayout, {.v = &layouts[0]} },+	{ MODKEY|MODSHIFT, XKB_KEY_F, setlayout, {.v = &layouts[1]} },+	{ MODKEY|MODSHIFT, XKB_KEY_M, setlayout, {.v = &layouts[2]} },+	{ MODKEY, XKB_KEY_space, togglefloating, {0} },+	{ MODKEY, XKB_KEY_f, togglefullscreen, {0} },+	{ MODKEY, XKB_KEY_comma, focusmon, {.i = WLR_DIRECTION_LEFT} },+	{ MODKEY, XKB_KEY_period, focusmon, {.i = WLR_DIRECTION_RIGHT} },+	{ MODKEY|MODSHIFT, XKB_KEY_less, tagmon, {.i = WLR_DIRECTION_LEFT} },+	{ MODKEY|MODSHIFT, XKB_KEY_greater, tagmon, {.i = WLR_DIRECTION_RIGHT} },+	{ MODKEY|MODSHIFT, XKB_KEY_P, quit, {0} },++	/* Ctrl-Alt-Backspace and Ctrl-Alt-Fx used to be handled by X server */+	{ MODCTRL|MODALT, XKB_KEY_Terminate_Server, quit, {0} },++	TAGKEYS(XKB_KEY_1, XKB_KEY_exclam, 0),+	TAGKEYS(XKB_KEY_2, XKB_KEY_at, 1),+	TAGKEYS(XKB_KEY_3, XKB_KEY_numbersign, 2),+	TAGKEYS(XKB_KEY_4, XKB_KEY_dollar, 3),+	TAGKEYS(XKB_KEY_5, XKB_KEY_percent, 4),+	TAGKEYS(XKB_KEY_6, XKB_KEY_asciicircum, 5),++	/* Ctrl-Alt-Fx is used to switch to another VT */+	CHVT(1), CHVT(2), CHVT(3), CHVT(4), CHVT(5), CHVT(6),+	CHVT(7), CHVT(8), CHVT(9), CHVT(10), CHVT(11), CHVT(12),+};++static const Button buttons[] = {+	{ MODKEY, BTN_LEFT, moveresize, {.ui = CurMove} },+	{ MODKEY, BTN_RIGHT, moveresize, {.ui = CurResize} },+	{ MODKEY, BTN_MIDDLE, togglefloating, {0} },+};