···42424343### [Community](https://den.oeiuwq.com/community/)
44444545-4646-4745</div>
4846</td>
4947<td>
···120118121119Den `main` always requires flake-aspects `main`. Same for `latest` versions.
122120123123-124121```nix
125122# Bleeding edge Den
126123{
···132129`main` branch follows development, this is where PRs are merged, it is stable in the sense
133130that every PR checks CI. However, some PR might introduce changes that require you being
134131aware of what is happening in Den. For people tracking development, we have announcements
135135-tagged `heads-up` whenever this happens.
136136-137137-132132+tagged `heads-up` whenever this happens.
138133139134```nix
140140-# Released Den - no longer gets updates until next release
135135+# Released Den - no longer gets updates until next release
141136{
142137 inputs.den.url = "github:vic/den/latest";
143138 inputs.flake-aspects.url = "github:vic/flake-aspects/latest";
···153148For other than main and latest versions, each release-notes documents the particular
154149flake-aspects version needed by Den. This is because flake-aspects can be used independently of Den,
155150and it does not follows Den version numbers because it is not as fast-paced as Den.
156156-157151158152## Code example (OS configuration domain)
159153
···11---
22-title: Host<-> User Bidirectional Configurations
33-description: How to configure bidirectional behavior in Den and how it differs from mutual-provider.
22+title: Host<->User Mutual Configurations
33+description: How to configure bidirectional behavior in Den.
44---
5566import { Aside } from '@astrojs/starlight/components';
···1212[`mutual-provider.nix`](https://github.com/vic/den/blob/main/modules/aspects/provides/mutual-provider.nix)
1313</Aside>
14141515+## What Mutual Configurations Means
15161616-## Normal, non-bidirectional OS configuration
1717+__Bidirectionality__ means that not only a User contributes
1818+configuration to a Host, but **also** that a Host contributes
1919+configurations to a User.
2020+2121+This is useful when you wish for a Host to provide a common
2222+_home environment_ for all its users, or for a User to require
2323+common _os environment_ everywhere it is defined.
2424+2525+There are at least two (built-in) ways to achieve this in Den.
2626+The `den._.bidirectional` and `den._.mutual-provider`, the
2727+first one was extracted from den-core and the second started
2828+life as an **aspect routing** example, but made it to become
2929+proper battery itself and even safer to use.
3030+3131+3232+## Default, *unidirectional* OS configuration
17331834Den framework is built around **context pipeline** transformations.
1935In order to create a full OS configuration, everything starts with a host definition:
···5773the host itself and from each of its user.
587459756060-## What Bidirectionality means
6161-6262-__Bidirectionality__ means that not only a User contributes
6363-configuration to a Host, but **also** that a Host contributes
6464-configurations to a User.
6565-6666-This is useful when the Host wishes to provide a
6767-commmon home environment for its users.
68766977## `den.provides.bidirectional`
7078···132140133141An alternative to bidirectionality is [`den.provides.mutual-provider`](https://github.com/vic/den/blob/main/modules/aspects/provides/mutual-provider.nix).
134142135135-This battery is more explicit, since it requires an explicit `.provides.` relationship between users and hosts.
143143+This battery is safer, instead of using the host aspect directly, it requires you to define other named aspects under `.provides.` to create an explicit relationship between users and hosts.
136144137145```nix
138138-# Host provides to a particular user
139139-den.aspects.igloo.provides.tux = {
140140- hjem = ...;
146146+den.default.includes = [ den._.mutual-provider ];
147147+148148+# user aspect provides to specific host or to all where it lives
149149+den.aspects.tux = {
150150+ provides.igloo.nixos.programs.emacs.enable = true;
151151+ provides.to-hosts = { host, ... }: {
152152+ nixos.programs.nh.enable = host.name == "igloo";
153153+ };
141154};
142155143143-# User provides to a particular host
144144-den.aspects.tux.provides.igloo = {
145145- nixos = ...;
156156+# host aspect provides to specific user or to all its users
157157+den.aspects.igloo = {
158158+ provides.alice.homeManager.programs.vim.enable = true;
159159+ provides.to-users = { user, ... }: {
160160+ homeManager.programs.helix.enable = user.name == "alice";
161161+ };
146162};
147163```
148148-149149-To enable it for both users and hosts, include at default:
150150-151151-```nix
152152-den.default.includes = [ den._.mutual-provider ];
153153-```
+37-30
modules/aspects/provides/mutual-provider.nix
···11# See usage at: templates/example/modules/aspects/{defaults.nix,alice.nix,igloo.nix}
22{ den, ... }:
33let
44+ inherit (den.lib) take parametric;
55+46 description = ''
55- Allows specifically-chosen hosts and users to contribute configuration **to
66- each other** through `provides`.
77-88- This is not the same as the built-in bidirectionality:
99-1010- # contributes to ALL users of this host
1111- den.aspects.my-host.homeManager = { ... }
1212-1313- # contributes to ALL hosts of where my-user exist
1414- den.aspects.my-user.nixos = { ... }
1515-1616- The difference is that this allows you to wire bidirectionality between
1717- explictly-named hosts/users pairs (see the usage below).
77+ Allows hosts and users to contribute configuration **to each other**
88+ through `provides`.
1891910 This battery implements an aspect "routing" pattern.
20111212+ This is not the same as `den._.bidirectional` battery, but provides a
1313+ **safer** alternative to `den._.bidirectional`.
1414+ The reason is that this battery does not re-invoke the `host-aspect.includes`,
1515+ instead it relies on you defining provides.
1616+2117 Unlike `den.default` which is `parametric.atLeast` we use
2218 `parametric.fixedTo` here, which help us propagate an already computed
2319 context to all includes.
24202521 This battery, when installed in a `parametric.atLeast` will just forward
2626- the same context. The `mutual` helper returns an static configuration
2222+ the same context. The `find-mutual` helper returns an static configuration
2723 which is ignored by parametric aspects, thus allowing non-existing
2824 aspects to be just ignored.
29253030- Be sure to read the Host Context section on:
3131- https://den.oeiuwq.com/explanation/context-pipeline
2626+ Be sure to read diagrams for the Host context pipeline:
2727+ https://den.oeiuwq.com/guides/bidirectional
32283329 ## Usage
34303531 den.hosts.x86_64-linux.igloo.users.tux = { };
3632 den.default.includes = [ den._.mutual-provider ];
37333838- A user providing config TO the host:
3939-3434+ # user aspect provides to specific host or to all where it lives
4035 den.aspects.tux = {
4141- provides.igloo = { host, ... }: {
3636+ provides.igloo.nixos.programs.emacs.enable = true;
3737+ provides.to-hosts = { host, ... }: {
4238 nixos.programs.nh.enable = host.name == "igloo";
4339 };
4440 };
45414646- A host providing config TO the user:
4747-4242+ # host aspect provides to specific user or to all its users
4843 den.aspects.igloo = {
4949- provides.tux = { user, ... }: {
4444+ provides.alice.homeManager.programs.vim.enable = true;
4545+ provides.to-users = { user, ... }: {
5046 homeManager.programs.helix.enable = user.name == "alice";
5147 };
5248 };
5349 '';
54505555- mutual = from: to: den.aspects.${from.aspect}._.${to.aspect} or { };
5656-in
5757-{
5858- den.provides.mutual-provider =
5151+ find-mutual = from: to: den.aspects.${from.aspect}._.${to.aspect} or { };
5252+ user-to-hosts = { host, user }: den.aspects.${user.aspect}._.to-hosts or { };
5353+ host-to-users = { host, user }: den.aspects.${host.aspect}._.to-users or { };
5454+5555+ named-mutuals =
5956 { host, user }@ctx:
6060- den.lib.parametric.fixedTo ctx {
6161- inherit description;
5757+ parametric.fixedTo ctx {
6258 includes = [
6363- (mutual user host)
6464- (mutual host user)
5959+ (find-mutual host user)
6060+ (find-mutual user host)
6561 ];
6662 };
6363+6464+in
6565+{
6666+ den.provides.mutual-provider = parametric.exactly {
6767+ inherit description;
6868+ includes = [
6969+ named-mutuals
7070+ host-to-users
7171+ user-to-hosts
7272+ ];
7373+ };
6774}