···294294295295---
296296297297-## 5. Bidirectional Configuration (Critical Advanced Feature)
298298-299299-Den supports two patterns for Host↔User bidirectional configuration.
300300-Read `https://den.oeiuwq.com/guides/bidirectional` and apply these rules:
301301-302302-### 5.1 Built-in Bidirectionality (`den._.bidirectional`)
303303-304304-This makes a HOST contribute configuration TO its users' home environments.
305305-Enable per-user or globally:
306306-307307-```nix
308308-# Only for specific user
309309-den.aspects.alice.includes = [ den._.bidirectional ];
310310-311311-# For ALL users (recommended for host-provides-home-env patterns)
312312-den.ctx.user.includes = [ den._.bidirectional ];
313313-```
314314-315315-**How it works:** When bidirectionality is enabled, the user pipeline calls
316316-`igloo.includes` TWICE: once with `{host}` (for host-only config) and once
317317-with `{host, user}` (so the host can contribute to THIS specific user's home).
318318-319319-**Mandatory: use take guards** in `igloo.includes` to handle dual invocation:
320320-321321-```nix
322322-# In igloo.includes — only runs for host-level context
323323-(den.lib.take.exactly ({ host }: { nixos.networking.hostName = host.hostName; }))
297297+## 5. Mutual Host<->User Configuration
324298325325-# In igloo.includes — only runs when user is present (host→user home contribution)
326326-(den.lib.take.atLeast ({ host, user }: { homeManager.programs.vim.enable = true; }))
327327-```
328328-329329-This pattern is ideal when: a host wants to provide a common home environment
330330-to ALL of its users (e.g., all users on `igloo` get `vim` configured in their home).
299299+Den supports a patterns for Host↔User mutual configuration.
300300+Read `https://den.oeiuwq.com/guides/mutual` and apply these rules:
331301332332-### 5.2 Explicit Mutual Provider (`den._.mutual-provider`)
302302+### 5.1 Explicit Mutual Provider (`den._.mutual-provider`)
333303334334-For EXPLICIT named host↔user pairings. More verbose, more precise:
304304+For EXPLICIT named host↔user pairings.
335305336306```nix
337307# Enable for everything
···346316den.aspects.tux.provides.igloo = { host, ... }: {
347317 nixos.programs.nh.enable = true;
348318};
349349-```
350319351351-### 5.3 When to Use Which
320320+# Host provides to all users
321321+den.aspects.igloo.provides.to-users = {};
352322353353-| Pattern | Use when |
354354-|---------|----------|
355355-| Built-in bidirectionality | Host provides common env to ALL its users |
356356-| `mutual-provider` | Explicit, named host↔user pair configurations |
357357-| User `nixos` class | User always contributes to any host it's on |
358358-| Host `homeManager` class | Host always contributes to all user homes |
323323+# User provides to all hosts
324324+den.aspects.tux.provides.to-hosts = {};
325325+```
359326360327---
361328···393360- `unfree [...]` — `nixpkgs.config.allowUnfreePredicate` for named packages
394361- `tty-autologin "user"` — `services.getty.autologinUser`
395362- `mutual-provider` — explicit named host↔user cross-config
396396-- `bidirectional` — host contributes to user homes in pipeline
397363- `forward` — creates custom Nix classes (see §7)
398364- `import-tree` — auto-imports legacy non-dendritic `.nix` directories
399365- `inputs'` — flake-parts system-qualified inputs
···519485};
520486```
521487522522-### 8.3 Host contributing home config to users (bidirectional)
488488+### 8.3 Host contributing home config to users
523489524490```nix
525491# Host igloo provides vim to ALL its users' home environments
526526-den.aspects.igloo = {
492492+den.aspects.igloo.provides.to-users = {
527493 homeManager.programs.vim.enable = true; # goes to ALL users on igloo
528494};
529529-den.ctx.user.includes = [ den._.bidirectional ];
495495+den.ctx.user.includes = [ den._.mutual-provider ];
530496```
531497532498### 8.4 Multiple home environments per user
···711677- [ ] `den.schema.*` defines shared options instead of repeating per-host
712678- [ ] `den.default` sets `stateVersion` for all classes
713679- [ ] All batteries used instead of manual equivalents
714714-- [ ] `bidirectional` or `mutual-provider` used for host↔user cross-config
715715-- [ ] `take.exactly`/`take.atLeast` guards on bidirectional aspects
680680+- [ ] `mutual-provider` used for host↔user cross-config
681681+- [ ] `perHost`/`perUser`/`take.exactly`/`take.atLeast` guards on mutual aspects
716682- [ ] One file per concern in `modules/aspects/`
717683- [ ] Non host/user specific re-usable aspects in `modules/community/<namespace>/`
718684- [ ] No monolithic `configuration.nix` style files
···729695730696All source truth lives at:
731697- `https://den.oeiuwq.com` — official documentation
732732-- `https://den.oeiuwq.com/guides/bidirectional` — bidirectional guide, Bidirectionality is an advanced feature not recommended.
698698+- `https://den.oeiuwq.com/guides/mutual` — Mutual Host<->User config
733699- `https://github.com/vic/den/tree/main/templates/ci/modules/features/` — executable feature tests (best learning resource)
734700- `https://github.com/vic/den/tree/main/modules/aspects/provides/` — all batteries source
735701- `https://github.com/vic/flake-aspects` — underlying aspect library
···772738Adding bluetooth to a new host is one line: include the aspect.
773739Removing it is deleting that line.
774740775775-```
776776-777777-**File:** docs/src/content/docs/guides/bidirectional.mdx (L60-153)
778778-```text
779779-## What Bidirectionality means
780780-781781-__Bidirectionality__ means that not only a User contributes
782782-configuration to a Host, but **also** that a Host contributes
783783-configurations to a User.
784784-785785-This is useful when the Host wishes to provide a
786786-commmon home environment for its users.
787787-788788-## `den.provides.bidirectional`
789789-790790-Bidirectionality is enabled __per-user__ or for _all_ of them.
791791-792792-```nix
793793-# only tux takes configurations from its hosts
794794-den.aspects.tux.includes = [ den._.bidirectional ];
795795-796796-# for ALL users
797797-den.ctx.user.includes = [ den._.bidirectional ];
798798-```
799799-800800-When Bidirectionality is enabled, the interaction looks like this:
801801-802802-```mermaid
803803-sequenceDiagram
804804- participant Den
805805- participant host as den.ctx.host
806806- participant user as den.ctx.user
807807- participant igloo as den.aspects.igloo
808808- participant tux as den.aspects.tux
809809-810810- Den ->> host : {host = igloo}
811811-812812- host ->> igloo : request nixos class
813813- igloo -->> igloo : each igloo.includes takes { host }
814814- igloo -->> host : { nixos = ... } owned and parametric results
815815-816816- host ->> user : fan-outs for each user: { host, user }
817817-818818- user ->> tux : request nixos class
819819-820820- tux ->> igloo : request home class
821821- igloo -->> igloo : each igloo.includes takes { host, user }
822822- igloo -->> tux : { hjem = ... } owned and parametric results
823823-824824- tux -->> tux : home classes forwarded as nixos class
825825-826826- tux -->> tux : each tux.includes takes { host, user }
827827- tux -->> user : { nixos = ... } owned and parametric results
828828-829829- user -->> host : { nixos = ... } all user contributions
830830-831831- host -->> Den : complete nixos module for lib.nixosSystem
832832-833833-```
834834-835835-Crucial points here are `igloo.includes takes { host }` and `igloo.includes takes { host, user }`.
836836-837837-Because the list of aspects at `igloo.includes` get invoked twice, with different contexts,
838838-functions at `igloo.includes` must take care of the following:
839839-840840-```nix
841841-# use den.lib.take.exactly to avoid being called with `{host, user}`
842842-take.exactly ({ host }: ...)
843843-844844-# use den.lib.take.atLeast to avoid being called with `{host}`
845845-take.atLeast ({ host, user }: ...)
846846-```
847847-848848-Read the documentation at [`context/user.nix`](https://github.com/vic/den/blob/main/modules/context/user.nix) for all the details.
849849-850850-## `den.provides.mutual-provider`
851851-852852-An alternative to bidirectionality is [`den.provides.mutual-provider`](https://github.com/vic/den/blob/main/modules/aspects/provides/mutual-provider.nix).
853853-854854-This battery is more explicit, since it requires an explicit `.provides.` relationship between users and hosts.
855855-856856-```nix
857857-# Host provides to a particular user
858858-den.aspects.igloo.provides.tux = {
859859- hjem = ...;
860860-};
861861-862862-# User provides to a particular host
863863-den.aspects.tux.provides.igloo = {
864864- nixos = ...;
865865-};
866866-```
867867-868868-To enable it for both users and hosts, include at default:
869869-870870-```nix
871871-den.default.includes = [ den._.mutual-provider ];
872872-```
873873-```
874874-875741**File:** docs/src/content/docs/guides/configure-aspects.mdx (L127-187)
876876-```text
8777428787431. Static (plain attribute set): `{ nixos.foo = ...; }`
8797442. Static (flake-aspects' leaf): `{class, aspect-chain}: { ${class}.foo = ...; }`
···1032897den.default.includes = [ den._.mutual-provider ];
1033898```
103489910351035-This is not the same as the built-in bidirectionality:
10361036-1037900```nix
1038901# contributes to ALL users of this host
10391039-den.aspects.my-host.homeManager = { ... }
902902+den.aspects.my-host.provides.to-users.homeManager = { ... }
10409031041904# contributes to ALL hosts of where my-user exist
1042905den.aspects.my-user.nixos = { ... }
1043906```
10441044-10451045-The difference is that this allows you to wire bidirectionality between
10461046-explictly-named hosts/users pairs.
10479071048908A user providing config TO the host:
1049909···23552215 schema-base-modules.nix # den.schema modules
23562216 special-args-custom-instantiate.nix # custom instantiation
23572217 top-level-parametric.nix # top-level context aspects
23582358- user-host-bidirectional-config.nix # bidirectional providers
22182218+ user-host-mutual-config.nix # mutual providers
23592219 batteries/
23602220 define-user.nix # define-user battery
23612221 flake-parts.nix # inputs' and self'
···2398225823992259| Test File | What It Tests |
24002260|-----------|---------------|
24012401-| [user-host-bidirectional-config.nix](https://github.com/vic/den/blob/main/templates/ci/modules/features/user-host-bidirectional-config.nix) | Host→user and user→host config flow |
22612261+| [user-host-mutual-config.nix](https://github.com/vic/den/blob/main/templates/ci/modules/features/user-host-mutual-config.nix) | Host→user and user→host config flow |
24022262| [context/cross-provider.nix](https://github.com/vic/den/blob/main/templates/ci/modules/features/context/cross-provider.nix) | Source providing config to target context |
24032263| [context/named-provider.nix](https://github.com/vic/den/blob/main/templates/ci/modules/features/context/named-provider.nix) | Self-named provider mechanism |
24042264