Skip to content

vic/den

Repository files navigation

Sponsor Vic Ask DeepWiki Dendritic Nix License CI Status

den - Aspect-oriented context-driven Dendritic Nix configurations.

den and vic's dendritic libs made for you with Love++ and AI--. If you like my work, consider sponsoring

At its core, Den is a library built on flake-aspects for activating configuration-aspects via context-transformation pipelines.

On top of the library, Den provides a framework for the NixOS/nix-Darwin/Home-Manager Nix domains.

Den embraces your Nix choices and does not impose itself. All parts of Den are optional and replaceable. Works with your current setup, with/without flakes, flake-parts or any other Nix module system.

Templates:

default: +flake-file +flake-parts +home-manager

minimal: +flakes -flake-parts -home-manager

noflake: -flakes +npins +lib.evalModules +nix-maid

example: cross-platform

ci: Each feature tested as code examples

bogus: Isolated test for bug reproduction

Examples:

vic/vix: author spends more time in Den itself (-flakes)

quasigod.xyz: beautiful organization (+flake-parts)

GitHub Search

❄️ Try it:

nix run github:vic/den
nix flake init -t github:vic/den && nix run .#vm

Testimonials

Den takes the Dendritic pattern to a whole new level, and I cannot imagine going back.
— @adda - Very early Den adopter after using Dendritic flake-parts and Unify.

I’m super impressed with den so far, I’m excited to try out some new patterns that Unify couldn’t easily do.
— @quasigod - Unify dendritic-framework author on adopting Den.

Massive work you did here!
— @drupol - Author of “Flipping the Configuration Matrix” Dendritic blog post.

Thanks for the awesome library and the support for non-flakes… it’s positively brilliant!. I really hope this gets wider adoption.
— @vczf - At den matrix channel.

Code example (OS configuration domain)

# Define hosts, users & homes
den.hosts.x86_64-linux.lap.users.vic = {};
den.hosts.aarch64-darwin.mac.users.vic = {};
den.homes.aarch64-darwin.vic = {};
$ nixos-rebuild switch --flake .#lap
$ darwin-rebuild switch --flake .#mac
$ home-manager   switch --flake .#vic
# extensible base modules for common, typed schemas
den.base.user = { user, lib, ... }: {
  config.classes =
    if user.userName == "vic" then [ "hjem" "maid" ]
    else lib.mkDefault [ "homeManager" ];

  options.mainGroup = lib.mkOption { default = user.userName; };
};
# modules/my-laptop.nix
{ den, inputs, ... }: {
  den.aspects.my-laptop = {
    # re-usable configuration aspects
    includes = [ den.aspects.work-vpn ];

    # regular nixos/darwin modules or any other Nix class
    nixos  = { pkgs, ... }: { imports = [ inputs.disko.nixosModules.disko ]; };
    darwin = { pkgs, ... }: { imports = [ inputs.nix-homebrew.darwinModules.nix-homebrew ]; };

    # Den `os` Nix class forwards to both nixos and darwin
    os = { pkgs, ... }: {
      networking.hostName = "yavanna";
      environment.packages = [ pkgs.direnv ];
    };

    # host can contribute to its users' environment
    homeManager.programs.vim.enable = true;
  };
}
# modules/vic.nix
{ den, ... }: {
  den.aspects.vic = {
    # supports multiple home environments
    homeManager = { pkgs, ... }: { };
    hjem.files.".envrc".text = "use flake ~/hk/home";
    maid.kconfig.settings.kwinrc.Desktops.Number = 3;

    # user can contribute configurations to all hosts it lives on
    darwin.services.karabiner-elements.enable = true;

    # user class forwards into {nixos/darwin}.users.users.<userName>
    user = { pkgs, ... }: {
      packages = [ pkgs.helix ];
      description = "oeiuwq";
    };

    includes = [
      den.provides.primary-user        # re-usable batteries
      (den.provides.user-shell "fish") # parametric aspects
      den.aspects.tiling-wm            # your own aspects
      den.aspects.gaming.provides.emulators
    ];
  };
}
# Custom Nix classes.

# Example: A class for role-based configuration between users and hosts

roleClass =
  { host, user }:
  { class, aspect-chain }:
  den._.forward {
    each = lib.intersectLists (host.roles or []) (user.roles or []);
    fromClass = lib.id;
    intoClass = _: host.class;
    intoPath = _: [ ];
    fromAspect = _: lib.head aspect-chain;
  };

den.ctx.user.includes = [ roleClass ];

den.hosts.x86_64-linux.igloo = {
  roles = [ "devops" "gaming" ];
  users = {
    alice.roles = [ "gaming" ];
    bob.roles = [ "devops" ];
  };
};

den.aspects.alice = {
  # enabled when host supports gaming role
  gaming = { pkgs, ... }: { programs.steam.enable = true; };

  # enabled when host supports devops role
  devops = { pkgs, ... }: { virtualisation.podman.enable = true; };
};
# Forward guards allow feature-detection without mkIf/mkMerge cluttering.

# Aspects use the `persys` class without any conditional. And guard guarantees
# settings are applied **only** when impermanence module has been imported.
persys = { host }: den._.forward {
  each = lib.singleton true;
  fromClass = _: "persys";
  intoClass = _: host.class;
  intoPath = _: [ "environment" "persistance" "/nix/persist/system" ];
  fromAspect = _: den.aspects.${host.aspect};
  guard = { options, config, ... }: options ? environment.persistance;
};

# enable on all hosts
den.ctx.host.includes = [ persys ];

# aspects just attach config to custom class
den.aspects.my-laptop.persys.hideMounts = true;