···18181919<img width="300" height="300" alt="den" src="https://github.com/user-attachments/assets/af9c9bca-ab8b-4682-8678-31a70d510bbb" />
20202121-- Dendritic: Same concern over different classes.
2121+- Dendritic: same concern, different classes and context-aware.
22222323-- Small and [DRY](modules/aspects/provides/unfree.nix)<br>
2424- [`class` generic](modules/aspects/provides/primary-user.nix) Nix configurations.
2323+- Small, [DRY](modules/aspects/provides/unfree.nix) & [`class`-generic](modules/aspects/provides/primary-user.nix) modules.
25242626-- Context-Aware aspects.<br>[Parametric](modules/aspects/provides/define-user.nix) over `host`/`home`/`user`.
2525+- [Parametric](modules/aspects/provides/define-user.nix) over `host`/`home`/`user`.
27262828-- Stop copying and **share**(tm)<br>
2929- aspects across systems and Dendritic repos.
2727+- [Share](templates/default/modules/_profile/namespace.nix) aspects across systems & repos.
30283131-- Bidirectional [configurations](modules/aspects/dependencies.nix).<br>
3232- Users can contribute to their Host configuration and the other way around.
3333-3434-- Custom factories and output attributes.<br>
3535- Support any new `class` of Nix configurations.
2929+- Bidirectional [dependencies](modules/aspects/dependencies.nix): user/host contributions.
36303737-- Use your `stable`/`unstable` input channels.
3131+- Custom factories for any Nix `class`.
38323939-- _Freeform_ `host`/`user`/`home` [schemas](modules/_types.nix).<br>
4040- Avoid the need for using `specialArgs`.
3333+- Use `stable`/`unstable` channels per config.
41344242-- Multi-platform, Multi-tenant hosts.
3535+- Freeform `host`/`user`/`home` [schemas](modules/_types.nix) (no `specialArgs`).
43364444-- Reuse aspects across hosts, OS, homes.
3737+- Multi-platform, multi-tenant hosts.
45384646-- [Batteries Included](modules/aspects/provides/)<br>
4747- Opt-in and replaceable.
3939+- [Batteries](modules/aspects/provides/): Opt-in, replaceable aspects.
48404949-- [Well tested](templates/default/modules/_example/ci.nix)<br>
5050- Suite exercises all [features with examples](templates/default/modules/).
4141+- [Well-tested](templates/default/modules/_example/ci.nix) with an [example suite](templates/default/modules/).
51425243Need more batteries? See [vic/denful](https://github.com/vic/denful).
53445454-Join the community [discussion](https://github.com/vic/den/discussions). Ask questions, share how you use `den`.
4545+Join our [community discussion](https://github.com/vic/den/discussions).
55465647</div>
5748</td>
5849<td>
59506060-🏠 Concise definitions of
6161-[Hosts, Users](templates/default/modules/_example/hosts.nix) and [Standalone-Homes](templates/default/modules/_example/homes.nix).
5151+🏠 Define [Hosts, Users](templates/default/modules/_example/hosts.nix) & [Homes](templates/default/modules/_example/homes.nix) concisely.
62526363-See [\_types.nix](modules/_types.nix) for complete schema.
5353+See schema in [`_types.nix`](modules/_types.nix).
64546555```nix
6656# modules/hosts.nix
5757+# OS & standalone homes share 'vic' aspect.
5858+# $ nixos-rebuild switch --flake .#my-laptop
5959+# $ home-manager switch --flake .#vic
6760{
6868- # This example defines the following aspects:
6969- # den.aspects.my-laptop and den.aspects.vic
7070- # standalone-hm and nixos-hm share vic aspect
7171-7272- # $ nixos-rebuild switch --flake .#my-laptop
7373- den.hosts.x86-64-linux.my-laptop.users.vic = {};
7474- # $ home-manager switch --flake .#vic
7575- den.homes.aarch64-darwin.vic = { };
7676-7777- # That's it! Now lets attach configs via aspects
6161+ den.hosts.x86-64-linux.laptop.users.vic = {};
6262+ den.homes.aarch64-darwin.vic = {};
7863}
7964```
80658181-🧩 [Aspect-oriented](https://github.com/vic/flake-aspects) configurations. ([example](templates/default/modules/_example/aspects.nix))
6666+🧩 [Aspect-oriented](https://github.com/vic/flake-aspects) incremental features. ([example](templates/default/modules/_example/aspects.nix))
6767+6868+Any module can contribute configurations to aspects.
82698370```nix
8484-# modules/my-laptop.nix -- Attach behaviour to host
8585-{ den, ... }:
8686-{
7171+# modules/my-laptop.nix
7272+{ den, ... }: {
8773 den.aspects.my-laptop = {
8888- # dependency graph on other shared aspects
8974 includes = [
9090- # my parametric { host } => aspect
9191- den.aspects.vpn # setups firewall/daemons
9292- # opt-in, replaceable batteries included
9393- den._.home-manager
7575+ den.aspects.vpn # { host } => config
7676+ den._.home-manager # battery
9477 ];
9595- # provide same features at any OS/platform
9696- nixos = ...; # (see nixos options)
9797- darwin = ...; # (see nix-darwin options)
9898- # contrib hm-config to all my-laptop users
7878+ nixos = { /* NixOS options */ };
7979+ darwin = { /* nix-darwin options */ };
8080+ # For all users of my-laptop
9981 homeManager.programs.vim.enable = true;
10082 };
10183}
10284103103-# modules/vic.nix -- Reused in OS/standalone HM
104104-{ den, ... }:
105105-{
8585+# modules/vic.nix
8686+{ den, ... }: {
10687 den.aspects.vic = {
107107- homeManager = ...; # (see home-manager options)
108108- # user can contrib to hosts where it lives
109109- nixos.users.users.vic.description = "oeiuwq";
8888+ homeManager = { /* ... */ };
8989+ # User contribs to host
9090+ nixos.users.users = {
9191+ vic.description = "oeiuwq";
9292+ }
11093 includes = [
11194 den.aspects.tiling-wm
112112- # parametric { user, host } => aspect
113113- den._.primary-user # vic is admin
9595+ den._.primary-user
11496 ];
11597 };
11698}
11799```
118100119119-For real-world examples, see [`vic/vix`](https://github.com/vic/vix/tree/den)
120120-or try this [GH search](https://github.com/search?q=vic%2Fden+language%3ANix&type=code).
101101+For real-world examples, see [`vic/vix`](https://github.com/vic/vix/tree/den) or this [GH search](https://github.com/search?q=vic%2Fden+language%3ANix&type=code).
121102122122-**❄️ Try it now! Launch our template VM:**
103103+**❄️ Try it now!**
123104105105+Launch our template VM:
124106```console
125107nix run github:vic/den
126108```
127109128128-Or clone it and run the VM as you edit
110110+Or, initialize a project:
129111130112```console
131113nix flake init -t github:vic/den
···133115nix run .#vm
134116```
135117136136-Our [default template](templates/default) provides a [layout](templates/default/modules/_profile/) for quickstart.
118118+Our [default template](templates/default) provides a [profile-based layout](templates/default/modules/_profile/) for a quick start.
137119138120</td>
139121</tr>
140122</table>
141123142142-You are done! You know everything there is to know about `den` for creating configurations with it.
124124+You are done! You know everything to start creating configurations with `den`.
125125+126126+Feel free to to __explore__ the codebase, particularly our [included batteries](modules/aspects/provides) and [tests](templates/default/modules/_example).
143127144144-However, if you want to learn more about how it works, I have tried to document some other topics in collapsible sections to avoid distraction from the introduction.
128128+# Learn More
129129+130130+If you want to learn how `den` works, the following sections detail its concepts and patterns.
145131146132<details>
147133<summary>
148134149149-# Basic Concepts and Patterns.
135135+### Basic Concepts
150136151151-> Learn about aspects, static and parametric. Default aspects and dependencies.
137137+> Learn about static vs. parametric aspects, the default aspect, and dependencies.
152138153139</summary>
154140155155-There are two fundamental types of aspects in `den`, _static_ and _parametric_.
141141+`den` has two fundamental types of aspects: _static_ and _parametric_.
156142157143<table>
158144<tr>
159145<td>
160146161161-#### **Static** aspects are just attribute sets
147147+#### **Static** aspects are attribute sets.
148148+149149+An aspect is a set of modules for different `classes`, configuring a single concern across them.
162150163151```nix
164164-# An aspect is a collection of many
165165-# Nix configuration modules, each having
166166-# a different `class`.
167152den.aspects.my-laptop = {
168168- nixos = { };
169169- darwin = { };
170170- homeManager = { };
153153+ nixos = { /* ... */ };
154154+ darwin = { /* ... */ };
171155172172- # aspects can be nested via `_` (`provides`)
173173- # forming a tree structure.
156156+ # Nested aspects via `_`
157157+ # (alias for `provides`)
174158 _.gaming = {
175175- nixos = { };
176176-177177- # aspects can also `include` others
178178- # forming a graph of dependencies
179179- includes = [
180180- # gaming.nixos module will mixin
181181- # nvidia-gpu.nixos module if any.
182182- den.aspects.nvidia-gpu
183183- ];
159159+ nixos = { /* ... */ };
160160+ # Dependency graph via `includes`
161161+ includes = [ den.aspects.nvidia-gpu ];
184162 };
185185-186163};
187164```
188165189189-> **TIP**
190190-> **`_`** is an alias for `provides`. In many examples you will see `foo._.bar._.baz` instead of `foo.provides.bar.provides.baz`.
191191-192166</td>
193167<td>
194168195195-#### **Parametric** aspects are just functions.
169169+#### **Parametric** aspects are functions.
170170+171171+They take a `context` and return a configuration.
196172197173```nix
198198-# The convention is to always use named args.
199199-# These required args is the **context** the
200200-# aspect needs to provide configuration.
201201-hostParametric = { host }: {
174174+# A `{ host, gaming }` contextual aspect.
175175+hostFunction = { host, gaming }: {
202176 nixos.networking.hostName = host.hostName;
203203-204204- # A parametric aspect can also ask other
205205- # aspects for context-aware configurations.
206206- # Here, we ask two other parametric aspects
207207- # given the `{ host, gaming }` context.
208208- includes = let
209209- context.host = host;
210210- context.gaming.emulators = [ "nes" ];
211211- in map (f: f context) [
212212- den.default
213213- den.aspects.gaming-platform
214214- ];
215177};
216216-```
217178218218-#### Important **context** variants in `den`.
219219-220220-Den uses the following contexts by default.
221221-222222-The aspect system is not limited to these,<br>
223223-but these are used to describe [dependencies](modules/aspects/dependencies.nix)<br>
224224-between hosts/users, homes and default configs.
225225-226226-- `{ host }` - For host _OS_ level configs.
227227-- `{ user, host }` - For user _Home_ level configs.
228228-- `{ home }` - For standalone _Home_ configs.
179179+# A parametric aspect can request context-aware
180180+# configurations from other aspects.
181181+hostParametric = { host }: {
182182+ __functor = den.lib.parametric {
183183+ inherit host;
184184+ gaming.emulators = [ "nes" ];
185185+ };
186186+ includes = [ hostFunction den.default ];
187187+}
188188+```
229189230190</td>
231191</tr>
232192</table>
233193234234-### The Default aspect and default Dependencies
235235-236236-Den has an special aspect at `den.default` that serves for global configuration. `den.default` is **included by default** in all *Hosts*, *Users* and *Homes*. For example a Home configuration invokes `den.default { inherit home; }`, to obtain the aggregated defaults for home contexts.
194194+`den` uses several default contexts to manage [dependencies](modules/aspects/dependencies.nix):
237195238238-<table>
239239-<tr>
240240-<td>
241241-242242-#### Registering defaults values
243243-244244-```nix
245245-{
246246- # you can assign static values directly.
247247- den.default.nixos = {
248248- system.stateVersion = "25.11";
249249- };
250250-251251- # you can also include other aspects
252252- den.default.includes = [
253253- { darwin.system.stateVersion = 6; }
254254- ]
255255-}
256256-```
257257-258258-It is possible to also register context-aware parametric aspects in `den.defaults`. This is how you can provide a default to all hosts or users that match a condition.
259259-260260-```nix
261261-# This example is split to aid reading.
262262-let
263263- hasOneUser = host:
264264- length (attrNames host.users) == 1;
265265- hasUser = host: user:
266266- hasAttr user.name host.users;
267267- makeAdmin = user: {
268268- nixos.users.users.${user.name} = {
269269- extraGroups = [ "wheel" ];
270270- };
271271- };
272272-273273- # IFF host has ONE user, make it admin
274274- single-user-is-admin = { host, user }:
275275- if hasOneUser host && hasUser host user
276276- then makeAdmin user else { };
277277-in
278278-{
279279- den.default.includes = [
280280- # will be called *ONLY* on when the
281281- # `{ host, user }` context is used.
282282- single-user-is-admin
283283- ];
284284-}
285285-```
286286-287287-#### Custom parametric providers.
288288-289289-The following is the code for how `den.default` is
290290-defined.
291291-292292-```nix
293293-{ den, ... }: {
294294- den.default.__functor = den.lib.parametric true;
295295-}
296296-```
297297-298298-You can do the very same for other aspects of you
299299-that can have context-aware aspects in their `.includes`.
300300-301301-```nix
302302-{ den, ...}: {
303303- den.aspects.gaming.__functor = den.lib.parametric true;
304304-305305- # any other file can register gaming aspects
306306- den.aspects.gaming.includes = [
307307- ({ emulation }: {
308308- nixos = ...;
309309- includes = [ den.aspects.steam ];
310310- })
311311-312312- { nixos = ...; } # always included
313313- ({ gpu }: { }) # non-match on my-laptop
314314- ];
315315-316316- # then you can depend on the gaming aspect:
317317- den.aspects.my-laptop.includes = [
318318- (den.aspects.gaming { emulation = "neogeo"; })
319319- ];
320320-321321-}
322322-```
323323-324324-For more examples on parametric aspects explore our [batteries](modules/aspects/provides/).
325325-326326-> Use the source, Luke!
196196+- `{ host }`, `{ user, host }`, `{ home }`
197197+- `{ fromUser, toHost }`, `{ fromHost, toUser }`
327198328199</td>
329329-330330-<td>
331331-332332-#### Aspect dependencies
333333-334334-Accessing an aspect module causes `flake-aspects` to resolve it
335335-by including the aspect's own class module and the same-class module
336336-of all its transitive includes.
337337-338338-Additional to this, `den` registers some special [dependencies](modules/aspects/dependencies.nix)
339339-designed to aid on Den particular use case: Host/Users, Homes.
340340-341341-###### Host dependencies
342342-343343-Host also include `den.aspects.<host> { inherit host; }` meaning
344344-all included parametric aspects have an opportunity to produce
345345-aditional configurations for the host.
346346-347347-Also for each user, `den.aspects.<user> { inherit host user; }`
348348-is called. So `den.aspects.alice.nixos` can provide config to
349349-all hosts where alice lives. And also has the opportunity to
350350-register parametric aspects on `alice.provides` that inspect
351351-the host attribute to contionally produce other aspects.
200200+</tr>
201201+</table>
352202353353-###### User dependencies
203203+### The Default Aspect and Dependencies
354204355355-User modules are read from [os-home](modules/aspects/provides/home-manager.nix) configurations.
205205+`den` features a special aspect, `den.default`, which applies global configurations. It is automatically included in all hosts, users, and homes, receiving the appropriate context (e.g., `den.default { inherit home; }`).
356206357357-It basically invokes `den.aspects.<user> { inherit host user; }` but
358358-this time the host also contributes back generic configs to the users.
359359-If you are wondering how this is not recursive, the answer is by using
360360-our _contexts_, user-to-host dependencies start with a `{ host }` context,
361361-while host-to-user dependencies start with a `{ user, host }` context, and
362362-even when both are given to `den.aspects.<user> ctx` the results are
363363-non recursive.
207207+You can register static values or context-aware parametric aspects within `den.default`. This allows you to define defaults that apply conditionally to all hosts or users.
364208365365-A user also depends on `den.default { inherit host user; }`.
366366-367367-###### Home dependencies
368368-369369-Home just uses its own module, its includes, and invokes `den.default { inherit home; }`.
370370-371371-</td>
372372-373373-</tr>
374374-</table>
209209+A key feature of `den` is its management of aspect dependencies. When an aspect is resolved, `flake-aspects` includes its class-specific module along with those of its transitive `includes`. `den` extends this by registering special [dependencies](modules/aspects/dependencies.nix) to link hosts and users. For instance, a host's configuration includes contributions from each of its users' aspects, and a user's home configuration includes contributions from its host's aspect, creating a bidirectional flow of settings. This is achieved without recursion by using distinct contexts for each direction.
375210376211</details>
377212378213<details>
379214<summary>
380215381381-# Aspect Organization Patterns
216216+### Organization Patterns
382217383383-> Learn about organizing patterns for reuse.
218218+> Learn patterns for organizing and reusing aspects.
384219385220</summary>
386221387387-No two nix configurations are the same. We all tend to organize things as we feel better.
388388-This section will try to outline some hints on possible ways to organize aspects, none
389389-of this is mandatory, and indeed you are encouraged to explore and [share](https://github.com/vic/den/discussions) your own patterns and insights.
222222+While `den` is unopinionated about organization, these patterns can help structure your aspects for clarity and reuse.
390223391391-#### Having a _namespace_ of aspects.
392392-393393-The first principle is using `.provides.` (aka [`._.`](https://github.com/vic/den/discussions/34)) to nest your aspects as they make sense for you.
394394-395395-Unlike normal flake-parts, where modules are _flat_ and people tend to use names like `flake.modules.nixos."host/my-laptop"` or `nixos."feature/gaming"` to avoid collission, in `den` you have a proper tree structure.
396396-397397-I (_vic_), use an aspect `vix` for all _features_ on my system, and from there I create sub-aspects.
398398-399399-Because writing `den.aspects.vix._.gaming._.emulation` tends to be repetitive, I use the following `vix` alias as module argument.
400400-401401-> This pattern is also shown in the default template, under [`_profile`](templates/default/modules/_profile/).
224224+#### Aspect Namespaces
402225403403-> **NOTE**:
404404-> `den` provides an [__angle brackets__](https://fzakaria.com/2025/08/10/angle-brackets-in-a-nix-flake-world) **experimental feature** that allows even shorter syntax for deep `.provides.` access.
405405-> See [import-non-dendritic.nix](templates/default/modules/_example/import-non-dendritic.nix) for an example usage.
226226+Group related aspects under a single top-level aspect and alias it as a module argument for easier access. The `den.namespace` function streamlines this.
406227407228<table>
408229<tr>
409230<td>
410231232232+#### Using local and remote namespaces
233233+411234```nix
412235# modules/namespace.nix
413413-{ config, ... }:
236236+{ inputs, ... }:
414237{
415415- den.aspects.vix = { };
416416- _module.args.vix = config.den.aspects.vix._;
238238+ imports = [
239239+ # create local `pro` namespace
240240+ (inputs.den.namespace "pro" true)
241241+ # mixin remote `pro` from input
242242+ (inputs.den.namespace "pro" inputs.foo)
243243+ ];
417244}
418245```
419246420247</td>
421248<td>
422249250250+#### Directly read and write to namespace
251251+423252```nix
424253# modules/my-laptop.nix
425425-{ vix, ... }:
254254+{ pro, ... }:
426255{
427427- vix.gaming = {
428428- _.steam.includes = [
429429- vix.gpu
430430- vix.performance-profile
431431- ];
432432- };
256256+ pro.gaming.includes = [ pro.gpu ];
433257}
434258```
435259436436-See [real-life example from vic/vix](https://github.com/vic/vix/blob/den/modules/hosts/nargun.nix)
437437-438260</td>
439261</tr>
440262</table>
441263442442-#### Using parametric aspects to route configurations.
264264+#### Angle-Bracket Syntax
443265444444-The following example routes configurations into the `vix` namespace.
445445-This is just an example of using parametric aspects to depend on other
446446-aspects in any part of the tree.
266266+For deeply nested aspects, `den` offers an experimental feature to shorten access paths. By bringing `den.lib.__findFile` into scope, you can use angle brackets to reference aspects more concisely.
447267448448-<table>
449449-<tr>
450450-<td>
268268+- `<my-laptop>` resolves to `den.aspects.my-laptop`
269269+- `<my-laptop/gaming>` resolves to `den.aspects.my-laptop.provides.gaming`
270270+- `<den/import-tree/host>` resolves to `den.provides.import-tree.provides.home`
271271+- `<vix/foo/bar>` namespace aware: `den.ful.vix.foo.provides.bar`
451272452452-```nix
453453-# modules/routes.nix
454454-{ den, ... }:
455455-let
456456- noop = _: { };
273273+This feature is powered by a custom [`__findFile`](nix/den-brackets.nix) implementation. See the [profile example](templates/default/modules/_profile/den-brackets.nix) to learn how to enable it.
457274458458- by-platform-config = { host }:
459459- vix.${host.system} or noop;
460460-461461- user-provides-host-config = { user, host }:
462462- vix.${user.aspect}._.${host.aspect} or noop;
463463-464464- host-provides-user-config = { user, host }:
465465- vix.${host.aspect}._.${user.aspect} or noop;
466466-467467- route = locator: { user, host }@ctx:
468468- (locator ctx) ctx;
469469-in
470470-{
471471- den.aspects.routes.__functor =
472472- den.lib.parametric true;
473473- den.aspects.routes.includes =
474474- map route [
475475- user-provides-host-config
476476- host-provides-user-config
477477- by-platform-config
478478- ];
479479-}
480480-```
275275+#### Parametric Routing
481276482482-</td>
483483-<td>
277277+You can use parametric aspects to create routing logic that dynamically includes other aspects based on context. This pattern allows you to build a flexible and declarative dependency tree.
484278485279```nix
280280+# modules/routes.nix
281281+{ den, pro, ... }:
282282+let
283283+ # Route to a platform-specific profile
284284+ by-platform = { host }: pro.${host.system} or { };
285285+in
486286{
487487- # for all darwin hardware
488488- vix.aarch64-darwin = { host }: {
489489- darwin = ...;
490490- };
491491-492492- # config bound to vic user
493493- # on my-laptop host.
494494- vix.vic.provides.my-laptop =
495495- { host, user }: {
496496- nixos = ...;
497497- };
287287+ # Apply routes globally
288288+ den.default.includes = [ by-platform ];
498289}
499290```
500291501501-Use your imagination, come up with
502502-an awesome Dendritic setup that suits you.
503503-504504-</td>
505505-</tr>
506506-</table>
507507-508508-> You made it to the end!, thanks for reading to this point.
509509-> I hope you enjoy using `den` as much as I have done writing it and have put dedication
510510-> on it for being high quality-nix for you. \<3.
511511-> I feel like den is now feature complete, and it will not likely change.
292292+> You made it to the end! Thanks for reading. I hope you enjoy using `den`. It is feature-complete and unlikely to change.
512293513294</details>
514295515515-### Contributing.
296296+### Contributing
516297517517-Yes, please, anything!. From fixing my bad english and typos, to sharing your ideas and experience with `den` in our discussion forums. Feel free to participate and be nice with everyone.
298298+Contributions are welcome! Feel free to fix typos, improve documentation, or share ideas in our [discussions](https://github.com/vic/den/discussions).
518299519519-PRs are more than welcome, the CI runs some checks that verify nothing (known) is broken. Any new feature needs a test in `_example/ci.nix`.
300300+All PRs are checked against the CI. New features should include a test in `_example/ci.nix`.
520301521521-If you need to run the test suite locally:
302302+To run tests locally:
522303523304```console
524524-$ nix flake check ./checkmate --override-input target .
525525-$ cd templates/default && nix flake check --override-input den ../..
305305+nix flake check ./checkmate --override-input target .
306306+cd templates/default && nix flake check --override-input den ../..
526307```
···11+# This enables den's angle brackets opt-in feature.
22+# Remove this file to opt-out.
33+#
44+# When den.lib.__findFile is in scope, you can do:
55+#
66+# <pro/foo/bar> and it will resolve to:
77+# den.aspects.pro.provides.foo.provides.bar
88+#
99+# <pro/foo.includes> resolves to:
1010+# den.aspects.pro.provides.foo.includes
1111+#
1212+# <den/import-tree/home> resolves to:
1313+# den.provides.import-tree.provides.home
1414+#
1515+# <den.default> resolves to den.default
1616+#
1717+# When the vix remote namespace is enabled
1818+# <vix/foo> resolves to: den.ful.vix.provides.foo
1919+#
2020+# Usage:
2121+#
2222+# Bring `__findFile` into scope from module args:
2323+#
2424+# { __findFile, ... }:
2525+# den.default.includes = [ <den/home-manager> ];
2626+# }
2727+#
2828+# IF you are using nixf-diagnose, it will complain
2929+# about __findFile not being used, trick it with:
3030+#
3131+# { __findFile ? __findFile, ... }
3232+#
3333+{ den, ... }:
3434+{
3535+ _module.args.__findFile = den.lib.__findFile;
3636+}
···44 # private aspects can be let-bindings
55 # more re-usable ones are better defined inside the `pro` namespace.
66 host-contrib-to-user =
77- # { host, user }: # uncomment if needed
88- {
99- homeManager.programs.vim.enable = true;
1010- };
77+ { fromHost, toUser }:
88+ if fromHost.name == "bones" || toUser.name == "fido" then
99+ {
1010+ homeManager.programs.vim.enable = true;
1111+ }
1212+ else
1313+ { };
1114in
1215{
1313- den.aspects.bones.provides.user.includes = [
1414- # add other aspects of yours that use host, user
1515- # to conditionally add behaviour.
1616+ den.default.includes = [
1617 host-contrib-to-user
1718 ];
1819}
+62-19
templates/default/modules/_profile/namespace.nix
···11-# creates a `pro` aspect namespace.
11+# This module creates an aspect namespace.
22+#
33+# Just add the following import:
44+#
55+# # define local namespace. enable flake output.
66+# imports = [ (inputs.den.namespace "vix" true) ];
77+#
88+# # you can use remote namespaces and they will merge
99+# imports = [ (inputs.den.namespace "vix" inputs.dendrix) ];
1010+#
1111+# Internally, a namespace is just a `provides` branch:
1212+#
1313+# # den.ful is the social-convention for namespaces.
1414+# den.ful.<name>
1515+#
1616+# Having an aspect namespace is not required but helps a lot
1717+# with organization and conventient access to your aspects.
1818+#
1919+# The following examples use the `vix` namespace,
2020+# inspired by github:vic/vix own namespace pattern.
2121+#
2222+# By using an aspect namespace you can:
2323+#
2424+# - Directly write to aspects in your namespace.
2525+#
2626+# {
2727+# vix.gaming.nixos = ...;
2828+#
2929+# # instead of:
3030+# # den.ful.vix.gaming.nixos = ...;
3131+# }
3232+#
3333+# - Directly read aspects from your namespace.
3434+#
3535+# # Access the namespace from module args
3636+# { vix, ... }:
3737+# {
3838+# den.default.includes = [ vix.security ];
3939+#
4040+# # instead of:
4141+# # den.default.includes = [ den.ful.vix.security ];
4242+# }
243#
33-# this is not required but helps you avoid writing
44-# `den.aspects.profile.provides` all the time
55-# and use your namespace instead.
66-# This is inspired by vic's vix namespae.
4444+# - Share and re-use aspects between Dendritic flakes
745#
88-# User TODO: rename `pro` to something else on your project.
99-# The namespace is accesible via the module args
1010-# and also writable as an option at module root.
4646+# # Aspects opt-in exposed as flake.denful.<name>
4747+# { imports = [( inputs.den.namespace "vix" true)] }
1148#
1212-{ config, lib, ... }:
4949+# # Many flakes can expose to the same namespace and we
5050+# # can merge them, accessing aspects in a uniform way.
5151+# { imports = [( inputs.den.namespace "vix" inputs.dendrix )] }
5252+#
5353+# - Use angle-brackets to access deeply nested trees
5454+#
5555+# # Be sure to read _profile/den-brackets.nix
5656+# { __findFile, ... }:
5757+# den.aspects.my-laptop.includes = [ <vix/gaming/retro> ];
5858+# }
5959+#
6060+#
6161+# You can of course choose to not have any of the above.
6262+# USER TODO: Remove this file for not using a namespace.
6363+# USER TODO: Replace `pro` and update other files using it.
6464+{ inputs, ... }:
1365{
1414- # create a sub-tree of provided aspects.
1515- # the `profile` name is generic, use your own
1616- # as deep as you like, only that it ends in a provides tree.
1717- den.aspects.profile.provides = { };
1818- # setup for write
1919- imports = [ (lib.mkAliasOptionModule [ "pro" ] [ "den" "aspects" "profile" "provides" ]) ];
2020- # setup for read
2121- _module.args.pro = config.den.aspects.profile.provides;
2222- # optionally expose outside your flake.
2323- # flake.pro = config.den.aspects.profile.provides;
6666+ imports = [ (inputs.den.namespace "pro" true) ];
2467}
+9-52
templates/default/modules/_profile/profiles.nix
···11# Profiles are just aspects whose only job is to include other aspects
22# based on the properties (context) of the host/user they are included in.
33-{ pro, ... }:
33+{ pro, den, ... }:
44{
5566 # install profiles as parametric aspects on all hosts/users
77 den.default.includes = [
88- pro.by-host
99- pro.by-user
88+ pro.profiles
109 ];
11101212- # `by-host { host }`
1313- #
1414- # den automatically includes `den.aspects.${host.name}`, besides that
1515- # this profile adds the following aspects if they exist:
1616- #
1717- # - `den.aspects.profile._.${system}` eg, an aspect per host hardware platform.
1818- #
1919- # since the `host` type is a freeform (see types.nix) you can add
2020- # custom attributes to your hosts and use them to dispatch for
2121- # common aspects. eg, by host network, etc.
2222- #
2323- # Also, remember that aspects can form a tree structure by using their
2424- # `provides` attribute, not all aspects need to exist at same level.
2525- pro.by-host =
2626- { host, ... }:
2727- {
2828- includes = [
2929- (pro.${host.system} or { })
3030- ];
3131- };
3232-3333- # `by-user { host, user }`
3434- #
3535- # den automatically includes `den.aspects.${user.name}`.
3636- # a user can contribute modules to the host is part of, and also
3737- # define its own home-level configs.
3838- #
3939- # - `den.aspects.<host>._.user { host, user }`: included on each user of a host.
4040- # - `den.aspects.<user>._.host { host, user }`: included on each host where a user exists.
4141- #
4242- # this profile adds the following aspects if they exist:
4343- #
4444- # - `den.aspects.profile._.single-user-is-admin { host, user }`
4545- #
4646- # Since both host and user types are freeforms, you might add custom attributes
4747- # to them and your parametric aspects can use those attributes to conditionally add
4848- # features into the host or user level.
4949- pro.by-user =
5050- { host, user }:
5151- {
5252- includes =
5353- let
5454- apply = f: f { inherit host user; };
5555- in
5656- map apply [
5757- pro.single-user-is-admin
5858- # TODO: add
5959- ];
6060- };
1111+ pro.profiles = {
1212+ __functor = den.lib.parametric true;
1313+ includes = [
1414+ ({ host }: pro.${host.system} or { })
1515+ # add other routes according to context.
1616+ ];
1717+ };
61186219}
···11# An aspect that contributes to any operating system where fido is a user.
22-{ ... }:
22+# hooks itself into any host.
33+{ pro, ... }:
34let
44- # private aspects can be in variables
55- # more re-usable ones are better defined inside the `pro` namespace.
66- user-contrib-to-host =
77- # { user, host }: # uncomment if needed
88- {
99- nixos = { };
1010- darwin = { };
1111- };
55+ fido-at-host =
66+ { fromUser, toHost }: if fromUser.name != "fido" then { } else pro.fido._.${toHost.name};
127in
138{
1414- den.aspects.fido.provides.host.includes = [
1515- # add other aspects of yours that use host, user
1616- # to conditionally add behaviour.
1717- user-contrib-to-host
99+ den.default.includes = [
1010+ fido-at-host
1811 ];
1212+1313+ # fido on bones host.
1414+ pro.fido._.bones.nixos = { };
1915}
+1-1
templates/default/modules/den.nix
···88 (inputs.import-tree ./_example)
991010 # The _profile directory contains a minimal profile-based layout.
1111- # (inputs.import-tree ./_profile) # Disabled, working on #45
1111+ (inputs.import-tree ./_profile)
1212 ];
1313}