Modular, context-aware and aspect-oriented dendritic Nix configurations. Discussions: https://oeiuwq.zulipchat.com/join/nqp26cd4kngon6mo3ncgnuap/ den.oeiuwq.com
configurations den dendritic nix aspect oriented
8
fork

Configure Feed

Select the types of activity you want to include in your feed.

docs about aspects and contexts

+122 -2
+120
docs/src/content/docs/explanation/core-principles.mdx
··· 5 5 6 6 import { Aside } from '@astrojs/starlight/components'; 7 7 8 + **Aspects** and **Contexts** are Den core arquitectural principles. 9 + 10 + It is how Den supports different platform configurations, packages/checks flake outputs, different home environments suppport, 11 + wsl support, third-party flake-parts perSystem modules, microvm guests, and pretty much everything. 12 + 13 + It is also how more complex entities, like machine fleets, terraform or cloud infra can be configured with Den. 14 + 15 + <Aside title="Aspect-Oriented"> 16 + If you are familiar with Aspect-Oriented-Programming you will recognize how Den uses pointcuts to define where configurations get applied at each context stage. 17 + 18 + > Pointcuts in **Aspect-Oriented-Programming** determine where additional behavior (advice) should be applied in your code, typically at method execution points. 19 + </Aside> 20 + 21 + <Aside title="Context-Driven"> 22 + Den is, fundamentally, a _data transformation_ pipeline (of your infra entities) to which _functions_ (producing configurations) are applied. 23 + 24 + 25 + > A context transformation pipeline takes initially `{host}` and traverses its topology 26 + > `host`->`[users]`->`[homes]` aggregating dependencies, optionally branching to suport 27 + > feature detection `host`->`wsl-host` or `host`->`[microvm-guest]`. 28 + </Aside> 29 + 30 + From our README header example: 31 + 32 + ```nix 33 + # These three lines is how Den instantiates a configuration. 34 + # Other Nix configuration domains outside NixOS/nix-Darwin 35 + # can use the same pattern. demo: templates/nvf-standalone 36 + 37 + # A context transformation pipeline takes initially {host} 38 + # and traverses its topology (host->[users]->[homes]) aggregating deps 39 + aspect = den.ctx.host { host = den.hosts.x86_64-linux.my-laptop; }; 40 + 41 + # obtain the final module for nixos class 42 + nixosModule = den.lib.aspects.resolve "nixos" aspect; 43 + 44 + # Use NixOS API to instantiate or mix-in with other custom modules 45 + nixosConfigurations.my-laptop = lib.nixosConfiguration { modules = [ nixosModule ]; }; 46 + ``` 47 + 48 + Anything that you can describe via a data structure that can be traversed, can be configured like we do for NixOS. 49 + 50 + ### Den is Aspect-oriented 51 + 52 + <Aside icon="nix" title="Dendritic Aspects"> 53 + 54 + A Dendritic aspect is an attrset that contains modules of different Nix `class`. 55 + 56 + ```nix 57 + gaming = { host, user }: { nixos = ...; homeManager = ...; hjem = ...; darwin = ...; } 58 + ``` 59 + 60 + Such an attrset is said to be [**Dendritic**](https://dendrix.oeiuwq.com/Dendritic.html) because it allows configuring a single cross-cutting concern (`gaming`) over different configuration domains. 61 + 62 + Nix classes are NOT an artificial concept created by Den. There are [many nix classes in the wild](https://github.com/search?q=language%3ANix+%28%22+class+%3D+%22+AND+%22evalModules%22%29&type=code), the most common are [`nixos`](https://github.com/search?q=repo%3ANixOS%2Fnixpkgs+%22class+%3D+%5C%22nixos%5C%22%22&type=code), [`darwin`](https://github.com/nix-darwin/nix-darwin/blob/da529ac9e46f25ed5616fd634079a5f3c579135f/eval-config.nix#L81), [`homeManager`](https://github.com/nix-community/home-manager/blob/5be5d8245cbc7bc0c09fbb5f38f23f223c543f85/nixos/common.nix#L27). 63 + </Aside> 64 + 65 + Most importantly, the context `{host,user}` here are **not** `_module.args` **nor** `specialArgs`, it is an actual function, not a module-looking-as-a-function. This means config can depend on context without Nix infinite loops. 66 + 67 + 68 + ### Den is Context-driven 69 + 70 + Den uses `den.ctx.<name>.provides.<name>` as **Aspect Pointcuts** where configuration is applied to data in that context stage. 71 + Say you have a data shape: `{ x }`, that you name as a `foo` context stage: 72 + 73 + ```nix 74 + # This says how to move from one context stage `foo` into another stage `bar` 75 + den.ctx.foo.into.bar = { x }: [ { y = x; } ] 76 + ``` 77 + 78 + The following `den.ctx.bar.provides.bar` is the actual pointcut that **locates** the aspect responsible for configuring 79 + using data `{ y }` available at `bar` context stage. 80 + 81 + ```nix 82 + # inlined aspect for this example, but can locate the aspect by any means 83 + den.ctx.bar.provides.bar = { y }: { nixos.something = y; } 84 + ``` 85 + 86 + and since `den.ctx.bar` **is** itself an aspect, it can be used to include 87 + additional configurations at that particular stage: 88 + 89 + ```nix 90 + den.ctx.bar.nixos.something-else = true; 91 + den.ctx.bar.includes = [ den.aspects.other ]; 92 + ``` 93 + 94 + ### `den.ctx.host` pipeline 95 + 96 + This is how everything works in Den, the following is the context transitions 97 + that happen when applying `den.ctx.host { host }` 98 + 99 + ```nix 100 + # host configuration: THIS is where your host-aspect is hooked into the pipeline 101 + den.ctx.host.provides.host = { host }: den.aspects.${host.aspect}; 102 + 103 + # host -> users context transformation 104 + den.ctx.host.into.user = { host }: map (user: { inherit host user; }) (lib.attrValues host.users); # transition into many { host, user } 105 + 106 + # user configuration: Lookup user aspect. 107 + den.ctx.user.provides.user = { host, user }: den.aspects.${user.aspect}; # Hook for the user-aspect. 108 + 109 + # conditional transition ONLY if hm is enabled for user and host. 110 + den.ctx.user.into.hm-user = { host, user }: lib.optional (host.hm.enable && lib.elem "homeManager" user.classes) { inherit host user; } 111 + 112 + # host -> wsl-host: Same data shape, different context stage. 113 + den.ctx.host.into.wsl-host = { host }: lib.optional host.wsl.enable { inherit host; } 114 + ``` 115 + 116 + **people can define their own extensions to Den's NixOS pipeline, or define other pipelines enterely**. 117 + 118 + <Aside title="Real world examples"> 119 + Minimal real-life example: [wsl support](https://github.com/vic/den/blob/main/modules/aspects/provides/wsl.nix) 120 + 121 + [home-env](https://github.com/vic/den/blob/main/nix/lib/home-env.nix#L97) is how Den implements homeManager/hjem/maid support 122 + 123 + [flake-parts perSystem classes](https://github.com/vic/den/blob/main/templates/flake-parts-modules/modules/custom-classes.nix) 124 + 125 + [microvm guests support](https://github.com/vic/den/blob/main/templates/microvm/modules/microvm-integration.nix#L46) 126 + </Aside> 127 + 8 128 ## Feature-First, Not Host-First 9 129 10 130 <Aside title="Recommended Read">
+2 -2
docs/src/content/docs/index.mdx
··· 11 11 - text: Getting Started 12 12 link: /guides/from-zero-to-den 13 13 icon: right-arrow 14 - - text: Den Library/Framework 15 - link: /explanation/library-vs-framework 14 + - text: Core Principles 15 + link: /explanation/core-principles 16 16 variant: minimal 17 17 - text: Why Den? 18 18 link: /motivation/