Commit 77f46c8

HPCesia <me@hpcesia.com>
2026-08-02 17:47:14
den: add shared den.users, merge into per-host users
Add options.den.users as a shared user definitions registry, merged into every host's user schema for users of the same name. Aspects receive the merged values through their user context argument. Assisted-by: opencode:deepseek-v4-flash
1 parent 4b48301
Changed files (9)
modules
modules/hosts/cyrene/default.nix
@@ -8,6 +8,7 @@
     '';
 
     users.hpcesia = {
+      admin = true;
       classes = ["user" "hjem"];
     };
   };
modules/hosts/hyacine/default.nix
@@ -8,6 +8,7 @@
     '';
 
     users.hpcesia = {
+      admin = true;
       classes = ["user" "hjem"];
     };
   };
modules/hosts/kevin/default.nix
@@ -8,6 +8,7 @@
     '';
 
     users.hpcesia = {
+      admin = true;
       classes = ["user" "hjem"];
     };
   };
modules/hosts/mobius/default.nix
@@ -8,6 +8,7 @@
     '';
 
     users.hpcesia = {
+      admin = true;
       classes = ["user" "hjem"];
     };
   };
modules/hosts/tribios/default.nix
@@ -8,6 +8,7 @@
     '';
 
     users.hpcesia = {
+      admin = true;
       classes = ["user" "hjem"];
     };
   };
modules/users/hpcesia/default.nix
@@ -1,4 +1,11 @@
 {
+  den.users.hpcesia = {
+    identity = {
+      displayName = "HPCesia";
+      email = "me@hpcesia.com";
+    };
+  };
+
   den.aspects.hpcesia = {
   };
 }
modules/users/default.nix
@@ -12,5 +12,23 @@
         isNormalUser = true;
       };
     })
+    ({user, ...}: {
+      name = "user-description/${user.userName}";
+      user.description = user.identity.displayName;
+    })
+    ({
+      host,
+      user,
+      ...
+    }: {
+      name = "user-admin/${user.userName}@${host.name}";
+      nixos.users.users.${user.userName} = {
+        isNormalUser = true;
+        extraGroups = [
+          "wheel"
+          "networkmanager"
+        ];
+      };
+    })
   ];
 }
modules/users/schema.nix
@@ -1,2 +1,65 @@
 {
+  lib,
+  config,
+  ...
+}: {
+  # Share a portion of the user schema across every host that declares
+  # the same user. Hosts without the user stay unaffected.
+  options.den.users = lib.mkOption {
+    type = lib.types.attrsOf (
+      lib.types.submodule ({name, ...}: {
+        freeformType = lib.types.attrsOf lib.types.anything;
+        options = {
+          identity = lib.mkOption {
+            type = lib.types.submodule {
+              options = {
+                displayName = lib.mkOption {
+                  type = lib.types.str;
+                  default = name;
+                  description = "Display name for the user";
+                };
+                email = lib.mkOption {
+                  type = lib.types.nullOr lib.types.str;
+                  default = null;
+                  description = "Email address for the user";
+                };
+              };
+            };
+            default = {};
+          };
+        };
+      })
+    );
+    default = {};
+    description = ''
+      Shared user definitions, keyed by user name.
+
+      Merged into the user schema of every host that declares `users.<name>`
+      in its `den.hosts` entry; host-specific values override shared ones.
+    '';
+  };
+
+  config.den.schema.user = {
+    # `config` referencing the instance's own args are forced while the
+    # fixpoint is still being built and recurse, so the per-user name can only
+    # be recovered from the freeform merge's option path.
+    options._module.freeformType = lib.mkOption {
+      apply = t:
+        if t == null
+        then null
+        else
+          lib.mkOptionType {
+            name = "den-shared-user-freeform";
+            check = builtins.isAttrs;
+            # If without any freeform definitions, the module system will skips
+            # the freeform merge entirely, so the shared registry would never
+            # reach hosts that declare `users.<name> = {}`.
+            merge = loc: defs:
+              lib.removeAttrs (
+                lib.recursiveUpdate (config.den.users.${lib.last loc} or {}) (t.merge loc defs)
+              ) ["ixSharedSentinel"];
+          };
+    };
+    config.ixSharedSentinel = true;
+  };
 }
README.md
@@ -3,6 +3,11 @@
 HPCesia's [Dendritic Pattern](https://github.com/mightyiam/dendritic) NixOS
 configuration for all my machines, powered by [den](https://github.com/denful/den).
 
+## LLM Usage Statement
+
+The code regarding the internal mechanisms of the den framework was basically all
+written by LLMs.
+
 ## Acknowledgements
 
 - [chlorine/shosai](https://src.chlo.is/chlorine/shosai)