Commit c74c654

HPCesia <me@hpcesia.com>
2026-08-03 00:14:55
core: init
1 parent e7d50ad
.secrets/cache/cyrene/55783bb656c3611c75488a2ff032e511cd06ddeb2decf425789cd4569080f34f
Binary file
.secrets/cache/hyacine/a53ed96ab50d55da66de90b810f996eb1e261ef33ee9af95635a54641bc54c91
@@ -0,0 +1,7 @@
+age-encryption.org/v1
+-> ssh-ed25519 diaafw nhczzLh5+er3sFDq24Ck4Mrc8n6k1s+nNGZdP5WKqiw
+xQpgOaCA8xPi07eyR+6n/5rTWb9v94hOBnySF3fqheE
+-> wb2X-grease
+zOUI4ofxzPxwBJRYiFIShvZQcq6maMF9lBg2o7BVNck3biw0nA
+--- mOlWqEhOvhDwayiILG3ZaA1su8kPWAvT2lNPT0ExdYM
+�c�|�7��� G��I��%�}�����ͺ/Uڛ㥸Rf�f(RBWZE���9mч��C�)����S���$Bq컱��4��M�F�}
�+�����띖k����������f��W�s*.�8!
\ No newline at end of file
.secrets/cache/kevin/4f6592341999fc1dab03e57bc2a19b384aec85a35f8812bcab732546522d3ce5
@@ -0,0 +1,8 @@
+age-encryption.org/v1
+-> ssh-ed25519 WM7kiQ ryfP2uTJVJhmr/3Lo+ikUIHEELR6Ql5h18SgN+t6lRU
+FTGf20uVeWa3vrXNnxvT9NcvUqWcrc3KiHTYgN68oQk
+-> qlZiCL-grease Q%s@M78@ v'th' 79}1y[b
+zTyiahs6ZbUHzogPDUFILHpriA+2mHFdQZiTofWPoMw
+--- Klr31zp8GmUl6bqpikl3lJg0jhbMvaPpo0ldUlm45qU
+�����xE��n����	ʎO����6���)�S�;�&[�ˤ$V��x�}}���f�������I��M+�^�T�
+~���S�P>�4[܄������cb�ĀW"��S��g�=�_=���
\ No newline at end of file
.secrets/cache/mobius/3a8f594f50d53aee84019bbbf3d0f5816ad971850c3b2d8d8bb22215b4b90434
Binary file
.secrets/cache/tribios/4e78a6b182c86e1f3a6d5f00078da6e2673c02c8ccd69189358d6b3914ecf104
@@ -0,0 +1,7 @@
+age-encryption.org/v1
+-> ssh-ed25519 1YGZAA QB4gUMuWTezIyipscQifozN2rRsDFrCny/ITn+6Qtgc
+bpz2PTYVgP4VCTxzehPjLxQEG8svppCOJ5AQMzrX24Q
+-> /-grease u8ne%J 1_
+ZCoRMggZkevMSUhj
+--- 1rD57KpAxNAadvY/RV/s2RdlaIVcScsMkJwwf7QejkA
+�7��Q/8� �J�u۷�:�G�7}�"��X�;��bđ�{�H�ǰ�"��q_r�vx���q�7+��	\�ou��&W�s1�G"�8��FYN1�aa��V�h9o,�z4�S�†q)VC�,�-w�
\ No newline at end of file
modules/core/nix/access-token-github.age
@@ -0,0 +1,9 @@
+age-encryption.org/v1
+-> piv-p256 xCEwtQ A46CzqMwsHRJ9QQfd/aNWXz03IyTywceiiUZDD+Zoa37
++qHfdPM60Ew+sbxsCjYniFvLc1p67n1jR3MkJFSefT0
+-> piv-p256 xCEwtQ AgaYsI6VMZKYUwGvWWL34f65kmXF/CC1jpLZ3c0SsV4Q
+ub923RpT+8iEy2lPDR9SisZiZ5bZJuFCc9t1YForp+A
+-> `00%%Aq-grease C sb;': kQh&
+iQ
+--- sZqJF4+7n83D7z/PvtZsa/ywp8NFtV4ilzaXmBWNt84
+	��)����[��͂ˈ�`����kh)�V�}$�U%R��t�q�L��88A�xBa�csla�̾H�OQf�}�������o�p ڻQ�'�s�<'m�	1�q>�AVRQ2?�W�4zdJ6}����@��
\ No newline at end of file
modules/core/nix/access-tokens.nix
@@ -0,0 +1,23 @@
+{den, ...}: {
+  den.aspects.core.nix.includes = [den.aspects.core.nix.access-tokens];
+  den.aspects.core.nix.access-tokens = {
+    nixos = {config, ...}: let
+      secretName = "nix-access-token-github";
+      templateName = "nix-access-tokens";
+    in {
+      nix.extraOptions = ''
+        !include ${config.vaultix.templates.${templateName}.path}
+      '';
+
+      vaultix.secrets.${secretName}.file = ./access-token-github.age;
+      vaultix.templates.${templateName} = {
+        content = ''
+          access-tokens = github.com=${config.vaultix.placeholder.${secretName}}
+        '';
+        mode = "0440";
+        owner = "root";
+        group = "wheel";
+      };
+    };
+  };
+}
modules/core/nix/default.nix
@@ -0,0 +1,29 @@
+{den, ...}: {
+  den.aspects.core.includes = [den.aspects.core.nix];
+  den.aspects.core.nix = {
+    nixos = {
+      nix.settings = {
+        experimental-features = [
+          "auto-allocate-uids"
+          "cgroups"
+        ];
+        # Select UIDs for builds automatically
+        auto-allocate-uids = true;
+        # Required by auto-allocate-uids
+        use-cgroups = true;
+        # Automatically hard link identical files in the Nix store
+        auto-optimise-store = true;
+        # Remote servers preferred substituters instead of local builders
+        builders-use-substitutes = true;
+        # Unlimited HTTP connections
+        http-connections = 0;
+        # Use `$XDG_STATE_HOME/nix/...` instead of `$HOME/.nix-...`
+        use-xdg-base-directories = true;
+
+        trusted-users = ["@wheel"];
+      };
+
+      system.copySystemConfiguration = false;
+    };
+  };
+}
modules/core/nix/flakes.nix
@@ -0,0 +1,17 @@
+{den, ...}: {
+  den.aspects.core.nix.includes = [den.aspects.core.nix.flakes];
+  den.aspects.core.nix.flakes = {
+    nixos = {
+      nix.settings = {
+        experimental-features = [
+          "nix-command"
+          "flakes"
+        ];
+        flake-registry = "";
+      };
+      nix.channel.enable = false;
+
+      nixpkgs.flake.setFlakeRegistry = true;
+    };
+  };
+}
modules/core/nix/substituters.nix
@@ -0,0 +1,74 @@
+{
+  inputs,
+  den,
+  lib,
+  ...
+}: {
+  flake-file.inputs.ncro = {
+    url = "github:manic-systems/ncro";
+    inputs.nixpkgs.follows = "nixpkgs";
+  };
+
+  den.aspects.core.nix.includes = [den.aspects.core.nix.substituters];
+  den.aspects.core.nix.substituters = {
+    cache = {
+      directories = [
+        {
+          directory = "/var/lib/private/ncro";
+          user = "nobody";
+          group = "nogroup";
+          mode = "0700";
+        }
+      ];
+    };
+
+    nixos = {config, ...}: {
+      imports = [inputs.ncro.nixosModules.ncro];
+
+      nix.settings = {
+        substituters = lib.mkForce ["http://${config.services.ncro.settings.server.listen}"];
+        trusted-public-keys = [
+        ];
+      };
+
+      services.ncro = {
+        enable = true;
+        settings = {
+          server = {
+            listen = "localhost:9000";
+            read_timeout = "30s";
+            write_timeout = "30s";
+          };
+          cache = {
+            db_path = "/var/lib/ncro/routes.db";
+          };
+          upstreams = [
+            {
+              url = "https://cache.nixos.org";
+              priority = 15;
+              public_key = "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=";
+            }
+            {
+              url = "https://nix-community.cachix.org";
+              priority = 20;
+              public_key = "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=";
+            }
+            {
+              url = "https://mirrors.ustc.edu.cn/nix-channels/store";
+              priority = 10;
+            }
+            {
+              url = "https://mirrors.tuna.tsinghua.edu.cn/nix-channels/store";
+              priority = 10;
+            }
+            {
+              url = "https://cache.flox.dev";
+              priority = 30;
+              public_key = "flox-cache-public-1:7F4OyH7ZCnFhcze3fJdfyXYLQw/aV7GEed86nQ7IsOs=";
+            }
+          ];
+        };
+      };
+    };
+  };
+}
modules/core/editor.nix
@@ -0,0 +1,11 @@
+{den, ...}: {
+  den.aspects.core.includes = [den.aspects.core.editor];
+  den.aspects.core.editor = {
+    nixos = {pkgs, ...}: {
+      environment = {
+        systemPackages = [pkgs.helix];
+        variables.EDITOR = "hx";
+      };
+    };
+  };
+}
modules/core/harden.nix
@@ -0,0 +1,46 @@
+{den, ...}: {
+  den.aspects.core.includes = [den.aspects.core.harden];
+  den.aspects.core.harden = {
+    nixos = {pkgs, ...}: {
+      security.apparmor = {
+        enable = true;
+        killUnconfinedConfinables = true;
+        packages = with pkgs; [
+          apparmor-utils
+          apparmor-profiles
+        ];
+      };
+
+      # Copy from https://wiki.nixos.org/wiki/NixOS_Hardening#Module_blacklist
+      boot.blacklistedKernelModules = [
+        # Obscure network protocols
+        "ax25"
+        "netrom"
+        "rose"
+
+        # Old or rare or insufficiently audited filesystems
+        "adfs"
+        "affs"
+        "bfs"
+        "befs"
+        "cramfs"
+        "efs"
+        "erofs"
+        "exofs"
+        "freevxfs"
+        "f2fs"
+        "hfs"
+        "hpfs"
+        "jfs"
+        "minix"
+        "nilfs2"
+        "ntfs"
+        "omfs"
+        "qnx4"
+        "qnx6"
+        "sysv"
+        "ufs"
+      ];
+    };
+  };
+}
modules/core/misc.nix
@@ -0,0 +1,37 @@
+{den, ...}: {
+  den.aspects.core.includes = [den.aspects.core.misc];
+  den.aspects.core.misc = {
+    nixos = {lib, ...}: {
+      # Don't need to keep too many generations when using Git for version control.
+      boot.loader.systemd-boot.configurationLimit = lib.mkDefault 10;
+
+      networking.nftables.enable = true;
+
+      networking.timeServers = [
+        "time.cloudflare.com" # Cloudflare NTP server
+        "ntp.aliyun.com" # Aliyun NTP server
+        "ntp.tencent.com" # Tencent NTP server
+      ];
+
+      time.timeZone = "Asia/Shanghai";
+
+      i18n = {
+        defaultLocale = "en_US.UTF-8";
+        extraLocaleSettings = {
+          LC_COLLATE = "C.UTF-8";
+        };
+      };
+    };
+
+    hjem = {config, ...}: {
+      clobberFiles = true;
+      files.".bash_profile".text = ''
+        # load session variables
+        . ${config.environment.loadEnv}
+
+        # include .bashrc if it exists
+        [[ -f ~/.bashrc ]] && . ~/.bashrc
+      '';
+    };
+  };
+}
modules/core/nh.nix
@@ -0,0 +1,22 @@
+{den, ...}: {
+  den.aspects.core.includes = [den.aspects.core.nh];
+  den.aspects.core.nh = {
+    nixos = {
+      programs.nh = {
+        enable = true;
+        clean.enable = true;
+        clean.extraArgs = "--keep-since 4d --keep 3";
+      };
+
+      system.tools = {
+        # disable useless tools
+        nixos-build-vms.enable = false;
+        nixos-enter.enable = false;
+        nixos-generate-config.enable = false;
+        nixos-install.enable = false;
+        nixos-option.enable = false;
+        nixos-rebuild.enable = false; # No needed, use `nh os` instead.
+      };
+    };
+  };
+}
modules/core/openssh.nix
@@ -0,0 +1,62 @@
+{
+  den,
+  lib,
+  ...
+}: {
+  den.aspects.core.includes = [den.aspects.core.openssh];
+
+  den.aspects.core.openssh = {
+    settings.host = {
+      server = {
+        enable = lib.mkEnableOption "Whether to start OpenSSH server";
+        port = lib.mkOption {
+          type = lib.types.port;
+          default = 22;
+        };
+      };
+      authorizedKeys = lib.mkOption {
+        type = lib.types.listOf lib.types.str;
+        default = [];
+        description = "SSH authorized keys for root on this host.";
+      };
+    };
+
+    nixos = {host, ...}: {
+      services.openssh = {
+        enable = host.settings.core.openssh.server.enable;
+        ports = [host.settings.core.openssh.server.port];
+        generateHostKeys = true;
+        hostKeys = [
+          {
+            path = "/etc/ssh/ssh_host_ed25519_key";
+            type = "ed25519";
+          }
+          {
+            path = "/etc/ssh/ssh_host_rsa_key";
+            type = "rsa";
+            bit = 4096;
+          }
+        ];
+        settings = {
+          PermitRootLogin = "prohibit-password";
+          PasswordAuthentication = false;
+        };
+        # Mannualy open filewall
+        openFirewall = false;
+      };
+
+      users.users.root.openssh.authorizedKeys.keys =
+        host.settings.core.openssh.authorizedKeys;
+
+      networking.firewall.allowedTCPPorts = [
+        host.settings.core.openssh.server.port
+      ];
+
+      environment.enableAllTerminfo = host.settings.core.openssh.server.enable;
+    };
+
+    user = {user, ...}: {
+      openssh.authorizedKeys.keys = user.identity.sshKeys;
+    };
+  };
+}
modules/core/polkit.nix
@@ -0,0 +1,11 @@
+{den, ...}: {
+  den.aspects.core.includes = [den.aspects.core.polkit];
+  den.aspects.core.polkit = {
+    nixos = {
+      security.polkit = {
+        enable = true;
+        adminIdentities = ["unix-group:wheel"];
+      };
+    };
+  };
+}
modules/core/shell.nix
@@ -0,0 +1,58 @@
+{den, ...}: {
+  den.aspects.core.includes = [den.aspects.core.shell];
+  den.aspects.core.shell = {
+    nixos = {pkgs, ...}: let
+      flyline-src = pkgs.fetchFromGitHub {
+        owner = "HalFrgrd";
+        repo = "flyline";
+        tag = "v1.7.1";
+        hash = "sha256-MscTAE921ymn0qyL3YQ06P3+AGg23c//6rh7+c+Iv4Y=";
+      };
+      flyline = (pkgs.callPackage "${flyline-src}/nix/package.nix" {}).overrideAttrs {
+        cargoDeps = pkgs.rustPlatform.importCargoLock {
+          lockFile = "${flyline-src}/Cargo.lock";
+          outputHashes = {
+            "ansi-to-tui-8.0.1" = "sha256-kjTxPzF0eIgJqtfsmquAqo1UFt1hXWv4oACFRgnHg9k=";
+            "flash-0.0.6" = "sha256-lIfTgRdBQWqOeYo3XkI/X6Q/0Vrcpm5vJMCxtX4u9Go=";
+            "flycomp-1.1.2" = "sha256-ipOFG1ZSro5OyWzCu28AYd2+eAuSW7vRDHOT5PuxDPA=";
+            "ratatui-0.30.2" = "sha256-68o9FXF2ioEuXyCq+3254ud95mVF3FRKVPOuBFKWeSI=";
+            "skim-4.6.0" = "sha256-cUSiXwEWUDZccbl3sts2DG4ZNzYExD9ra/VESv2u+Zs=";
+            "termina-0.3.3" = "sha256-WpBKKnOhA+Q1+iopQ3IcGxsjGGW1SNweo8R7gFN5QRA=";
+          };
+        };
+      };
+    in {
+      environment.systemPackages = [flyline];
+
+      programs.bash = {
+        enable = true;
+        completion.enable = true;
+        interactiveShellInit = ''
+          enable -f ${flyline}/lib/libflyline.so flyline
+        '';
+        promptInit = ''
+          # Provide a nice prompt if the terminal supports it.
+          if [ "$TERM" != "dumb" ] || [ -n "$INSIDE_EMACS" ]; then
+            PROMPT_COLOR="1;31m"
+            ((UID)) && PROMPT_COLOR="1;32m"
+            # Show the hostname only when connected via SSH.
+            SSH_HOST=""
+            [ -n "$SSH_CONNECTION" ] && SSH_HOST="@$HOSTNAME"
+            if [ -n "$INSIDE_EMACS" ]; then
+              # Emacs term mode doesn't support xterm title escape sequence (\e]0;)
+              PS1="\[\033[$PROMPT_COLOR\]\u$SSH_HOST\[\033[0m\]: \[\033[1;34m\]\w\[\033[0m\]\n\[\033[$PROMPT_COLOR\]\\$\[\033[0m\] "
+            else
+              PS1="\[\033[$PROMPT_COLOR\]\u$SSH_HOST\[\033[0m\]: \[\033[1;34m\]\w\[\033[0m\]\n\[\033[$PROMPT_COLOR\]\\$\[\033[0m\] "
+              PS1="\[\e]0;\u@\h: \w\a\]$PS1"
+            fi
+            if test "$TERM" = "xterm"; then
+              PS1="\[\033]2;\h:\u:\w\007\]$PS1"
+            fi
+            # Final (transient) prompt: replace the two-line prompt in scrollback.
+            PS1_FINAL="\[\033[$PROMPT_COLOR\]\u@\h\\$\[\033[0m\] "
+          fi
+        '';
+      };
+    };
+  };
+}
modules/core/state-version.nix
@@ -0,0 +1,8 @@
+{den, ...}: {
+  den.aspects.core.includes = [den.aspects.core.state-version];
+  den.aspects.core.state-version = let
+    stateVersion = "26.05";
+  in {
+    nixos.system.stateVersion = stateVersion;
+  };
+}
modules/core/sudo.nix
@@ -0,0 +1,25 @@
+{den, ...}: {
+  den.aspects.core.includes = [den.aspects.core.sudo];
+  den.aspects.core.sudo = {
+    nixos = {
+      security.sudo = {
+        enable = true;
+        extraRules = [
+          {
+            commands =
+              map
+              (command: {
+                command = "/run/current-system/sw/bin/${command}";
+                options = ["NOPASSWD"];
+              })
+              [
+                "poweroff"
+                "reboot"
+              ];
+            groups = ["wheel"];
+          }
+        ];
+      };
+    };
+  };
+}
modules/core/tools.nix
@@ -0,0 +1,35 @@
+{den, ...}: {
+  den.aspects.core.includes = [den.aspects.core.tools];
+  den.aspects.core.tools = {
+    nixos = {pkgs, ...}: {
+      environment.systemPackages = with pkgs; [
+        # Basic tools
+        coreutils
+        findutils
+
+        # Archives process
+        gnutar
+        p7zip
+        unzipNLS
+        xz
+        zip
+        zstd
+
+        # Networking
+        curl
+        netcat
+        tcpdump
+        wget
+
+        # Misc
+        microfetch
+        fd
+        file
+        git
+        which
+
+        rsync
+      ];
+    };
+  };
+}
modules/core/xdg-dirs.nix
@@ -0,0 +1,25 @@
+{den, ...}: {
+  den.aspects.core.includes = [den.aspects.core.xdg-dirs];
+  den.aspects.core.xdg-dirs = {
+    provides.to-users = {
+      cacheHome = {config, ...}: {
+        directories = [
+          config.xdg.cache.directory
+        ];
+      };
+
+      hjem = {config, ...}: {
+        environment.sessionVariables = {
+          XDG_BIN_HOME = "${config.directory}/.local/bin";
+        };
+
+        xdg = {
+          cache.directory = "${config.directory}/.cache";
+          config.directory = "${config.directory}/.config";
+          data.directory = "${config.directory}/.local/share";
+          state.directory = "${config.directory}/.local/state";
+        };
+      };
+    };
+  };
+}
modules/hosts/cyrene/default.nix
@@ -13,5 +13,15 @@
     };
 
     settings.secret.pubKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOhtRc77FG6usuOu3KQ6ar1Qc8j52RZ4L7RSJlyl8qxK root@cyrene";
+
+    settings.core.openssh = {
+      server = {
+        enable = true;
+        port = 51093;
+      };
+      authorizedKeys = [
+        "sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIH6wZFUEv9pSV+MgzqZRJ08WwJvL5FRMhayp73kCnDckAAAABHNzaDo= me@hpcesia.com"
+      ];
+    };
   };
 }
modules/hosts/hyacine/default.nix
@@ -13,5 +13,15 @@
     };
 
     settings.secret.pubKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAlF4NQvg+huSucSEvnS8vxwqyNPPTa4kxNW184WxnhH root@hyacine";
+
+    settings.core.openssh = {
+      server = {
+        enable = true;
+        port = 22876;
+      };
+      authorizedKeys = [
+        "sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIH6wZFUEv9pSV+MgzqZRJ08WwJvL5FRMhayp73kCnDckAAAABHNzaDo= me@hpcesia.com"
+      ];
+    };
   };
 }
modules/hosts/mobius/default.nix
@@ -13,5 +13,12 @@
     };
 
     settings.secret.pubKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKSHlIARpQYDi744NML9QmFMxOEZwShfyj/ovQh6lCt7 root@mobius";
+
+    settings.core.openssh = {
+      server.enable = true;
+      authorizedKeys = [
+        "sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIH6wZFUEv9pSV+MgzqZRJ08WwJvL5FRMhayp73kCnDckAAAABHNzaDo= me@hpcesia.com"
+      ];
+    };
   };
 }
modules/hosts/tribios/default.nix
@@ -13,5 +13,12 @@
     };
 
     settings.secret.pubKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMQTx9RhZJa4WOAJyAUzlQLaFExcDv921sVsfM02vB9h root@tribios";
+
+    settings.core.openssh = {
+      server.enable = true;
+      authorizedKeys = [
+        "sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIH6wZFUEv9pSV+MgzqZRJ08WwJvL5FRMhayp73kCnDckAAAABHNzaDo= me@hpcesia.com"
+      ];
+    };
   };
 }
modules/hosts/default.nix
@@ -1,5 +1,7 @@
 {den, ...}: {
   den.default.includes = [
     den.batteries.hostname
+
+    den.aspects.core
   ];
 }
modules/users/hpcesia/default.nix
@@ -3,6 +3,10 @@
     identity = {
       displayName = "HPCesia";
       email = "me@hpcesia.com";
+      sshKeys = [
+        "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFMKaGC2I3an4AJDeWzVx5vhm63+kxi6zJNdh7yEp6CK hpcesia@kevin"
+        "sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIH6wZFUEv9pSV+MgzqZRJ08WwJvL5FRMhayp73kCnDckAAAABHNzaDo= me@hpcesia.com"
+      ];
     };
     system = {
       hashedPasswordAged = ./hashed-password.age;
modules/users/schema.nix
@@ -10,6 +10,7 @@
       lib.types.submodule ({name, ...}: {
         freeformType = lib.types.attrsOf lib.types.anything;
         options = {
+          admin = lib.mkEnableOption "Whether to add user to admin user";
           identity = lib.mkOption {
             type = lib.types.submodule {
               options = {
@@ -23,6 +24,10 @@
                   default = null;
                   description = "Email address for the user";
                 };
+                sshKeys = lib.mkOption {
+                  type = lib.types.listOf lib.types.str;
+                  default = [];
+                };
               };
             };
             default = {};
flake.lock
@@ -155,6 +155,26 @@
         "type": "github"
       }
     },
+    "ncro": {
+      "inputs": {
+        "nixpkgs": [
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1786701834,
+        "narHash": "sha256-Ixz0rc6rnDEgNG6Cw2LJRdKxGjMbdy9bC9ncjAU+SmA=",
+        "owner": "manic-systems",
+        "repo": "ncro",
+        "rev": "3cc83303cc859901eb4330e9c4319b61f6ba1ffc",
+        "type": "github"
+      },
+      "original": {
+        "owner": "manic-systems",
+        "repo": "ncro",
+        "type": "github"
+      }
+    },
     "nixpkgs": {
       "locked": {
         "lastModified": 1785571196,
@@ -205,6 +225,7 @@
         "flake-parts": "flake-parts",
         "hjem": "hjem",
         "import-tree": "import-tree",
+        "ncro": "ncro",
         "nixpkgs": "nixpkgs",
         "vaultix": "vaultix"
       }
flake.nix
@@ -22,6 +22,10 @@
       inputs.nixpkgs.follows = "nixpkgs";
     };
     import-tree.url = "github:denful/import-tree";
+    ncro = {
+      url = "github:manic-systems/ncro";
+      inputs.nixpkgs.follows = "nixpkgs";
+    };
     nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
     vaultix = {
       url = "github:HPCesia/vaultix";