refactor(modules): organize module tree #72

Merged
alexion merged 1 commits from refactor/organize-modules into main 2026-08-28 08:47:26 -04:00
41 changed files with 133 additions and 140 deletions

View File

@@ -18,11 +18,11 @@ One flake builds every machine I own.
### Desktop
- When adding a graphical application, add a `window-rewrite` icon mapping in `modules/desktop/waybar.nix`.
- When adding a graphical application, add a `window-rewrite` icon mapping in `modules/desktop/session/waybar.nix`.
The workspace indicator uses this mapping to show an application icon instead of the generic default glyph.
Match the mapping on the window class.
Run `hyprctl clients -j | jq -r '.[].class' | sort -u` to list classes in the running session.
- Set Hyprland session environment variables in `modules/desktop/hyprland/hyprland.nix` with `env = KEY,VALUE`.
- Set Hyprland session environment variables in `modules/desktop/session/hyprland/default.nix` with `env = KEY,VALUE`.
`home.sessionVariables` do **not** reach the Hyprland session because UWSM does not source `hm-session-vars.sh`.
Source cursor values from `config.stylix.cursor`.
Set `XCURSOR_*` and `HYPRCURSOR_*` to the same theme for Bibata.

View File

@@ -171,7 +171,7 @@ Then populate that file, which needs no existing identity because encrypting onl
$ nix run nixpkgs#sops -- secrets/newhost.yaml
```
A host with `modules.ssh.enable` expects one entry per key type, named `ssh-host-<type>-key`, each holding a private key generated with `ssh-keygen -t <type> -N "" -f /tmp/<type>`.
A host with `modules.network.ssh.enable` expects one entry per key type, named `ssh-host-<type>-key`, each holding a private key generated with `ssh-keygen -t <type> -N "" -f /tmp/<type>`.
The build fails at evaluation if a declared secret is absent from the file, so a host that enables the daemon without these will not install.
Commit the matching public halves beside the host's configuration in plaintext, since publishing them is their purpose.

View File

@@ -36,9 +36,9 @@
# So setup can be driven over the network.
# The matching host public keys sit beside this file in plaintext, since
# publishing them is their purpose.
modules.ssh.enable = true;
modules.ssh.hostKeys.sopsFile = ../../secrets/neogaia.yaml;
modules.ssh.userKey.sopsFile = ../../secrets/neogaia.yaml;
modules.network.ssh.enable = true;
modules.network.ssh.hostKeys.sopsFile = ../../secrets/neogaia.yaml;
modules.network.ssh.userKey.sopsFile = ../../secrets/neogaia.yaml;
# The walking-skeleton guest, enabled like any module: proves the guest path
# end to end through this host's `nix flake check`.
@@ -60,13 +60,13 @@
tasksMax = 512;
};
modules.agents.herdr.enable = true;
modules.shell.herdr.enable = true;
modules.agents.tools.gitea-axi.enable = true;
modules.agents.pi.enable = true;
modules.desktop.enable = true;
modules.desktop.obsidian.enable = true;
modules.desktop.steam.enable = true;
modules.desktop.apps.obsidian.enable = true;
modules.desktop.apps.steam.enable = true;
time.timeZone = "America/New_York";
i18n.defaultLocale = "en_GB.UTF-8";

View File

@@ -62,7 +62,7 @@
};
networking.useDHCP = false;
modules.network.vlans = [ 20 ];
modules.network.vlans.ids = [ 20 ];
boot.zfs.forceImportRoot = false;
@@ -74,11 +74,10 @@
registry.address.pikachu.self = "10.23.10.102";
modules.ssh.enable = true;
modules.ssh.hostKeys.sopsFile = ../../secrets/pikachu.yaml;
modules.ssh.userKey.sopsFile = ../../secrets/pikachu.yaml;
modules.network.ssh.enable = true;
modules.network.ssh.hostKeys.sopsFile = ../../secrets/pikachu.yaml;
modules.network.ssh.userKey.sopsFile = ../../secrets/pikachu.yaml;
modules.git.enable = true;
guests.actualbudget = {
enable = true;
vlan = 20;

View File

@@ -108,7 +108,7 @@ let
The tagged VLAN this guest lives on. The guest attaches to its host's
`br-vlan<id>` bridge for that VLAN. Left null, the guest keeps a
private network with no bridge attachment. The id must be one of the
host's `modules.network.vlans`.
host's `modules.network.vlans.ids`.
'';
};
mac = lib.mkOption {
@@ -301,9 +301,9 @@ let
'';
}
{
assertion = !networked || lib.elem cfg.vlan config.modules.network.vlans;
assertion = !networked || lib.elem cfg.vlan config.modules.network.vlans.ids;
message = ''
guests.${name}.vlan = ${toString cfg.vlan} is not among its host's modules.network.vlans (${lib.concatMapStringsSep ", " toString config.modules.network.vlans}). Declare the VLAN on the host or correct the guest's placement.
guests.${name}.vlan = ${toString cfg.vlan} is not among its host's modules.network.vlans.ids (${lib.concatMapStringsSep ", " toString config.modules.network.vlans.ids}). Declare the VLAN on the host or correct the guest's placement.
'';
}
];

View File

@@ -116,11 +116,11 @@ in
cleanup = "sudo nix-collect-garbage -d";
};
modules.fish.enable = lib.mkDefault true;
modules.fish.defaultShell = lib.mkDefault true;
modules.tmux.enable = lib.mkDefault true;
modules.nvim.enable = lib.mkDefault true;
modules.git.enable = lib.mkDefault true;
modules.direnv.enable = lib.mkDefault true;
modules.shell.fish.enable = lib.mkDefault true;
modules.shell.fish.defaultShell = lib.mkDefault true;
modules.shell.tmux.enable = lib.mkDefault true;
modules.shell.nvim.enable = lib.mkDefault true;
modules.shell.git.enable = lib.mkDefault true;
modules.shell.direnv.enable = lib.mkDefault true;
};
}

View File

@@ -6,11 +6,11 @@
}:
# Alacritty as the desktop terminal.
let
cfg = config.modules.desktop.terminal;
cfg = config.modules.desktop.apps.alacritty;
user = config.user.name;
in
{
options.modules.desktop.terminal.enable = lib.mkEnableOption "Alacritty as the desktop terminal";
options.modules.desktop.apps.alacritty.enable = lib.mkEnableOption "Alacritty as the desktop terminal";
config = lib.mkIf cfg.enable {
home-manager.users.${user}.home.packages = [ pkgs.alacritty ];

View File

@@ -7,12 +7,12 @@
}:
# Firefox as the desktop browser: stock mainline, hardened and de-monetized by policy.
let
cfg = config.modules.desktop.firefox;
cfg = config.modules.desktop.apps.firefox;
user = config.user.name;
firefoxAddons = inputs.firefox-addons.packages.${pkgs.stdenv.hostPlatform.system};
in
{
options.modules.desktop.firefox.enable = lib.mkEnableOption "Firefox as the desktop browser";
options.modules.desktop.apps.firefox.enable = lib.mkEnableOption "Firefox as the desktop browser";
config = lib.mkIf cfg.enable {
home-manager.users.${user} = hm: {

View File

@@ -6,11 +6,11 @@
}:
# Obsidian as the desktop note-taking vault.
let
cfg = config.modules.desktop.obsidian;
cfg = config.modules.desktop.apps.obsidian;
user = config.user.name;
in
{
options.modules.desktop.obsidian.enable = lib.mkEnableOption "Obsidian as the desktop note-taking vault";
options.modules.desktop.apps.obsidian.enable = lib.mkEnableOption "Obsidian as the desktop note-taking vault";
config = lib.mkIf cfg.enable {
home-manager.users.${user}.home.packages = [ pkgs.obsidian ];

View File

@@ -6,10 +6,10 @@
}:
# Steam game launcher and runtime integration.
let
cfg = config.modules.desktop.steam;
cfg = config.modules.desktop.apps.steam;
in
{
options.modules.desktop.steam.enable = lib.mkEnableOption "Steam game launcher";
options.modules.desktop.apps.steam.enable = lib.mkEnableOption "Steam game launcher";
config = lib.mkIf cfg.enable {
programs.steam = {

View File

@@ -0,0 +1,30 @@
{ config, lib, ... }:
# The desktop aggregator: one flag brings up the whole graphical session.
let
cfg = config.modules.desktop;
in
{
options.modules.desktop.enable = lib.mkEnableOption "the keyboard-driven Hyprland desktop";
# Each piece is turned on at default priority, so a host can still override
# any one of them while the single flag above enables the whole desktop.
config = lib.mkIf cfg.enable {
modules.desktop.apps.alacritty.enable = lib.mkDefault true;
modules.desktop.apps.firefox.enable = lib.mkDefault true;
modules.desktop.session.hyprland.enable = lib.mkDefault true;
modules.desktop.session.hyprland.hypridle.enable = lib.mkDefault true;
modules.desktop.session.hyprland.hyprlock.enable = lib.mkDefault true;
modules.desktop.session.login.enable = lib.mkDefault true;
modules.desktop.session.mako.enable = lib.mkDefault true;
modules.desktop.session.portals.enable = lib.mkDefault true;
modules.desktop.session.rofi.enable = lib.mkDefault true;
modules.desktop.session.waybar.enable = lib.mkDefault true;
modules.desktop.utilities.audio.enable = lib.mkDefault true;
modules.desktop.utilities.clipboard.enable = lib.mkDefault true;
modules.desktop.utilities.osd.enable = lib.mkDefault true;
modules.desktop.utilities.recording.enable = lib.mkDefault true;
modules.desktop.utilities.screenshot.enable = lib.mkDefault true;
modules.desktop.utilities.theming.enable = lib.mkDefault true;
modules.desktop.utilities.userdirs.enable = lib.mkDefault true;
};
}

View File

@@ -1,30 +0,0 @@
{ config, lib, ... }:
# The desktop aggregator: one flag brings up the whole graphical session.
let
cfg = config.modules.desktop;
in
{
options.modules.desktop.enable = lib.mkEnableOption "the keyboard-driven Hyprland desktop";
# Each piece is turned on at default priority, so a host can still override
# any one of them while the single flag above enables the whole desktop.
config = lib.mkIf cfg.enable {
modules.desktop.clipboard.enable = lib.mkDefault true;
modules.desktop.firefox.enable = lib.mkDefault true;
modules.desktop.hyprland.enable = lib.mkDefault true;
modules.desktop.hyprland.hyprlock.enable = lib.mkDefault true;
modules.desktop.hyprland.hypridle.enable = lib.mkDefault true;
modules.desktop.login.enable = lib.mkDefault true;
modules.desktop.mako.enable = lib.mkDefault true;
modules.desktop.portals.enable = lib.mkDefault true;
modules.desktop.recording.enable = lib.mkDefault true;
modules.desktop.rofi.enable = lib.mkDefault true;
modules.desktop.screenshot.enable = lib.mkDefault true;
modules.desktop.terminal.enable = lib.mkDefault true;
modules.desktop.userdirs.enable = lib.mkDefault true;
modules.desktop.theming.enable = lib.mkDefault true;
modules.desktop.waybar.enable = lib.mkDefault true;
modules.desktop.audio.enable = lib.mkDefault true;
modules.desktop.osd.enable = lib.mkDefault true;
};
}

View File

@@ -6,7 +6,7 @@
}:
# The Hyprland compositor.
let
cfg = config.modules.desktop.hyprland;
cfg = config.modules.desktop.session.hyprland;
user = config.user.name;
cursor = config.stylix.cursor;
@@ -27,7 +27,7 @@ let
'';
in
{
options.modules.desktop.hyprland = {
options.modules.desktop.session.hyprland = {
enable = lib.mkEnableOption "the Hyprland compositor";
blur = lib.mkEnableOption ''

View File

@@ -6,7 +6,7 @@
}:
# hypridle: idle-triggered locking and display power management.
let
cfg = config.modules.desktop.hyprland.hypridle;
cfg = config.modules.desktop.session.hyprland.hypridle;
user = config.user.name;
hyprctl = "${config.programs.hyprland.package}/bin/hyprctl";
@@ -17,7 +17,7 @@ let
lockCmd = "${pkgs.procps}/bin/pidof hyprlock || ${hyprlock}";
in
{
options.modules.desktop.hyprland.hypridle = {
options.modules.desktop.session.hyprland.hypridle = {
enable = lib.mkEnableOption "hypridle idle management";
lockTimeout = lib.mkOption {

View File

@@ -6,7 +6,7 @@
}:
# The lock screen: a hyprlock session-lock surface the compositor owns.
let
cfg = config.modules.desktop.hyprland.hyprlock;
cfg = config.modules.desktop.session.hyprland.hyprlock;
user = config.user.name;
# The hyprlock this module installs, used by the lock keybind below.
@@ -45,7 +45,7 @@ let
'';
in
{
options.modules.desktop.hyprland.hyprlock.enable = lib.mkEnableOption "the hyprlock lock screen";
options.modules.desktop.session.hyprland.hyprlock.enable = lib.mkEnableOption "the hyprlock lock screen";
config = lib.mkIf cfg.enable {
home-manager.users.${user} = {

View File

@@ -7,10 +7,10 @@
# Text login: greetd running the tuigreet greeter, which starts the session
# through the universal Wayland session manager.
let
cfg = config.modules.desktop.login;
cfg = config.modules.desktop.session.login;
in
{
options.modules.desktop.login.enable = lib.mkEnableOption "greetd with the tuigreet text greeter";
options.modules.desktop.session.login.enable = lib.mkEnableOption "greetd with the tuigreet text greeter";
config = lib.mkIf cfg.enable {
services.greetd = {

View File

@@ -6,13 +6,13 @@
}:
# mako as the notification daemon: toasts, a do-not-disturb mode, and history recall.
let
cfg = config.modules.desktop.mako;
cfg = config.modules.desktop.session.mako;
user = config.user.name;
makoctl = "${pkgs.mako}/bin/makoctl";
in
{
options.modules.desktop.mako.enable = lib.mkEnableOption "the mako notification daemon";
options.modules.desktop.session.mako.enable = lib.mkEnableOption "the mako notification daemon";
config = lib.mkIf cfg.enable {
home-manager.users.${user} = {

View File

@@ -1,10 +1,10 @@
{ config, lib, ... }:
# XDG desktop portal routing for in-app screen sharing and file dialogs.
let
cfg = config.modules.desktop.portals;
cfg = config.modules.desktop.session.portals;
in
{
options.modules.desktop.portals.enable =
options.modules.desktop.session.portals.enable =
lib.mkEnableOption "XDG desktop portals for in-app screen sharing and file dialogs";
config = lib.mkIf cfg.enable {

View File

@@ -6,7 +6,7 @@
}:
# rofi as the desktop launcher and dmenu-style menu frontend.
let
cfg = config.modules.desktop.rofi;
cfg = config.modules.desktop.session.rofi;
user = config.user.name;
# A session menu built on the same themed rofi, so the power actions look
@@ -24,7 +24,7 @@ let
'';
in
{
options.modules.desktop.rofi.enable = lib.mkEnableOption "the rofi launcher";
options.modules.desktop.session.rofi.enable = lib.mkEnableOption "the rofi launcher";
config = lib.mkIf cfg.enable {
home-manager.users.${user} = {

View File

@@ -6,7 +6,7 @@
}:
# Waybar: a top status bar reading system state at a glance.
let
cfg = config.modules.desktop.waybar;
cfg = config.modules.desktop.session.waybar;
user = config.user.name;
# A Nerd Font Private-Use-Area codepoint as a literal character, decoded
@@ -49,7 +49,7 @@ let
'';
in
{
options.modules.desktop.waybar.enable = lib.mkEnableOption "the Waybar status bar";
options.modules.desktop.session.waybar.enable = lib.mkEnableOption "the Waybar status bar";
config = lib.mkIf cfg.enable {
# A symbols font backs the module glyphs, so pango falls back to it for the

View File

@@ -1,10 +1,10 @@
{ config, lib, ... }:
# PipeWire as the desktop audio server.
let
cfg = config.modules.desktop.audio;
cfg = config.modules.desktop.utilities.audio;
in
{
options.modules.desktop.audio.enable = lib.mkEnableOption "the PipeWire audio server";
options.modules.desktop.utilities.audio.enable = lib.mkEnableOption "the PipeWire audio server";
config = lib.mkIf cfg.enable {
# Realtime scheduling for the audio threads, so playback survives load.

View File

@@ -6,7 +6,7 @@
}:
# Clipboard history: cliphist records every copy, picked back through rofi.
let
cfg = config.modules.desktop.clipboard;
cfg = config.modules.desktop.utilities.clipboard;
user = config.user.name;
cliphist = "${pkgs.cliphist}/bin/cliphist";
@@ -25,7 +25,7 @@ let
'';
in
{
options.modules.desktop.clipboard.enable = lib.mkEnableOption "cliphist clipboard history";
options.modules.desktop.utilities.clipboard.enable = lib.mkEnableOption "cliphist clipboard history";
config = lib.mkIf cfg.enable {
home-manager.users.${user} = {

View File

@@ -6,11 +6,11 @@
}:
# SwayOSD: a transient on-screen popup for volume and brightness changes.
let
cfg = config.modules.desktop.osd;
cfg = config.modules.desktop.utilities.osd;
user = config.user.name;
in
{
options.modules.desktop.osd.enable = lib.mkEnableOption "the SwayOSD volume and brightness popup";
options.modules.desktop.utilities.osd.enable = lib.mkEnableOption "the SwayOSD volume and brightness popup";
config = lib.mkIf cfg.enable {
environment.systemPackages = [ pkgs.swayosd ];

View File

@@ -6,7 +6,7 @@
}:
# Keybound screen recording: pick a region, then toggle a video-only capture.
let
cfg = config.modules.desktop.recording;
cfg = config.modules.desktop.utilities.recording;
user = config.user.name;
slurp = "${pkgs.slurp}/bin/slurp";
@@ -41,7 +41,7 @@ let
'';
in
{
options.modules.desktop.recording.enable = lib.mkEnableOption "wf-recorder screen recording";
options.modules.desktop.utilities.recording.enable = lib.mkEnableOption "wf-recorder screen recording";
config = lib.mkIf cfg.enable {
home-manager.users.${user} = {

View File

@@ -7,7 +7,7 @@
# Keyboard-driven screenshots that open in satty for annotation, then land in
# both the clipboard and a dated file.
let
cfg = config.modules.desktop.screenshot;
cfg = config.modules.desktop.utilities.screenshot;
user = config.user.name;
grimblast = "${pkgs.grimblast}/bin/grimblast";
@@ -32,7 +32,7 @@ let
'';
in
{
options.modules.desktop.screenshot.enable = lib.mkEnableOption "screenshots via grimblast and satty";
options.modules.desktop.utilities.screenshot.enable = lib.mkEnableOption "screenshots via grimblast and satty";
config = lib.mkIf cfg.enable {
home-manager.users.${user} = {

View File

@@ -6,7 +6,7 @@
}:
# Nord theming for the graphical layer, driven from one base16 scheme by Stylix.
let
cfg = config.modules.desktop.theming;
cfg = config.modules.desktop.utilities.theming;
user = config.user.name;
# A single static Nord wallpaper, drawn as a vertical gradient across the
@@ -18,7 +18,7 @@ let
'';
in
{
options.modules.desktop.theming.enable =
options.modules.desktop.utilities.theming.enable =
lib.mkEnableOption "Nord theming of the graphical layer via Stylix";
config = lib.mkIf cfg.enable {

View File

@@ -2,11 +2,11 @@
# Declares the XDG user directories, so a tool that queries them lands in a
# well-known folder a host can relocate from one place.
let
cfg = config.modules.desktop.userdirs;
cfg = config.modules.desktop.utilities.userdirs;
user = config.user.name;
in
{
options.modules.desktop.userdirs.enable = lib.mkEnableOption "XDG user directories";
options.modules.desktop.utilities.userdirs.enable = lib.mkEnableOption "XDG user directories";
config = lib.mkIf cfg.enable {
# Write ~/.config/user-dirs.dirs from the option defaults.

View File

@@ -8,7 +8,7 @@ in
config = lib.mkIf cfg.enable {
system.stateVersion = "26.05";
modules.ssh.enable = lib.mkDefault true;
modules.ssh.hostKeys.restore = lib.mkDefault false;
modules.network.ssh.enable = lib.mkDefault true;
modules.network.ssh.hostKeys.restore = lib.mkDefault false;
};
}

View File

@@ -6,7 +6,7 @@
}:
# SSH on this machine, in both directions.
let
cfg = config.modules.ssh;
cfg = config.modules.network.ssh;
user = config.user.name;
inherit (lib)
@@ -153,7 +153,7 @@ let
);
in
{
options.modules.ssh = {
options.modules.network.ssh = {
enable = lib.mkEnableOption "the OpenSSH daemon, with host keys restored from secrets";
hosts = {
@@ -226,7 +226,7 @@ in
default = null;
description = ''
Complete override for client public keys admitted by this host.
Leave null to derive access from `modules.ssh.hosts` and `modules.ssh.targets`.
Leave null to derive access from `modules.network.ssh.hosts` and `modules.network.ssh.targets`.
'';
};
@@ -304,7 +304,7 @@ in
assertions = [
{
assertion = cfg.hostKeys.sopsFile != null;
message = "modules.ssh.hostKeys.restore requires modules.ssh.hostKeys.sopsFile to name the encrypted host keys.";
message = "modules.network.ssh.hostKeys.restore requires modules.network.ssh.hostKeys.sopsFile to name the encrypted host keys.";
}
];

View File

@@ -6,30 +6,26 @@
}:
# The host networking foundation: per-VLAN bridges over a tagged trunk.
let
cfg = config.modules.network;
cfg = config.modules.network.vlans;
# Each tagged VLAN materializes as a bridge named for its id, by the shared
# convention.
inherit (my) bridgeName;
# The tagged sub-interface stacked on the trunk that feeds one bridge.
vlanName = id: "${cfg.trunk}.${toString id}";
in
{
options.modules.network = {
enable =
lib.mkEnableOption "the host trunk, its tagged-VLAN bridges, and the host management address";
options.modules.network.vlans = {
enable = lib.mkEnableOption "host VLAN bridges over a tagged trunk";
trunk = lib.mkOption {
type = lib.types.str;
example = "enp1s0";
description = ''
The physical interface carrying 802.1Q-tagged traffic for every VLAN.
Each declared VLAN is stacked on it and enslaved to its own bridge.
Physical interface that carries 802.1Q-tagged traffic for every VLAN.
Each declared VLAN attaches to its own bridge.
'';
};
vlans = lib.mkOption {
ids = lib.mkOption {
type = lib.types.listOf (lib.types.ints.between 1 4094);
default = [ ];
example = [
@@ -38,8 +34,8 @@ in
30
];
description = ''
The tagged VLAN ids to materialize. Each id N emits exactly one bridge
named `br-vlanN`, and guests on VLAN N attach to it.
Tagged VLAN ids to materialize.
Each id N creates one bridge named `br-vlanN`.
'';
};
@@ -48,9 +44,9 @@ in
type = lib.types.nullOr (lib.types.ints.between 1 4094);
default = null;
description = ''
The VLAN whose bridge carries the host's own management address; must
be one of `vlans`. Left null, the host takes no address on any bridge
and the bridges serve guests alone.
VLAN whose bridge carries the host's own management address.
The value must be one of `ids`.
Left null, the host takes no address on any bridge.
'';
};
@@ -59,8 +55,8 @@ in
default = null;
example = "10.0.10.2/24";
description = ''
The host's static management address, in CIDR form, on the management
VLAN's bridge. Left null, the host takes its address there by DHCP.
Host static management address in CIDR form.
Left null, the host takes its management address by DHCP.
'';
};
};
@@ -69,21 +65,20 @@ in
config = lib.mkIf cfg.enable {
assertions = [
{
assertion = cfg.management.vlan == null || lib.elem cfg.management.vlan cfg.vlans;
message = "modules.network.management.vlan (${toString cfg.management.vlan}) must name one of modules.network.vlans.";
assertion = cfg.management.vlan == null || lib.elem cfg.management.vlan cfg.ids;
message = "modules.network.vlans.management.vlan (${toString cfg.management.vlan}) must name one of modules.network.vlans.ids.";
}
{
assertion = cfg.management.address == null || cfg.management.vlan != null;
message = "modules.network.management.address needs modules.network.management.vlan to say which bridge carries it.";
message = "modules.network.vlans.management.address needs modules.network.vlans.management.vlan to say which bridge carries it.";
}
];
# networkd owns the trunk, its VLAN sub-interfaces, and the bridges, so a host
# also running NetworkManager leaves them to networkd rather than contending.
# networkd owns these interfaces so NetworkManager does not contend for them.
networking.networkmanager.unmanaged =
[ "interface-name:${cfg.trunk}" ]
++ map (id: "interface-name:${bridgeName id}") cfg.vlans
++ map (id: "interface-name:${vlanName id}") cfg.vlans;
++ map (id: "interface-name:${bridgeName id}") cfg.ids
++ map (id: "interface-name:${vlanName id}") cfg.ids;
systemd.network = {
enable = true;
@@ -103,19 +98,18 @@ in
};
vlanConfig.Id = id;
};
}) cfg.vlans
}) cfg.ids
);
networks = lib.mkMerge (
[
# The trunk carries only tagged frames up to the sub-interfaces and
# takes no address of its own.
# The trunk carries only tagged frames and takes no address.
{
"30-${cfg.trunk}" = {
matchConfig.Name = cfg.trunk;
networkConfig.LinkLocalAddressing = "no";
linkConfig.RequiredForOnline = "no";
vlan = map vlanName cfg.vlans;
vlan = map vlanName cfg.ids;
};
}
]
@@ -126,8 +120,8 @@ in
networkConfig.Bridge = bridgeName id;
linkConfig.RequiredForOnline = "no";
};
# The management VLAN's bridge carries the host address; every other
# bridge is a plain L2 segment for guests.
# The management bridge carries the host address.
# Other bridges provide L2 segments for guests.
"40-${bridgeName id}" = lib.mkMerge [
{
matchConfig.Name = bridgeName id;
@@ -140,7 +134,7 @@ in
{ address = [ cfg.management.address ]; }
))
];
}) cfg.vlans
}) cfg.ids
);
};
};

View File

@@ -5,11 +5,11 @@
}:
# direnv for the primary user, configured through home-manager.
let
cfg = config.modules.direnv;
cfg = config.modules.shell.direnv;
user = config.user.name;
in
{
options.modules.direnv.enable =
options.modules.shell.direnv.enable =
lib.mkEnableOption "direnv for the primary user, with nix-direnv shell caching";
config = lib.mkIf cfg.enable {

View File

@@ -6,13 +6,13 @@
}:
# fish for the primary user, configured through home-manager.
let
cfg = config.modules.fish;
cfg = config.modules.shell.fish;
user = config.user.name;
shortcuts = config.registry.shell-shortcut.${config.networking.hostName};
commandsOf = shortcuts: lib.mapAttrs (_name: shortcut: shortcut.command) shortcuts;
in
{
options.modules.fish = {
options.modules.shell.fish = {
enable = lib.mkEnableOption "fish as the user's shell, configured via home-manager";
defaultShell = lib.mkOption {

View File

@@ -5,11 +5,11 @@
}:
# git for the primary user, configured through home-manager.
let
cfg = config.modules.git;
cfg = config.modules.shell.git;
user = config.user.name;
in
{
options.modules.git.enable =
options.modules.shell.git.enable =
lib.mkEnableOption "git for the primary user, carrying the operator's commit identity";
config = lib.mkIf cfg.enable {

View File

@@ -6,11 +6,11 @@
}:
# Herdr, a terminal multiplexer for coding agents.
let
cfg = config.modules.agents.herdr;
cfg = config.modules.shell.herdr;
user = config.user.name;
in
{
options.modules.agents.herdr.enable = lib.mkEnableOption "Herdr, a terminal multiplexer for coding agents";
options.modules.shell.herdr.enable = lib.mkEnableOption "Herdr, a terminal multiplexer for coding agents";
config = lib.mkIf cfg.enable {
registry.shell-shortcut.${config.networking.hostName}.hs = "herdr --session";

View File

@@ -7,11 +7,11 @@
}:
# Neovim for the primary user, configured declaratively through nixvim.
let
cfg = config.modules.nvim;
cfg = config.modules.shell.nvim;
user = config.user.name;
in
{
options.modules.nvim.enable = lib.mkEnableOption "Neovim, configured declaratively via nixvim";
options.modules.shell.nvim.enable = lib.mkEnableOption "Neovim, configured declaratively via nixvim";
config = lib.mkIf cfg.enable {
registry.shell-shortcut.${config.networking.hostName} = {

View File

@@ -6,11 +6,11 @@
# tmux for the primary user, configured through home-manager.
# Settings without a home-manager option are read from ./extra.conf.
let
cfg = config.modules.tmux;
cfg = config.modules.shell.tmux;
user = config.user.name;
in
{
options.modules.tmux.enable = lib.mkEnableOption "tmux, configured via home-manager";
options.modules.shell.tmux.enable = lib.mkEnableOption "tmux, configured via home-manager";
config = lib.mkIf cfg.enable {
registry.shell-shortcut.${config.networking.hostName}.tmx = "tmux new-session -A -s";