summaryrefslogtreecommitdiffstats
path: root/pkgs
diff options
context:
space:
mode:
authorBenedikt Peetz <benedikt.peetz@b-peetz.de>2026-11-04 17:56:37 +0100
committerBenedikt Peetz <benedikt.peetz@b-peetz.de>2026-11-05 22:47:43 +0100
commit36e836abf8ead21c88154a7e962a8d397d74b78f (patch)
treef8336765778eb22e847e11bfb9d7c92e334810cd /pkgs
parentflake.nix: Don't perform source mapping via sources and raw_sources (diff)
downloadnixos-config-36e836abf8ead21c88154a7e962a8d397d74b78f.zip
pkgs/rollup: Init
Diffstat (limited to 'pkgs')
-rw-r--r--pkgs/by-name/ro/rollup/.envrc21
-rw-r--r--pkgs/by-name/ro/rollup/.gitignore16
-rw-r--r--pkgs/by-name/ro/rollup/Cargo.lock193
-rw-r--r--pkgs/by-name/ro/rollup/Cargo.toml20
-rw-r--r--pkgs/by-name/ro/rollup/package.unstable.nix28
-rw-r--r--pkgs/by-name/ro/rollup/patches2/0001-hosts-apzu-Add-host.toml.patch21
-rw-r--r--pkgs/by-name/ro/rollup/patches2/0002-treewide-Use-extra_modules-to-import-dependency-modu.patch391
-rw-r--r--pkgs/by-name/ro/rollup/patches2/0003-modules-Always-use-extra_lib-also-for-options.mkEnab.patch564
-rw-r--r--pkgs/by-name/ro/rollup/patches2/0004-pkgs-Use-a-stable-unstable-marker-in-the-filename.patch278
-rw-r--r--pkgs/by-name/ro/rollup/patches2/0005-modules-Fix-various-name-mistakes-and-other-issues.patch1098
-rw-r--r--pkgs/by-name/ro/rollup/patches2/0006-lib-Merge-with-the-extraLib.patch145
-rw-r--r--pkgs/by-name/ro/rollup/patches2/0007-flake.nix-Don-t-perform-source-mapping-via-sources-a.patch65
-rw-r--r--pkgs/by-name/ro/rollup/src/main.rs106
-rwxr-xr-xpkgs/by-name/ro/rollup/update.sh14
14 files changed, 2960 insertions, 0 deletions
diff --git a/pkgs/by-name/ro/rollup/.envrc b/pkgs/by-name/ro/rollup/.envrc
new file mode 100644
index 00000000..0001f149
--- /dev/null
+++ b/pkgs/by-name/ro/rollup/.envrc
@@ -0,0 +1,21 @@
+#!/usr/bin/env sh
+
+# Mpdpopm - A mpd rating tracker
+#
+# Copyright (C) 2026 Benedikt Peetz, Michael Herstine <sp1ff@pobox.com> <benedikt.peetz@b-peetz.de, sp1ff@pobox.com>
+# SPDX-License-Identifier: AGPL-3.0-or-later
+#
+# This file is part of Mpdpopm.
+#
+# You should have received a copy of the License along with this program.
+# If not, see <https://www.gnu.org/licenses/agpl.txt>.
+
+source_env_if_exists ./.nenvrc
+
+PATH_add ./scripts
+PATH_add ./target/debug/
+PATH_add ./target/release/
+
+if on_git_branch; then
+ echo && git status --short --branch
+fi
diff --git a/pkgs/by-name/ro/rollup/.gitignore b/pkgs/by-name/ro/rollup/.gitignore
new file mode 100644
index 00000000..c80d7eef
--- /dev/null
+++ b/pkgs/by-name/ro/rollup/.gitignore
@@ -0,0 +1,16 @@
+# Mpdpopm - A mpd rating tracker
+#
+# Copyright (C) 2026 Benedikt Peetz, Michael Herstine <sp1ff@pobox.com> <benedikt.peetz@b-peetz.de, sp1ff@pobox.com>
+# SPDX-License-Identifier: AGPL-3.0-or-later
+#
+# This file is part of Mpdpopm.
+#
+# You should have received a copy of the License along with this program.
+# If not, see <https://www.gnu.org/licenses/agpl.txt>.
+
+# build
+/target
+/result
+
+# dev env
+.direnv
diff --git a/pkgs/by-name/ro/rollup/Cargo.lock b/pkgs/by-name/ro/rollup/Cargo.lock
new file mode 100644
index 00000000..dc5d553a
--- /dev/null
+++ b/pkgs/by-name/ro/rollup/Cargo.lock
@@ -0,0 +1,193 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "anstream"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d"
+dependencies = [
+ "anstyle",
+ "anstyle-parse",
+ "anstyle-query",
+ "anstyle-wincon",
+ "colorchoice",
+ "is_terminal_polyfill",
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle"
+version = "1.0.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000"
+
+[[package]]
+name = "anstyle-parse"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e"
+dependencies = [
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle-query"
+version = "1.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
+dependencies = [
+ "windows-sys",
+]
+
+[[package]]
+name = "anstyle-wincon"
+version = "3.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
+dependencies = [
+ "anstyle",
+ "once_cell_polyfill",
+ "windows-sys",
+]
+
+[[package]]
+name = "anyhow"
+version = "1.0.104"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470"
+
+[[package]]
+name = "clap"
+version = "4.6.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa8876b300ab35ba921adea3dfd70157a46249b33f95c9084ae5709785478946"
+dependencies = [
+ "clap_builder",
+ "clap_derive",
+]
+
+[[package]]
+name = "clap_builder"
+version = "4.6.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec0797fb7aeb1406c84efac526901f7ec3ead2124f946b494e72879d4b54704d"
+dependencies = [
+ "anstream",
+ "anstyle",
+ "clap_lex",
+ "strsim",
+]
+
+[[package]]
+name = "clap_derive"
+version = "4.6.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f9c751b79415d4e559e3d1fcf128e09e720eb673a06d26cf6f392d37d75b66e0"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "clap_lex"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1c133bc6a41be0d194c306b5506d15e6feeea7b1d6604bd3f8310dfb2ca96486"
+
+[[package]]
+name = "colorchoice"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570"
+
+[[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
+[[package]]
+name = "is_terminal_polyfill"
+version = "1.70.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
+
+[[package]]
+name = "once_cell_polyfill"
+version = "1.70.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.107"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.47"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "rollup"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "clap",
+]
+
+[[package]]
+name = "strsim"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+
+[[package]]
+name = "syn"
+version = "3.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563"
+
+[[package]]
+name = "utf8parse"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
+
+[[package]]
+name = "windows-link"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
+
+[[package]]
+name = "windows-sys"
+version = "0.61.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
+dependencies = [
+ "windows-link",
+]
diff --git a/pkgs/by-name/ro/rollup/Cargo.toml b/pkgs/by-name/ro/rollup/Cargo.toml
new file mode 100644
index 00000000..ce857a6e
--- /dev/null
+++ b/pkgs/by-name/ro/rollup/Cargo.toml
@@ -0,0 +1,20 @@
+# Mpdpopm - A mpd rating tracker
+#
+# Copyright (C) 2026 Benedikt Peetz, Michael Herstine <sp1ff@pobox.com> <benedikt.peetz@b-peetz.de, sp1ff@pobox.com>
+# SPDX-License-Identifier: AGPL-3.0-or-later
+#
+# This file is part of Mpdpopm.
+#
+# You should have received a copy of the License along with this program.
+# If not, see <https://www.gnu.org/licenses/agpl.txt>.
+
+[package]
+name = "rollup"
+version = "0.1.0"
+edition = "2024"
+license = "AGPL-3.0-or-later"
+homepage = ""
+
+[dependencies]
+clap = { version = "4.6", features = ["derive"] }
+anyhow = "1.0.104"
diff --git a/pkgs/by-name/ro/rollup/package.unstable.nix b/pkgs/by-name/ro/rollup/package.unstable.nix
new file mode 100644
index 00000000..6c052965
--- /dev/null
+++ b/pkgs/by-name/ro/rollup/package.unstable.nix
@@ -0,0 +1,28 @@
+# nixos-config - My current NixOS configuration
+#
+# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+# This file is part of my nixos-config.
+#
+# You should have received a copy of the License along with this program.
+# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
+{
+ rustPlatform,
+}:
+rustPlatform.buildRustPackage (finalAttrs: {
+ pname = "rollup";
+ version = "0.1.0";
+
+ buildInputs = [];
+ nativeBuildInputs = [];
+
+ src = ./.;
+ cargoLock = {
+ lockFile = ./Cargo.lock;
+ };
+
+ meta = {
+ mainProgram = "rollup";
+ };
+})
diff --git a/pkgs/by-name/ro/rollup/patches2/0001-hosts-apzu-Add-host.toml.patch b/pkgs/by-name/ro/rollup/patches2/0001-hosts-apzu-Add-host.toml.patch
new file mode 100644
index 00000000..0d9213b6
--- /dev/null
+++ b/pkgs/by-name/ro/rollup/patches2/0001-hosts-apzu-Add-host.toml.patch
@@ -0,0 +1,21 @@
+From 60e073a216a039cc49f35db9d26ecc60c7e3feb9 Mon Sep 17 00:00:00 2001
+From: Benedikt Peetz <benedikt.peetz@b-peetz.de>
+Date: Mon, 2 Nov 2026 15:03:48 +0100
+Subject: [PATCH 1/7] hosts/apzu: Add host.toml
+
+---
+ hosts/by-name/apzu/host.toml | 2 ++
+ 1 file changed, 2 insertions(+)
+ create mode 100644 hosts/by-name/apzu/host.toml
+
+diff --git a/hosts/by-name/apzu/host.toml b/hosts/by-name/apzu/host.toml
+new file mode 100644
+index 00000000..9e975618
+--- /dev/null
++++ b/hosts/by-name/apzu/host.toml
+@@ -0,0 +1,2 @@
++hostname = "apzu.fritzbox.com"
++nixpkgs = "unstable"
+--
+2.55.0
+
diff --git a/pkgs/by-name/ro/rollup/patches2/0002-treewide-Use-extra_modules-to-import-dependency-modu.patch b/pkgs/by-name/ro/rollup/patches2/0002-treewide-Use-extra_modules-to-import-dependency-modu.patch
new file mode 100644
index 00000000..c231408f
--- /dev/null
+++ b/pkgs/by-name/ro/rollup/patches2/0002-treewide-Use-extra_modules-to-import-dependency-modu.patch
@@ -0,0 +1,391 @@
+From 4f492b1253fb14354068a04e6ca37889e1c6b773 Mon Sep 17 00:00:00 2001
+From: Benedikt Peetz <benedikt.peetz@b-peetz.de>
+Date: Mon, 2 Nov 2026 15:05:07 +0100
+Subject: [PATCH 2/7] treewide: Use `extra_modules` to import dependency
+ modules
+
+---
+ flake.nix | 28 ++++++++++++-------
+ .../tiamat/legacy-disk-module/module.nix | 4 +--
+ hosts/default.nix | 19 ++++++-------
+ modules/by-name/ag/age/module.nix | 4 +--
+ modules/by-name/bo/boot/module.nix | 6 ++--
+ modules/by-name/di/disks/module.nix | 4 +--
+ modules/by-name/ho/home-manager/module.nix | 4 +--
+ modules/by-name/im/impermanence/module.nix | 4 +--
+ modules/by-name/ni/nix-index/module.nix | 4 +--
+ modules/by-name/nv/nvim/module.nix | 4 +--
+ tests/default.nix | 23 ++++++---------
+ tests/old/by-name/nv/nvim-neorg/test.nix | 4 +--
+ tests/old/infrastructure/default.nix | 2 +-
+ 13 files changed, 55 insertions(+), 55 deletions(-)
+
+diff --git a/flake.nix b/flake.nix
+index 9e306ef7..860ce277 100644
+--- a/flake.nix
++++ b/flake.nix
+@@ -24,14 +24,22 @@
+ lib = packageSets.unstable.lib;
+ extra_lib = raw_sources.library.nixLib;
+
+- extra_modules = [
+- sources.agenix.nixosModules.default
+- sources.turtle.nixosModules.nixos
+- sources.disko.nixosModules.default
+- sources.impermanence.nixosModules.impermanence
+- sources.simple-nixos-mailserver.nixosModule
+- sources.rocie.nixosModules.default
+- ];
++ extra_modules = {
++ nixos = {
++ agenix = sources.agenix.nixosModules.default;
++ turtle = sources.turtle.nixosModules.nixos;
++ disko = sources.disko.nixosModules.default;
++ impermanence = sources.impermanence.nixosModules.impermanence;
++ simple-nixos-mailserver = sources.simple-nixos-mailserver.nixosModule;
++ rocie = sources.rocie.nixosModules.default;
++ home-manager = sources.home-manager.nixosModules.home-manager;
++ lanzaboote = sources.lanzaboote.nixosModules.lanzaboote;
++ };
++ home = {
++ nix-index-database = sources.nix-index-database.homeModules.nix-index;
++ nixvim = sources.nixvim.homeManagerModule;
++ };
++ };
+ module_args = {
+ inherit
+ sources
+@@ -48,6 +56,7 @@
+ # Needs to be a special argument, because it is used for determining the `imports`
+ # value (via `mkByName`).
+ extra_lib
++ extra_modules
+ ;
+ };
+
+@@ -64,7 +73,6 @@
+ extra_lib
+ module_args
+ special_args
+- extra_modules
+ system
+ ;
+ inherit
+@@ -78,7 +86,7 @@
+ deployChecks = builtins.mapAttrs (system: deployLib: deployLib.deployChecks self.deploy) sources.deploy-rs.lib;
+ tests = lib.attrsets.filterAttrs (_: v: !(v ? meta && v.meta.broken)) (import ./tests
+ {
+- inherit sources packageSets extra_modules module_args special_args extra_lib;
++ inherit sources packageSets module_args special_args extra_lib;
+ });
+ # myPkgsFlat =
+ # builtins.listToAttrs
+diff --git a/hosts/by-name/tiamat/legacy-disk-module/module.nix b/hosts/by-name/tiamat/legacy-disk-module/module.nix
+index 955d2026..8c49f6eb 100644
+--- a/hosts/by-name/tiamat/legacy-disk-module/module.nix
++++ b/hosts/by-name/tiamat/legacy-disk-module/module.nix
+@@ -11,7 +11,7 @@
+ config,
+ lib,
+ pkgs,
+- modules,
++ extra_modules,
+ ...
+ }: let
+ # FIXME: The iso redeploy requires a bigger efi partition <2024-05-12>
+@@ -48,7 +48,7 @@ in {
+ };
+
+ imports = [
+- modules.disko.nixosModules.default
++ extra_modules.nixos.disko
+ ];
+
+ config = lib.mkIf cfg.enable {
+diff --git a/hosts/default.nix b/hosts/default.nix
+index 4a3d52fc..4f5d2982 100644
+--- a/hosts/default.nix
++++ b/hosts/default.nix
+@@ -2,7 +2,6 @@
+ self,
+ extra_lib,
+ module_args,
+- extra_modules,
+ special_args,
+ nixpkgs-stable,
+ nixpkgs-unstable,
+@@ -24,17 +23,15 @@
+ in
+ nixpkgs.lib.nixosSystem {
+ specialArgs = special_args;
+- modules =
+- extra_modules
+- ++ [
+- {
+- _module.args = module_args;
+- }
+- path
++ modules = [
++ {
++ _module.args = module_args;
++ }
++ path
+
+- ../modules
+- # ../modules/common
+- ];
++ ../modules
++ # ../modules/common
++ ];
+ };
+ mkDeployHost = name: path: let
+ host_file = builtins.fromTOML (builtins.readFile path + "/host.toml");
+diff --git a/modules/by-name/ag/age/module.nix b/modules/by-name/ag/age/module.nix
+index 9a498ab6..6eb0f9c4 100644
+--- a/modules/by-name/ag/age/module.nix
++++ b/modules/by-name/ag/age/module.nix
+@@ -1,7 +1,7 @@
+ {
+ config,
+ lib,
+- modules,
++ extra_modules,
+ pkgs,
+ ...
+ }: let
+@@ -12,7 +12,7 @@ in {
+ };
+
+ imports = [
+- modules.agenix.nixosModules.default
++ extra_modules.nixos.agenix
+ ];
+
+ config = lib.mkIf cfg.enable {
+diff --git a/modules/by-name/bo/boot/module.nix b/modules/by-name/bo/boot/module.nix
+index 86ad58da..8d3cbe5f 100644
+--- a/modules/by-name/bo/boot/module.nix
++++ b/modules/by-name/bo/boot/module.nix
+@@ -11,7 +11,7 @@
+ config,
+ lib,
+ pkgs,
+- modules,
++ extra_modules,
+ modulesPath,
+ system,
+ specialArgs,
+@@ -94,7 +94,7 @@ in {
+ };
+
+ imports = [
+- modules.lanzaboote.nixosModules.lanzaboote
++ extra_modules.nixos.lanzaboote
+ ];
+
+ config = lib.mkIf cfg.enable {
+@@ -130,7 +130,7 @@ in {
+ lanzabooteInstallHook = import "${modulesPath}/../lib/eval-config.nix" {
+ inherit system specialArgs;
+ modules = [
+- modules.lanzaboote.nixosModules.lanzaboote
++ extra_modules.nixos.lanzaboote
+
+ {
+ # Copy the relevant config into the eval-module context.
+diff --git a/modules/by-name/di/disks/module.nix b/modules/by-name/di/disks/module.nix
+index ed5c939a..0a46c402 100644
+--- a/modules/by-name/di/disks/module.nix
++++ b/modules/by-name/di/disks/module.nix
+@@ -11,7 +11,7 @@
+ config,
+ lib,
+ pkgs,
+- modules,
++ extra_modules,
+ ...
+ }: let
+ cfg = config.soispha.disks;
+@@ -42,7 +42,7 @@ in {
+ };
+
+ imports = [
+- modules.disko.nixosModules.default
++ extra_modules.nixos.disko
+ ];
+
+ config = lib.mkIf cfg.enable {
+diff --git a/modules/by-name/ho/home-manager/module.nix b/modules/by-name/ho/home-manager/module.nix
+index d7eccbd6..e20cfa6d 100644
+--- a/modules/by-name/ho/home-manager/module.nix
++++ b/modules/by-name/ho/home-manager/module.nix
+@@ -11,7 +11,7 @@
+ config,
+ lib,
+ system,
+- modules,
++ extra_modules,
+ ...
+ }: let
+ cfg = config.soispha.home-manager;
+@@ -21,7 +21,7 @@ in {
+ };
+
+ imports = [
+- modules.home-manager.nixosModules.home-manager
++ extra_modules.nixos.home-manager
+ ];
+
+ # TODO: Find a way to throw this error below, when a user `enable`s a home-manager
+diff --git a/modules/by-name/im/impermanence/module.nix b/modules/by-name/im/impermanence/module.nix
+index 0fbd7425..0de6f3e6 100644
+--- a/modules/by-name/im/impermanence/module.nix
++++ b/modules/by-name/im/impermanence/module.nix
+@@ -1,7 +1,7 @@
+ {
+ config,
+ lib,
+- modules,
++ extra_modules,
+ ...
+ }: let
+ cfg = config.vhack.persist;
+@@ -46,7 +46,7 @@ in {
+ };
+
+ imports = [
+- modules.impermanence.nixosModules.impermanence
++ extra_modules.nixos.impermanence
+ ];
+
+ config = lib.mkIf cfg.enable {
+diff --git a/modules/by-name/ni/nix-index/module.nix b/modules/by-name/ni/nix-index/module.nix
+index 72be6b52..269c6f95 100644
+--- a/modules/by-name/ni/nix-index/module.nix
++++ b/modules/by-name/ni/nix-index/module.nix
+@@ -10,7 +10,7 @@
+ {
+ config,
+ lib,
+- modules,
++ extra_modules,
+ ...
+ }: let
+ cfg = config.soispha.programs.nix-index;
+@@ -27,7 +27,7 @@ in {
+
+ home-manager.users.soispha = {
+ imports = [
+- modules.nix-index-database.homeModules.nix-index
++ extra_modules.home.nix-index-database
+ ];
+
+ programs.nix-index = {
+diff --git a/modules/by-name/nv/nvim/module.nix b/modules/by-name/nv/nvim/module.nix
+index f6f9ba95..f6e2162e 100644
+--- a/modules/by-name/nv/nvim/module.nix
++++ b/modules/by-name/nv/nvim/module.nix
+@@ -11,7 +11,7 @@
+ pkgs,
+ lib,
+ config,
+- modules,
++ extra_modules,
+ libraries,
+ ...
+ }: let
+@@ -51,7 +51,7 @@ in {
+
+ home-manager.users.soispha = {
+ imports = [
+- modules.nixvim.homeModules.nixvim
++ extra_modules.home.nixvim
+ ];
+
+ home.sessionVariables = {
+diff --git a/tests/default.nix b/tests/default.nix
+index 870ecfb5..6ab6b5fa 100644
+--- a/tests/default.nix
++++ b/tests/default.nix
+@@ -1,6 +1,5 @@
+ {
+ packageSets,
+- extra_modules,
+ module_args,
+ special_args,
+ extra_lib,
+@@ -86,12 +85,10 @@
+ ];
+ };
+ name_server = {nodes, ...}: {
+- imports =
+- extra_modules
+- ++ [
+- ./common/acme/client.nix
+- ./common/dns/server.nix
+- ];
++ imports = [
++ ./common/acme/client.nix
++ ./common/dns/server.nix
++ ];
+
+ vhack.dns.zones = let
+ mkDomain = attr: let
+@@ -129,14 +126,12 @@
+
+ args.nodes
+ (builtins.mapAttrs (_: _: {
+- imports =
+- extra_modules
+- ++ [
+- ./common/acme/client.nix
+- ./common/dns/client.nix
++ imports = [
++ ./common/acme/client.nix
++ ./common/dns/client.nix
+
+- ../modules
+- ];
++ ../modules
++ ];
+ })
+ args.nodes)
+ ];
+diff --git a/tests/old/by-name/nv/nvim-neorg/test.nix b/tests/old/by-name/nv/nvim-neorg/test.nix
+index 9f160df5..82cb533d 100644
+--- a/tests/old/by-name/nv/nvim-neorg/test.nix
++++ b/tests/old/by-name/nv/nvim-neorg/test.nix
+@@ -9,7 +9,7 @@
+ # If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
+ {
+ mkTest,
+- extraModules,
++ extra_modules,
+ pkgs,
+ ...
+ }:
+@@ -34,7 +34,7 @@ mkTest {
+ };
+ home-manager.users.soispha = {
+ imports = [
+- extraModules.nixvim.homeManagerModule
++ extra_modules.home.nixvim
+ ];
+ };
+ };
+diff --git a/tests/old/infrastructure/default.nix b/tests/old/infrastructure/default.nix
+index cd21198c..4696a99f 100644
+--- a/tests/old/infrastructure/default.nix
++++ b/tests/old/infrastructure/default.nix
+@@ -47,7 +47,7 @@ nixos-lib.runTest {
+ machine = {config, ...}: {
+ imports =
+ [
+- extraModules.home-manager
++ extra_modules.home.home-manager
+ ../../modules/by-name/us/users/module.nix
+ ]
+ ++ configuration.imports;
+--
+2.55.0
+
diff --git a/pkgs/by-name/ro/rollup/patches2/0003-modules-Always-use-extra_lib-also-for-options.mkEnab.patch b/pkgs/by-name/ro/rollup/patches2/0003-modules-Always-use-extra_lib-also-for-options.mkEnab.patch
new file mode 100644
index 00000000..c44f0ba8
--- /dev/null
+++ b/pkgs/by-name/ro/rollup/patches2/0003-modules-Always-use-extra_lib-also-for-options.mkEnab.patch
@@ -0,0 +1,564 @@
+From 82481ecb3850d7ec0bcd1dfee721600a2302a7ce Mon Sep 17 00:00:00 2001
+From: Benedikt Peetz <benedikt.peetz@b-peetz.de>
+Date: Mon, 2 Nov 2026 15:10:37 +0100
+Subject: [PATCH 3/7] modules/*: Always use `extra_lib`, also for
+ `options.mkEnable`
+
+---
+ modules/by-name/al/alacritty/module.nix | 4 ++--
+ modules/by-name/au/ausweisapp/module.nix | 4 ++--
+ modules/by-name/ca/calibre/module.nix | 4 ++--
+ modules/by-name/ca/cargo/module.nix | 4 ++--
+ modules/by-name/fo/foot/module.nix | 4 ++--
+ modules/by-name/gt/gtk/module.nix | 4 ++--
+ modules/by-name/hl/lhedger/module.nix | 4 ++--
+ modules/by-name/ia/iamb/module.nix | 4 ++--
+ modules/by-name/lf/lf/module.nix | 4 ++--
+ modules/by-name/lu/lutris/module.nix | 4 ++--
+ modules/by-name/ma/mandb/module.nix | 4 ++--
+ modules/by-name/me/mergiraf/module.nix | 4 ++--
+ modules/by-name/mp/mpdpopm/module.nix | 4 ++--
+ modules/by-name/ni/nix/module.nix | 4 ++--
+ modules/by-name/ni/nixos-option/module.nix | 4 ++--
+ modules/by-name/nv/nvim/module.nix | 4 ++--
+ modules/by-name/op/openssh/module.nix | 4 ++--
+ modules/by-name/pi/pipewire/module.nix | 4 ++--
+ modules/by-name/pl/plymouth/module.nix | 4 ++--
+ modules/by-name/ri/river/keymap.nix | 2 +-
+ modules/by-name/ro/rofi/module.nix | 4 ++--
+ modules/by-name/si/signal/module.nix | 4 ++--
+ modules/by-name/so/sound/module.nix | 4 ++--
+ modules/by-name/st/starship/module.nix | 4 ++--
+ modules/by-name/sw/swaybg/module.nix | 4 ++--
+ modules/by-name/sw/swayidle/module.nix | 4 ++--
+ 26 files changed, 51 insertions(+), 51 deletions(-)
+
+diff --git a/modules/by-name/al/alacritty/module.nix b/modules/by-name/al/alacritty/module.nix
+index 73860a57..74b938ec 100644
+--- a/modules/by-name/al/alacritty/module.nix
++++ b/modules/by-name/al/alacritty/module.nix
+@@ -11,13 +11,13 @@
+ config,
+ lib,
+ pkgs,
+- libraries,
++ extra_lib,
+ ...
+ }: let
+ cfg = config.soispha.programs.alacritty;
+ in {
+ options.soispha.programs.alacritty = {
+- enable = libraries.base.options.mkEnable "alacritty";
++ enable = extra_lib.options.mkDefaultEnabled "alacritty";
+
+ package = lib.mkPackageOption pkgs "alacritty" {};
+ };
+diff --git a/modules/by-name/au/ausweisapp/module.nix b/modules/by-name/au/ausweisapp/module.nix
+index e74f3d91..93716ed9 100644
+--- a/modules/by-name/au/ausweisapp/module.nix
++++ b/modules/by-name/au/ausweisapp/module.nix
+@@ -1,13 +1,13 @@
+ {
+ config,
+ lib,
+- libraries,
++ extra_lib,
+ ...
+ }: let
+ cfg = config.soispha.programs.ausweisapp;
+ in {
+ options.soispha.programs.ausweisapp = {
+- enable = libraries.base.options.mkEnable "AusweisApp";
++ enable = extra_lib.options.mkDefaultEnabled "AusweisApp";
+ };
+
+ config = lib.mkIf cfg.enable {
+diff --git a/modules/by-name/ca/calibre/module.nix b/modules/by-name/ca/calibre/module.nix
+index 4188e360..76b245e0 100644
+--- a/modules/by-name/ca/calibre/module.nix
++++ b/modules/by-name/ca/calibre/module.nix
+@@ -10,13 +10,13 @@
+ {
+ config,
+ lib,
+- libraries,
++ extra_lib,
+ ...
+ }: let
+ cfg = config.soispha.programs.calibre;
+ in {
+ options.soispha.programs.calibre = {
+- enable = libraries.base.options.mkEnable "calibre";
++ enable = extra_lib.options.mkDefaultEnabled "calibre";
+ };
+
+ config = lib.mkIf cfg.enable {
+diff --git a/modules/by-name/ca/cargo/module.nix b/modules/by-name/ca/cargo/module.nix
+index 6b675a03..a4216020 100644
+--- a/modules/by-name/ca/cargo/module.nix
++++ b/modules/by-name/ca/cargo/module.nix
+@@ -10,13 +10,13 @@
+ {
+ config,
+ lib,
+- libraries,
++ extra_lib,
+ ...
+ }: let
+ cfg = config.soispha.programs.cargo;
+ in {
+ options.soispha.programs.cargo = {
+- enable = libraries.base.options.mkEnable "cargo";
++ enable = extra_lib.options.mkDefaultEnabled "cargo";
+ };
+
+ config = lib.mkIf cfg.enable {
+diff --git a/modules/by-name/fo/foot/module.nix b/modules/by-name/fo/foot/module.nix
+index 8d5cfe2b..d0189e21 100644
+--- a/modules/by-name/fo/foot/module.nix
++++ b/modules/by-name/fo/foot/module.nix
+@@ -10,14 +10,14 @@
+ {
+ config,
+ lib,
+- libraries,
++ extra_lib,
+ pkgs,
+ ...
+ }: let
+ cfg = config.soispha.foot;
+ in {
+ options.soispha.foot = {
+- enable = libraries.base.options.mkEnable "foot terminal";
++ enable = extra_lib.options.mkDefaultEnabled "foot terminal";
+ };
+
+ config = lib.mkIf cfg.enable {
+diff --git a/modules/by-name/gt/gtk/module.nix b/modules/by-name/gt/gtk/module.nix
+index 44442077..cfb000a0 100644
+--- a/modules/by-name/gt/gtk/module.nix
++++ b/modules/by-name/gt/gtk/module.nix
+@@ -12,7 +12,7 @@
+ pkgs,
+ lib,
+ packageSets,
+- libraries,
++ extra_lib,
+ ...
+ }: let
+ cfg = config.soispha.gtk;
+@@ -20,7 +20,7 @@
+ homeConfig = config.home-manager.users.soispha;
+ in {
+ options.soispha.gtk = {
+- enable = libraries.base.options.mkEnable "gtk themes";
++ enable = extra_lib.options.mkDefaultEnabled "gtk themes";
+ };
+
+ config.home-manager.users.soispha = lib.mkIf cfg.enable {
+diff --git a/modules/by-name/hl/lhedger/module.nix b/modules/by-name/hl/lhedger/module.nix
+index 68de85d0..2a9a9e3a 100644
+--- a/modules/by-name/hl/lhedger/module.nix
++++ b/modules/by-name/hl/lhedger/module.nix
+@@ -11,14 +11,14 @@
+ config,
+ lib,
+ pkgs,
+- libraries,
++ extra_lib,
+ ...
+ }: let
+ cfg = config.soispha.hledger;
+ ledgerFile = "${config.home-manager.users.soispha.xdg.dataHome}/hledger/2025.journal";
+ in {
+ options.soispha.hledger = {
+- enable = libraries.base.options.mkEnable "hledger";
++ enable = extra_lib.options.mkDefaultEnabled "hledger";
+ };
+
+ config = lib.mkIf cfg.enable {
+diff --git a/modules/by-name/ia/iamb/module.nix b/modules/by-name/ia/iamb/module.nix
+index ef46f5e0..8b8697ac 100644
+--- a/modules/by-name/ia/iamb/module.nix
++++ b/modules/by-name/ia/iamb/module.nix
+@@ -10,13 +10,13 @@
+ {
+ config,
+ lib,
+- libraries,
++ extra_lib,
+ ...
+ }: let
+ cfg = config.soispha.programs.iamb;
+ in {
+ options.soispha.programs.iamb = {
+- enable = libraries.base.options.mkEnable "iamb";
++ enable = extra_lib.options.mkDefaultEnabled "iamb";
+ };
+
+ config = lib.mkIf cfg.enable {
+diff --git a/modules/by-name/lf/lf/module.nix b/modules/by-name/lf/lf/module.nix
+index 2d80f68e..9d9447d6 100644
+--- a/modules/by-name/lf/lf/module.nix
++++ b/modules/by-name/lf/lf/module.nix
+@@ -14,7 +14,7 @@
+ shell_library,
+ system,
+ lib,
+- libraries,
++ extra_lib,
+ ...
+ }: let
+ real_commands = import ./commands {inherit pkgs sysLib shell_library system;};
+@@ -23,7 +23,7 @@
+ # HACK: There is no (easy) way for me to make sure, that the `clearmaps` command is
+ # generated in the lf config before the keymapping commands.
+ # This command injection works around that. <2026-07-21>
+- commands = libraries.extra.warnMerge real_commands {
++ commands = extra_lib.warnMerge real_commands {
+ __clearmaps_injection = ''
+ :{{
+ clearmaps
+diff --git a/modules/by-name/lu/lutris/module.nix b/modules/by-name/lu/lutris/module.nix
+index 6864bacb..7772b269 100644
+--- a/modules/by-name/lu/lutris/module.nix
++++ b/modules/by-name/lu/lutris/module.nix
+@@ -10,7 +10,7 @@
+ {
+ lib,
+ config,
+- libraries,
++ extra_lib,
+ pkgs,
+ ...
+ }: let
+@@ -19,7 +19,7 @@
+ inherit (config.home-manager.users.soispha.home) homeDirectory;
+ in {
+ options.soispha.programs.lutris = {
+- enable = libraries.base.options.mkEnable "Lutris";
++ enable = extra_lib.options.mkDefaultEnabled "Lutris";
+ };
+
+ config = lib.mkIf cfg.enable {
+diff --git a/modules/by-name/ma/mandb/module.nix b/modules/by-name/ma/mandb/module.nix
+index 64d586db..83992729 100644
+--- a/modules/by-name/ma/mandb/module.nix
++++ b/modules/by-name/ma/mandb/module.nix
+@@ -10,13 +10,13 @@
+ {
+ config,
+ lib,
+- libraries,
++ extra_lib,
+ ...
+ }: let
+ cfg = config.soispha.services.mandb;
+ in {
+ options.soispha.services.mandb = {
+- enable = libraries.base.options.mkEnable "mandb";
++ enable = extra_lib.options.mkDefaultEnabled "mandb";
+ };
+
+ config = lib.mkIf cfg.enable {
+diff --git a/modules/by-name/me/mergiraf/module.nix b/modules/by-name/me/mergiraf/module.nix
+index 693969e6..e1048ca1 100644
+--- a/modules/by-name/me/mergiraf/module.nix
++++ b/modules/by-name/me/mergiraf/module.nix
+@@ -10,13 +10,13 @@
+ {
+ config,
+ lib,
+- libraries,
++ extra_lib,
+ ...
+ }: let
+ cfg = config.soispha.programs.mergiraf;
+ in {
+ options.soispha.programs.mergiraf = {
+- enable = libraries.base.options.mkEnable "mergiraf";
++ enable = extra_lib.options.mkDefaultEnabled "mergiraf";
+ };
+
+ config = lib.mkIf cfg.enable {
+diff --git a/modules/by-name/mp/mpdpopm/module.nix b/modules/by-name/mp/mpdpopm/module.nix
+index 82943fe8..03529095 100644
+--- a/modules/by-name/mp/mpdpopm/module.nix
++++ b/modules/by-name/mp/mpdpopm/module.nix
+@@ -10,7 +10,7 @@
+ {
+ config,
+ pkgs,
+- libraries,
++ extra_lib,
+ lib,
+ ...
+ }: let
+@@ -19,7 +19,7 @@
+ settingsFormat = pkgs.formats.json {};
+ in {
+ options.soispha.services.mpdpopm = {
+- enable = libraries.base.options.mkEnable "mpdpopm";
++ enable = extra_lib.options.mkDefaultEnabled "mpdpopm";
+
+ settings = lib.mkOption {
+ # Setting this type allows for correct merging behavior
+diff --git a/modules/by-name/ni/nix/module.nix b/modules/by-name/ni/nix/module.nix
+index e46d6e85..11b2d7e4 100644
+--- a/modules/by-name/ni/nix/module.nix
++++ b/modules/by-name/ni/nix/module.nix
+@@ -9,7 +9,7 @@
+ # If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
+ {
+ pkgs,
+- libraries,
++ extra_lib,
+ config,
+ lib,
+ # flakes
+@@ -56,7 +56,7 @@
+ cfg = config.soispha.nix;
+ in {
+ options.soispha.nix = {
+- enable = libraries.base.options.mkEnable "nix";
++ enable = extra_lib.options.mkDefaultEnabled "nix";
+ };
+
+ config = lib.mkIf cfg.enable {
+diff --git a/modules/by-name/ni/nixos-option/module.nix b/modules/by-name/ni/nixos-option/module.nix
+index 0053d357..3e41bd34 100644
+--- a/modules/by-name/ni/nixos-option/module.nix
++++ b/modules/by-name/ni/nixos-option/module.nix
+@@ -1,13 +1,13 @@
+ {
+ config,
+ lib,
+- libraries,
++ extra_lib,
+ ...
+ }: let
+ cfg = config.soispha.programs.nixos-option;
+ in {
+ options.soispha.programs.nixos-option = {
+- enable = libraries.base.options.mkEnable "nixos-option";
++ enable = extra_lib.options.mkDefaultEnabled "nixos-option";
+ };
+
+ config = lib.mkIf cfg.enable {
+diff --git a/modules/by-name/nv/nvim/module.nix b/modules/by-name/nv/nvim/module.nix
+index f6e2162e..e63c9565 100644
+--- a/modules/by-name/nv/nvim/module.nix
++++ b/modules/by-name/nv/nvim/module.nix
+@@ -12,12 +12,12 @@
+ lib,
+ config,
+ extra_modules,
+- libraries,
++ extra_lib,
+ ...
+ }: let
+ cfg = config.soispha.programs.nvim;
+
+- plgs = builtins.attrValues (libraries.extra.mkByName {
++ plgs = builtins.attrValues (extra_lib.mkByName {
+ useShards = false;
+ baseDirectory = ./plgs;
+ fileName = "default.nix";
+diff --git a/modules/by-name/op/openssh/module.nix b/modules/by-name/op/openssh/module.nix
+index 3182f7ba..e1464338 100644
+--- a/modules/by-name/op/openssh/module.nix
++++ b/modules/by-name/op/openssh/module.nix
+@@ -1,13 +1,13 @@
+ {
+ config,
+ lib,
+- libraries,
++ extra_lib,
+ ...
+ }: let
+ cfg = config.vhack.openssh;
+ in {
+ options.vhack.openssh = {
+- enable = libraries.base.options.mkEnable "openssh";
++ enable = extra_lib.options.mkDefaultEnabled "openssh";
+ };
+
+ config = lib.mkIf cfg.enable {
+diff --git a/modules/by-name/pi/pipewire/module.nix b/modules/by-name/pi/pipewire/module.nix
+index 57610806..df8eca0a 100644
+--- a/modules/by-name/pi/pipewire/module.nix
++++ b/modules/by-name/pi/pipewire/module.nix
+@@ -10,13 +10,13 @@
+ {
+ config,
+ lib,
+- libraries,
++ extra_lib,
+ ...
+ }: let
+ cfg = config.soispha.pipewire;
+ in {
+ options.soispha.pipewire = {
+- enable = libraries.base.options.mkEnable "pipewire and wireplumber";
++ enable = extra_lib.options.mkDefaultEnabled "pipewire and wireplumber";
+ };
+
+ config = lib.mkIf cfg.enable {
+diff --git a/modules/by-name/pl/plymouth/module.nix b/modules/by-name/pl/plymouth/module.nix
+index 5e4735b9..f64c9464 100644
+--- a/modules/by-name/pl/plymouth/module.nix
++++ b/modules/by-name/pl/plymouth/module.nix
+@@ -11,13 +11,13 @@
+ config,
+ pkgs,
+ lib,
+- libraries,
++ extra_lib,
+ ...
+ }: let
+ cfg = config.soispha.services.plymouth;
+ in {
+ options.soispha.services.plymouth = {
+- enable = libraries.base.options.mkEnable "plymouth";
++ enable = extra_lib.options.mkDefaultEnabled "plymouth";
+ };
+
+ config = lib.mkIf cfg.enable {
+diff --git a/modules/by-name/ri/river/keymap.nix b/modules/by-name/ri/river/keymap.nix
+index 897d11df..feabf379 100644
+--- a/modules/by-name/ri/river/keymap.nix
++++ b/modules/by-name/ri/river/keymap.nix
+@@ -1,7 +1,7 @@
+ {
+ lib,
+ pkgs,
+- libraries,
++ extra_lib,
+ config,
+ ...
+ }: let
+diff --git a/modules/by-name/ro/rofi/module.nix b/modules/by-name/ro/rofi/module.nix
+index f2b404d6..ac23b499 100644
+--- a/modules/by-name/ro/rofi/module.nix
++++ b/modules/by-name/ro/rofi/module.nix
+@@ -10,13 +10,13 @@
+ {
+ config,
+ lib,
+- libraries,
++ extra_lib,
+ ...
+ }: let
+ cfg = config.soispha.programs.rofi;
+ in {
+ options.soispha.programs.rofi = {
+- enable = libraries.base.options.mkEnable "rofi";
++ enable = extra_lib.options.mkDefaultEnabled "rofi";
+ };
+
+ config = lib.mkIf cfg.enable {
+diff --git a/modules/by-name/si/signal/module.nix b/modules/by-name/si/signal/module.nix
+index 0e9c4437..e7cef901 100644
+--- a/modules/by-name/si/signal/module.nix
++++ b/modules/by-name/si/signal/module.nix
+@@ -1,13 +1,13 @@
+ {
+ config,
+ lib,
+- libraries,
++ extra_lib,
+ ...
+ }: let
+ cfg = config.soispha.signal;
+ in {
+ options.soispha.signal = {
+- enable = libraries.base.options.mkEnable "signal";
++ enable = extra_lib.options.mkDefaultEnabled "signal";
+ };
+ config = lib.mkIf cfg.enable {
+ soispha.impermanence.userDirectories = [
+diff --git a/modules/by-name/so/sound/module.nix b/modules/by-name/so/sound/module.nix
+index 06df63e5..67187ff3 100644
+--- a/modules/by-name/so/sound/module.nix
++++ b/modules/by-name/so/sound/module.nix
+@@ -9,14 +9,14 @@
+ # If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
+ {
+ config,
+- libraries,
++ extra_lib,
+ lib,
+ ...
+ }: let
+ cfg = config.soispha.sound;
+ in {
+ options.soispha.sound = {
+- enable = libraries.base.options.mkEnable "sound based on pipewire";
++ enable = extra_lib.options.mkDefaultEnabled "sound based on pipewire";
+ };
+
+ config = lib.mkIf cfg.enable {
+diff --git a/modules/by-name/st/starship/module.nix b/modules/by-name/st/starship/module.nix
+index a271d645..903f97b6 100644
+--- a/modules/by-name/st/starship/module.nix
++++ b/modules/by-name/st/starship/module.nix
+@@ -11,13 +11,13 @@
+ lib,
+ pkgs,
+ config,
+- libraries,
++ extra_lib,
+ ...
+ }: let
+ cfg = config.soispha.programs.starship;
+ in {
+ options.soispha.programs.starship = {
+- enable = libraries.base.options.mkEnable "starship";
++ enable = extra_lib.options.mkDefaultEnabled "starship";
+
+ showBattery = lib.mkOption {
+ type = lib.types.bool;
+diff --git a/modules/by-name/sw/swaybg/module.nix b/modules/by-name/sw/swaybg/module.nix
+index fa6a079a..216a0c59 100644
+--- a/modules/by-name/sw/swaybg/module.nix
++++ b/modules/by-name/sw/swaybg/module.nix
+@@ -11,13 +11,13 @@
+ config,
+ lib,
+ pkgs,
+- libraries,
++ extra_lib,
+ ...
+ }: let
+ cfg = config.soispha.programs.swaybg;
+ in {
+ options.soispha.programs.swaybg = {
+- enable = libraries.base.options.mkEnable "swaybg";
++ enable = extra_lib.options.mkDefaultEnabled "swaybg";
+ };
+
+ config = lib.mkIf cfg.enable {
+diff --git a/modules/by-name/sw/swayidle/module.nix b/modules/by-name/sw/swayidle/module.nix
+index 9bda534f..953ec83f 100644
+--- a/modules/by-name/sw/swayidle/module.nix
++++ b/modules/by-name/sw/swayidle/module.nix
+@@ -11,14 +11,14 @@
+ config,
+ pkgs,
+ lib,
+- libraries,
++ extra_lib,
+ ...
+ }: let
+ cfg = config.soispha.programs.swayidle;
+ swaylock = lib.getExe pkgs.swaylock;
+ in {
+ options.soispha.programs.swayidle = {
+- enable = libraries.base.options.mkEnable "swayidle";
++ enable = extra_lib.options.mkDefaultEnabled "swayidle";
+ };
+
+ config = lib.mkIf cfg.enable {
+--
+2.55.0
+
diff --git a/pkgs/by-name/ro/rollup/patches2/0004-pkgs-Use-a-stable-unstable-marker-in-the-filename.patch b/pkgs/by-name/ro/rollup/patches2/0004-pkgs-Use-a-stable-unstable-marker-in-the-filename.patch
new file mode 100644
index 00000000..9f275376
--- /dev/null
+++ b/pkgs/by-name/ro/rollup/patches2/0004-pkgs-Use-a-stable-unstable-marker-in-the-filename.patch
@@ -0,0 +1,278 @@
+From 4e606441932dfac2c99d12ed2fa2413c45d1dec6 Mon Sep 17 00:00:00 2001
+From: Benedikt Peetz <benedikt.peetz@b-peetz.de>
+Date: Mon, 2 Nov 2026 19:53:17 +0100
+Subject: [PATCH 4/7] pkgs/*: Use a `stable`/`unstable` marker in the filename
+
+---
+ .../aumo/{package.nix => package.unstable.nix} | 0
+ .../{package.nix => package.unstable.nix} | 0
+ .../{package.nix => package.unstable.nix} | 0
+ .../{package.nix => package.unstable.nix} | 0
+ .../{package.nix => package.unstable.nix} | 0
+ .../{package.nix => package.unstable.nix} | 0
+ .../{package.nix => package.unstable.nix} | 0
+ .../{package.nix => package.unstable.nix} | 0
+ .../{package.nix => package.stable.nix} | 0
+ .../{package.nix => package.unstable.nix} | 0
+ .../{package.nix => package.unstable.nix} | 0
+ .../{package.nix => package.unstable.nix} | 0
+ .../{package.nix => package.unstable.nix} | 0
+ .../{package.nix => package.unstable.nix} | 0
+ .../{package.nix => package.unstable.nix} | 0
+ .../{package.nix => package.unstable.nix} | 0
+ .../{package.nix => package.unstable.nix} | 0
+ .../{package.nix => package.unstable.nix} | 0
+ .../{package.nix => package.unstable.nix} | 0
+ .../{package.nix => package.unstable.nix} | 0
+ .../lock/{package.nix => package.unstable.nix} | 0
+ .../{package.nix => package.unstable.nix} | 0
+ .../{package.nix => package.unstable.nix} | 0
+ .../{package.nix => package.unstable.nix} | 0
+ .../{package.nix => package.unstable.nix} | 0
+ .../mpp/{package.nix => package.unstable.nix} | 0
+ .../{package.nix => package.unstable.nix} | 0
+ .../{package.nix => package.unstable.nix} | 0
+ .../{package.nix => package.unstable.nix} | 0
+ .../{package.nix => package.unstable.nix} | 0
+ .../{package.nix => package.unstable.nix} | 0
+ .../{package.nix => package.stable.nix} | 0
+ .../{package.nix => package.unstable.nix} | 0
+ .../sw/{package.nix => package.unstable.nix} | 0
+ .../{package.nix => package.unstable.nix} | 0
+ .../{package.nix => package.unstable.nix} | 0
+ .../{package.nix => package.unstable.nix} | 0
+ .../tskm/{package.nix => package.unstable.nix} | 0
+ .../yt/{package.nix => package.unstable.nix} | 0
+ pkgs/default.nix | 18 +++++++++++-------
+ 40 files changed, 11 insertions(+), 7 deletions(-)
+ rename pkgs/by-name/au/aumo/{package.nix => package.unstable.nix} (100%)
+ rename pkgs/by-name/ba/battery/{package.nix => package.unstable.nix} (100%)
+ rename pkgs/by-name/be/beetsExtraPlugins/{package.nix => package.unstable.nix} (100%)
+ rename pkgs/by-name/br/brightness/{package.nix => package.unstable.nix} (100%)
+ rename pkgs/by-name/co/con2pdf/{package.nix => package.unstable.nix} (100%)
+ rename pkgs/by-name/ct/ctpv-64-types/{package.nix => package.unstable.nix} (100%)
+ rename pkgs/by-name/di/direnv-patched/{package.nix => package.unstable.nix} (100%)
+ rename pkgs/by-name/fd/fd_list/{package.nix => package.unstable.nix} (100%)
+ rename pkgs/by-name/fe/fetchmail-common-name/{package.nix => package.stable.nix} (100%)
+ rename pkgs/by-name/fi/fish-mk-maps/{package.nix => package.unstable.nix} (100%)
+ rename pkgs/by-name/fi/fish-patched/{package.nix => package.unstable.nix} (100%)
+ rename pkgs/by-name/fu/fupdate-flake/{package.nix => package.unstable.nix} (100%)
+ rename pkgs/by-name/fu/fupdate-sys/{package.nix => package.unstable.nix} (100%)
+ rename pkgs/by-name/fu/fupdate/{package.nix => package.unstable.nix} (100%)
+ rename pkgs/by-name/gi/git-cgit/{package.nix => package.unstable.nix} (100%)
+ rename pkgs/by-name/gi/git-cm/{package.nix => package.unstable.nix} (100%)
+ rename pkgs/by-name/gi/git-edit-index/{package.nix => package.unstable.nix} (100%)
+ rename pkgs/by-name/hi/hibernate/{package.nix => package.unstable.nix} (100%)
+ rename pkgs/by-name/i3/i3bar-river-patched/{package.nix => package.unstable.nix} (100%)
+ rename pkgs/by-name/lf/lf-make-map/{package.nix => package.unstable.nix} (100%)
+ rename pkgs/by-name/lo/lock/{package.nix => package.unstable.nix} (100%)
+ rename pkgs/by-name/mp/mpdpopm/{package.nix => package.unstable.nix} (100%)
+ rename pkgs/by-name/mp/mpp-beetrm/{package.nix => package.unstable.nix} (100%)
+ rename pkgs/by-name/mp/mpp-lyrics/{package.nix => package.unstable.nix} (100%)
+ rename pkgs/by-name/mp/mpp-searchadd/{package.nix => package.unstable.nix} (100%)
+ rename pkgs/by-name/mp/mpp/{package.nix => package.unstable.nix} (100%)
+ rename pkgs/by-name/no/notify-run/{package.nix => package.unstable.nix} (100%)
+ rename pkgs/by-name/qu/qutebrowser-patched/{package.nix => package.unstable.nix} (100%)
+ rename pkgs/by-name/ri/river-mk-keymap/{package.nix => package.unstable.nix} (100%)
+ rename pkgs/by-name/sc/screenshot_persistent/{package.nix => package.unstable.nix} (100%)
+ rename pkgs/by-name/sc/screenshot_temporary/{package.nix => package.unstable.nix} (100%)
+ rename pkgs/by-name/st/stalwart-mail-patched/{package.nix => package.stable.nix} (100%)
+ rename pkgs/by-name/st/stamp/{package.nix => package.unstable.nix} (100%)
+ rename pkgs/by-name/sw/sw/{package.nix => package.unstable.nix} (100%)
+ rename pkgs/by-name/sy/systemd-toggle/{package.nix => package.unstable.nix} (100%)
+ rename pkgs/by-name/ta/tails-iso/{package.nix => package.unstable.nix} (100%)
+ rename pkgs/by-name/tr/tree-sitter-yts/{package.nix => package.unstable.nix} (100%)
+ rename pkgs/by-name/ts/tskm/{package.nix => package.unstable.nix} (100%)
+ rename pkgs/by-name/yt/yt/{package.nix => package.unstable.nix} (100%)
+
+diff --git a/pkgs/by-name/au/aumo/package.nix b/pkgs/by-name/au/aumo/package.unstable.nix
+similarity index 100%
+rename from pkgs/by-name/au/aumo/package.nix
+rename to pkgs/by-name/au/aumo/package.unstable.nix
+diff --git a/pkgs/by-name/ba/battery/package.nix b/pkgs/by-name/ba/battery/package.unstable.nix
+similarity index 100%
+rename from pkgs/by-name/ba/battery/package.nix
+rename to pkgs/by-name/ba/battery/package.unstable.nix
+diff --git a/pkgs/by-name/be/beetsExtraPlugins/package.nix b/pkgs/by-name/be/beetsExtraPlugins/package.unstable.nix
+similarity index 100%
+rename from pkgs/by-name/be/beetsExtraPlugins/package.nix
+rename to pkgs/by-name/be/beetsExtraPlugins/package.unstable.nix
+diff --git a/pkgs/by-name/br/brightness/package.nix b/pkgs/by-name/br/brightness/package.unstable.nix
+similarity index 100%
+rename from pkgs/by-name/br/brightness/package.nix
+rename to pkgs/by-name/br/brightness/package.unstable.nix
+diff --git a/pkgs/by-name/co/con2pdf/package.nix b/pkgs/by-name/co/con2pdf/package.unstable.nix
+similarity index 100%
+rename from pkgs/by-name/co/con2pdf/package.nix
+rename to pkgs/by-name/co/con2pdf/package.unstable.nix
+diff --git a/pkgs/by-name/ct/ctpv-64-types/package.nix b/pkgs/by-name/ct/ctpv-64-types/package.unstable.nix
+similarity index 100%
+rename from pkgs/by-name/ct/ctpv-64-types/package.nix
+rename to pkgs/by-name/ct/ctpv-64-types/package.unstable.nix
+diff --git a/pkgs/by-name/di/direnv-patched/package.nix b/pkgs/by-name/di/direnv-patched/package.unstable.nix
+similarity index 100%
+rename from pkgs/by-name/di/direnv-patched/package.nix
+rename to pkgs/by-name/di/direnv-patched/package.unstable.nix
+diff --git a/pkgs/by-name/fd/fd_list/package.nix b/pkgs/by-name/fd/fd_list/package.unstable.nix
+similarity index 100%
+rename from pkgs/by-name/fd/fd_list/package.nix
+rename to pkgs/by-name/fd/fd_list/package.unstable.nix
+diff --git a/pkgs/by-name/fe/fetchmail-common-name/package.nix b/pkgs/by-name/fe/fetchmail-common-name/package.stable.nix
+similarity index 100%
+rename from pkgs/by-name/fe/fetchmail-common-name/package.nix
+rename to pkgs/by-name/fe/fetchmail-common-name/package.stable.nix
+diff --git a/pkgs/by-name/fi/fish-mk-maps/package.nix b/pkgs/by-name/fi/fish-mk-maps/package.unstable.nix
+similarity index 100%
+rename from pkgs/by-name/fi/fish-mk-maps/package.nix
+rename to pkgs/by-name/fi/fish-mk-maps/package.unstable.nix
+diff --git a/pkgs/by-name/fi/fish-patched/package.nix b/pkgs/by-name/fi/fish-patched/package.unstable.nix
+similarity index 100%
+rename from pkgs/by-name/fi/fish-patched/package.nix
+rename to pkgs/by-name/fi/fish-patched/package.unstable.nix
+diff --git a/pkgs/by-name/fu/fupdate-flake/package.nix b/pkgs/by-name/fu/fupdate-flake/package.unstable.nix
+similarity index 100%
+rename from pkgs/by-name/fu/fupdate-flake/package.nix
+rename to pkgs/by-name/fu/fupdate-flake/package.unstable.nix
+diff --git a/pkgs/by-name/fu/fupdate-sys/package.nix b/pkgs/by-name/fu/fupdate-sys/package.unstable.nix
+similarity index 100%
+rename from pkgs/by-name/fu/fupdate-sys/package.nix
+rename to pkgs/by-name/fu/fupdate-sys/package.unstable.nix
+diff --git a/pkgs/by-name/fu/fupdate/package.nix b/pkgs/by-name/fu/fupdate/package.unstable.nix
+similarity index 100%
+rename from pkgs/by-name/fu/fupdate/package.nix
+rename to pkgs/by-name/fu/fupdate/package.unstable.nix
+diff --git a/pkgs/by-name/gi/git-cgit/package.nix b/pkgs/by-name/gi/git-cgit/package.unstable.nix
+similarity index 100%
+rename from pkgs/by-name/gi/git-cgit/package.nix
+rename to pkgs/by-name/gi/git-cgit/package.unstable.nix
+diff --git a/pkgs/by-name/gi/git-cm/package.nix b/pkgs/by-name/gi/git-cm/package.unstable.nix
+similarity index 100%
+rename from pkgs/by-name/gi/git-cm/package.nix
+rename to pkgs/by-name/gi/git-cm/package.unstable.nix
+diff --git a/pkgs/by-name/gi/git-edit-index/package.nix b/pkgs/by-name/gi/git-edit-index/package.unstable.nix
+similarity index 100%
+rename from pkgs/by-name/gi/git-edit-index/package.nix
+rename to pkgs/by-name/gi/git-edit-index/package.unstable.nix
+diff --git a/pkgs/by-name/hi/hibernate/package.nix b/pkgs/by-name/hi/hibernate/package.unstable.nix
+similarity index 100%
+rename from pkgs/by-name/hi/hibernate/package.nix
+rename to pkgs/by-name/hi/hibernate/package.unstable.nix
+diff --git a/pkgs/by-name/i3/i3bar-river-patched/package.nix b/pkgs/by-name/i3/i3bar-river-patched/package.unstable.nix
+similarity index 100%
+rename from pkgs/by-name/i3/i3bar-river-patched/package.nix
+rename to pkgs/by-name/i3/i3bar-river-patched/package.unstable.nix
+diff --git a/pkgs/by-name/lf/lf-make-map/package.nix b/pkgs/by-name/lf/lf-make-map/package.unstable.nix
+similarity index 100%
+rename from pkgs/by-name/lf/lf-make-map/package.nix
+rename to pkgs/by-name/lf/lf-make-map/package.unstable.nix
+diff --git a/pkgs/by-name/lo/lock/package.nix b/pkgs/by-name/lo/lock/package.unstable.nix
+similarity index 100%
+rename from pkgs/by-name/lo/lock/package.nix
+rename to pkgs/by-name/lo/lock/package.unstable.nix
+diff --git a/pkgs/by-name/mp/mpdpopm/package.nix b/pkgs/by-name/mp/mpdpopm/package.unstable.nix
+similarity index 100%
+rename from pkgs/by-name/mp/mpdpopm/package.nix
+rename to pkgs/by-name/mp/mpdpopm/package.unstable.nix
+diff --git a/pkgs/by-name/mp/mpp-beetrm/package.nix b/pkgs/by-name/mp/mpp-beetrm/package.unstable.nix
+similarity index 100%
+rename from pkgs/by-name/mp/mpp-beetrm/package.nix
+rename to pkgs/by-name/mp/mpp-beetrm/package.unstable.nix
+diff --git a/pkgs/by-name/mp/mpp-lyrics/package.nix b/pkgs/by-name/mp/mpp-lyrics/package.unstable.nix
+similarity index 100%
+rename from pkgs/by-name/mp/mpp-lyrics/package.nix
+rename to pkgs/by-name/mp/mpp-lyrics/package.unstable.nix
+diff --git a/pkgs/by-name/mp/mpp-searchadd/package.nix b/pkgs/by-name/mp/mpp-searchadd/package.unstable.nix
+similarity index 100%
+rename from pkgs/by-name/mp/mpp-searchadd/package.nix
+rename to pkgs/by-name/mp/mpp-searchadd/package.unstable.nix
+diff --git a/pkgs/by-name/mp/mpp/package.nix b/pkgs/by-name/mp/mpp/package.unstable.nix
+similarity index 100%
+rename from pkgs/by-name/mp/mpp/package.nix
+rename to pkgs/by-name/mp/mpp/package.unstable.nix
+diff --git a/pkgs/by-name/no/notify-run/package.nix b/pkgs/by-name/no/notify-run/package.unstable.nix
+similarity index 100%
+rename from pkgs/by-name/no/notify-run/package.nix
+rename to pkgs/by-name/no/notify-run/package.unstable.nix
+diff --git a/pkgs/by-name/qu/qutebrowser-patched/package.nix b/pkgs/by-name/qu/qutebrowser-patched/package.unstable.nix
+similarity index 100%
+rename from pkgs/by-name/qu/qutebrowser-patched/package.nix
+rename to pkgs/by-name/qu/qutebrowser-patched/package.unstable.nix
+diff --git a/pkgs/by-name/ri/river-mk-keymap/package.nix b/pkgs/by-name/ri/river-mk-keymap/package.unstable.nix
+similarity index 100%
+rename from pkgs/by-name/ri/river-mk-keymap/package.nix
+rename to pkgs/by-name/ri/river-mk-keymap/package.unstable.nix
+diff --git a/pkgs/by-name/sc/screenshot_persistent/package.nix b/pkgs/by-name/sc/screenshot_persistent/package.unstable.nix
+similarity index 100%
+rename from pkgs/by-name/sc/screenshot_persistent/package.nix
+rename to pkgs/by-name/sc/screenshot_persistent/package.unstable.nix
+diff --git a/pkgs/by-name/sc/screenshot_temporary/package.nix b/pkgs/by-name/sc/screenshot_temporary/package.unstable.nix
+similarity index 100%
+rename from pkgs/by-name/sc/screenshot_temporary/package.nix
+rename to pkgs/by-name/sc/screenshot_temporary/package.unstable.nix
+diff --git a/pkgs/by-name/st/stalwart-mail-patched/package.nix b/pkgs/by-name/st/stalwart-mail-patched/package.stable.nix
+similarity index 100%
+rename from pkgs/by-name/st/stalwart-mail-patched/package.nix
+rename to pkgs/by-name/st/stalwart-mail-patched/package.stable.nix
+diff --git a/pkgs/by-name/st/stamp/package.nix b/pkgs/by-name/st/stamp/package.unstable.nix
+similarity index 100%
+rename from pkgs/by-name/st/stamp/package.nix
+rename to pkgs/by-name/st/stamp/package.unstable.nix
+diff --git a/pkgs/by-name/sw/sw/package.nix b/pkgs/by-name/sw/sw/package.unstable.nix
+similarity index 100%
+rename from pkgs/by-name/sw/sw/package.nix
+rename to pkgs/by-name/sw/sw/package.unstable.nix
+diff --git a/pkgs/by-name/sy/systemd-toggle/package.nix b/pkgs/by-name/sy/systemd-toggle/package.unstable.nix
+similarity index 100%
+rename from pkgs/by-name/sy/systemd-toggle/package.nix
+rename to pkgs/by-name/sy/systemd-toggle/package.unstable.nix
+diff --git a/pkgs/by-name/ta/tails-iso/package.nix b/pkgs/by-name/ta/tails-iso/package.unstable.nix
+similarity index 100%
+rename from pkgs/by-name/ta/tails-iso/package.nix
+rename to pkgs/by-name/ta/tails-iso/package.unstable.nix
+diff --git a/pkgs/by-name/tr/tree-sitter-yts/package.nix b/pkgs/by-name/tr/tree-sitter-yts/package.unstable.nix
+similarity index 100%
+rename from pkgs/by-name/tr/tree-sitter-yts/package.nix
+rename to pkgs/by-name/tr/tree-sitter-yts/package.unstable.nix
+diff --git a/pkgs/by-name/ts/tskm/package.nix b/pkgs/by-name/ts/tskm/package.unstable.nix
+similarity index 100%
+rename from pkgs/by-name/ts/tskm/package.nix
+rename to pkgs/by-name/ts/tskm/package.unstable.nix
+diff --git a/pkgs/by-name/yt/yt/package.nix b/pkgs/by-name/yt/yt/package.unstable.nix
+similarity index 100%
+rename from pkgs/by-name/yt/yt/package.nix
+rename to pkgs/by-name/yt/yt/package.unstable.nix
+diff --git a/pkgs/default.nix b/pkgs/default.nix
+index 4fdb94fe..bc7d70e7 100644
+--- a/pkgs/default.nix
++++ b/pkgs/default.nix
+@@ -6,16 +6,20 @@
+ inherit (unstable_pkgs) lib;
+
+ mergePkgs = pkgs: lib.callPackageWith (extra_lib.warnMerge pkgs in_tree_pkgs "the ./pkgs/by-name set");
+- callPackageStable = lib.callPackageWith (mergePkgs stable_pkgs);
+- callPackageUnstable = lib.callPackageWith (mergePkgs unstable_pkgs);
++ callPackageStable = mergePkgs stable_pkgs;
++ callPackageUnstable = mergePkgs unstable_pkgs;
+
+ in_tree_pkgs = extra_lib.mkByName {
+ baseDirectory = ./by-name;
+- fileName = "package.nix";
+- finalizeFunction = name: value:
+- if value.stable
+- then callPackageStable value.pkg {}
+- else callPackageUnstable value.pkg {};
++ fileRegex = "package.(stable|unstable).nix";
++ finalizeFunction = name: pkgPathList: let
++ # When specifying a regex `mkByName` returns a list of candidates.
++ # But we know, that there can only be one.
++ pkgPath = builtins.head pkgPathList;
++ in
++ if (builtins.match "(stable)" (builtins.baseNameOf pkgPath)) == ["stable"]
++ then callPackageStable pkgPath {}
++ else callPackageUnstable pkgPath {};
+ };
+ in
+ in_tree_pkgs
+--
+2.55.0
+
diff --git a/pkgs/by-name/ro/rollup/patches2/0005-modules-Fix-various-name-mistakes-and-other-issues.patch b/pkgs/by-name/ro/rollup/patches2/0005-modules-Fix-various-name-mistakes-and-other-issues.patch
new file mode 100644
index 00000000..242115be
--- /dev/null
+++ b/pkgs/by-name/ro/rollup/patches2/0005-modules-Fix-various-name-mistakes-and-other-issues.patch
@@ -0,0 +1,1098 @@
+From 1daf25c665a1abf14f060f0599d156d84a04d825 Mon Sep 17 00:00:00 2001
+From: Benedikt Peetz <benedikt.peetz@b-peetz.de>
+Date: Mon, 2 Nov 2026 19:55:32 +0100
+Subject: [PATCH 5/7] modules/*: Fix various name mistakes and other issues
+
+---
+ hosts/by-name/apzu/configuration.nix | 32 +++++------
+ hosts/by-name/tiamat/configuration.nix | 43 ++++++++-------
+ modules/by-name/ad/adb/module.nix | 2 +-
+ modules/by-name/at/atuin/module.nix | 9 ++-
+ modules/by-name/au/ausweisapp/module.nix | 2 +-
+ modules/by-name/ba/backup/module.nix | 29 ++++++++--
+ modules/by-name/bl/bluetooth/module.nix | 2 +-
+ modules/by-name/bo/boot/module.nix | 2 +-
+ modules/by-name/ca/calibre/module.nix | 2 +-
+ modules/by-name/co/constants/module.nix | 4 ++
+ modules/by-name/di/direnv/module.nix | 4 +-
+ modules/by-name/fi/fish/keymappings.nix | 22 ++++----
+ modules/by-name/fw/fwupd/module.nix | 4 +-
+ modules/by-name/ia/iamb/module.nix | 2 +-
+ modules/by-name/im/impermanence/module.nix | 12 ++--
+ modules/by-name/lu/lutris/module.nix | 5 +-
+ modules/by-name/ma/mail/module.nix | 18 ++++--
+ modules/by-name/ma/mandb/module.nix | 4 +-
+ modules/by-name/mp/mpv/module.nix | 2 +-
+ modules/by-name/ms/msr/module.nix | 2 +-
+ modules/by-name/ne/networking/module.nix | 8 +--
+ modules/by-name/ni/nixpkgs/module.nix | 9 ++-
+ modules/by-name/nv/nvim/module.nix | 2 +-
+ .../nv/nvim/plgs/lsp/servers/servers/ltex.nix | 2 +
+ modules/by-name/ol/ollama/module.nix | 2 +-
+ modules/by-name/pi/pipewire/module.nix | 2 +-
+ modules/by-name/po/polkit/module.nix | 2 +-
+ modules/by-name/pr/printing/module.nix | 8 +--
+ modules/by-name/ri/river/keymap.nix | 6 +-
+ modules/by-name/ri/river/module.nix | 4 +-
+ modules/by-name/ro/rocie/module.nix | 5 ++
+ modules/by-name/si/signal/module.nix | 2 +-
+ modules/by-name/so/sound/module.nix | 4 +-
+ modules/by-name/ss/ssh/module.nix | 52 +++---------------
+ modules/by-name/us/users/module.nix | 4 +-
+ modules/by-name/wa/waydroid/module.nix | 2 +-
+ modules/by-name/xd/xdg/module.nix | 2 +-
+ modules/common/{ => soispha}/default.nix | 55 +++++++++----------
+ .../common/{ => soispha}/hooks/default.nix | 0
+ .../hooks/scripts/sync-git-repo.sh | 0
+ modules/common/{ => soispha}/projects.json | 0
+ .../{ => soispha}/projects.json.license | 0
+ 42 files changed, 195 insertions(+), 178 deletions(-)
+ rename modules/common/{ => soispha}/default.nix (90%)
+ rename modules/common/{ => soispha}/hooks/default.nix (100%)
+ rename modules/common/{ => soispha}/hooks/scripts/sync-git-repo.sh (100%)
+ rename modules/common/{ => soispha}/projects.json (100%)
+ rename modules/common/{ => soispha}/projects.json.license (100%)
+
+diff --git a/hosts/by-name/apzu/configuration.nix b/hosts/by-name/apzu/configuration.nix
+index a27688ba..fe5be0af 100644
+--- a/hosts/by-name/apzu/configuration.nix
++++ b/hosts/by-name/apzu/configuration.nix
+@@ -10,8 +10,23 @@
+ {...}: {
+ imports = [
+ ./hardware.nix
++ ../../../modules/common/soispha
+ ];
+
++ vhack.users = {
++ enable = true;
++ users = [
++ {
++ name = "soispha";
++ groups = ["wheel" "audio"];
++ enableDeprecatedPlugdev = true;
++ uid = 1000;
++ sshKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIME4ZVa+IoZf6T3U08JG93i6QIAJ4amm7mkBzO14JSkz";
++ hashedPassword = "$y$jFT$3qI9MYLDHPUdGKsVa8skV0$TOjX0SFHWuj52zd7/kmkNtG5EqQwYcqv0FKXWbLaro6";
++ }
++ ];
++ };
++
+ soispha = {
+ bluetooth.enable = true;
+
+@@ -20,10 +35,6 @@
+ enable = true;
+ };
+
+- impermanence.directories = [
+- "/var/log"
+- ];
+-
+ power.enable = true;
+
+ programs = {
+@@ -55,19 +66,6 @@
+ enable = true;
+ systemName = "x86_64-linux";
+ };
+- users = {
+- enable = true;
+- users = [
+- {
+- name = "soispha";
+- groups = ["wheel" "audio"];
+- enableDeprecatedPlugdev = true;
+- uid = 1000;
+- sshKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIME4ZVa+IoZf6T3U08JG93i6QIAJ4amm7mkBzO14JSkz";
+- hashedPassword = "$y$jFT$3qI9MYLDHPUdGKsVa8skV0$TOjX0SFHWuj52zd7/kmkNtG5EqQwYcqv0FKXWbLaro6";
+- }
+- ];
+- };
+ };
+
+ system.stateVersion = "23.05";
+diff --git a/hosts/by-name/tiamat/configuration.nix b/hosts/by-name/tiamat/configuration.nix
+index 35378aa9..462bbe9a 100644
+--- a/hosts/by-name/tiamat/configuration.nix
++++ b/hosts/by-name/tiamat/configuration.nix
+@@ -10,13 +10,33 @@
+ {
+ lib,
+ system,
+- externalBinaries,
++ sources,
+ ...
+ }: {
+ imports = [
+ ./hardware.nix
+ ];
+
++ vhack = {
++ # TODO: Hard-code all the uids/gids <2025-05-13>
++ persist.directories = [
++ "/var/lib/nixos"
++ ];
++ users = {
++ enable = true;
++ users = [
++ {
++ name = "soispha";
++ groups = ["wheel" "audio"];
++ enableDeprecatedPlugdev = true;
++ uid = 1000;
++ sshKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIME4ZVa+IoZf6T3U08JG93i6QIAJ4amm7mkBzO14JSkz";
++ hashedPassword = "$y$jFT$qi3wS9njrMl2y55b3NOBI0$j40Qt6AAkMSfZ82KPhqMaUaPztWtPps1wOqaXaF/L.6";
++ }
++ ];
++ };
++ };
++
+ soispha = {
+ bluetooth = {enable = true;};
+ networking = {
+@@ -29,12 +49,6 @@
+ systemName = "x86_64-linux";
+ };
+
+- # TODO: Hard-code all the uids/gids <2025-05-13>
+- impermanence.directories = [
+- "/var/lib/nixos"
+- "/var/log"
+- ];
+-
+ services = {
+ unison.foreign.address = "apzu.fritz.box";
+ };
+@@ -48,7 +62,7 @@
+ # Support Unicode input
+ "<Alt+Ctrl+Meta+Shift-Z>" = [
+ "spawn"
+- "${lib.getExe externalBinaries.qmk_firmware.packages.${system}.qmk_unicode_type} 106 65377"
++ "${lib.getExe sources.qmk_firmware.packages.${system}.qmk_unicode_type} 106 65377"
+ ];
+ };
+ };
+@@ -66,19 +80,6 @@
+ enable = true;
+ keyMap = "us";
+ };
+- users = {
+- enable = true;
+- users = [
+- {
+- name = "soispha";
+- groups = ["wheel" "audio"];
+- enableDeprecatedPlugdev = true;
+- uid = 1000;
+- sshKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIME4ZVa+IoZf6T3U08JG93i6QIAJ4amm7mkBzO14JSkz";
+- hashedPassword = "$y$jFT$qi3wS9njrMl2y55b3NOBI0$j40Qt6AAkMSfZ82KPhqMaUaPztWtPps1wOqaXaF/L.6";
+- }
+- ];
+- };
+ };
+
+ system.stateVersion = "23.05";
+diff --git a/modules/by-name/ad/adb/module.nix b/modules/by-name/ad/adb/module.nix
+index 89cb1439..9d07a5be 100644
+--- a/modules/by-name/ad/adb/module.nix
++++ b/modules/by-name/ad/adb/module.nix
+@@ -32,7 +32,7 @@ in {
+
+ users = {
+ users."${cfg.user}".extraGroups = ["adbusers"];
+- groups.adbusers.gid = config.soispha.constants.ids.gids.adbusers;
++ groups.adbusers.gid = config.vhack.constants.ids.gids.adbusers;
+ };
+ };
+ }
+diff --git a/modules/by-name/at/atuin/module.nix b/modules/by-name/at/atuin/module.nix
+index d68e830c..b9e9645a 100644
+--- a/modules/by-name/at/atuin/module.nix
++++ b/modules/by-name/at/atuin/module.nix
+@@ -10,12 +10,15 @@
+ {
+ config,
+ lib,
+- externalBinaries,
+- system,
++ extra_modules,
+ ...
+ }: let
+ cfg = config.soispha.programs.atuin;
+ in {
++ imports = [
++ extra_modules.nixos.turtle
++ ];
++
+ options.soispha.programs.atuin = {
+ enable = lib.mkEnableOption "atuin";
+
+@@ -47,7 +50,7 @@ in {
+
+ home-manager.users.soispha = {
+ imports = [
+- externalBinaries.turtle.nixosModules.home-manager
++ extra_modules.home.turtle
+ ];
+
+ programs.turtle = {
+diff --git a/modules/by-name/au/ausweisapp/module.nix b/modules/by-name/au/ausweisapp/module.nix
+index 93716ed9..ee3e8917 100644
+--- a/modules/by-name/au/ausweisapp/module.nix
++++ b/modules/by-name/au/ausweisapp/module.nix
+@@ -11,7 +11,7 @@ in {
+ };
+
+ config = lib.mkIf cfg.enable {
+- soispha.impermanence.userDirectories = [
++ vhack.persist.userDirectories.soispha = [
+ ".config/AusweisApp"
+ ];
+ soispha.services.unison.pathsToSync = [
+diff --git a/modules/by-name/ba/backup/module.nix b/modules/by-name/ba/backup/module.nix
+index ca7a469c..7ac6e081 100644
+--- a/modules/by-name/ba/backup/module.nix
++++ b/modules/by-name/ba/backup/module.nix
+@@ -113,10 +113,31 @@ in {
+ };
+ };
+
+- vhack.programs.ssh = lib.mkIf cfg.storagebox.enable {
+- enable = true;
+- rootKnownHosts = {
+- "[${cfg.storagebox.user}.your-storagebox.de]:23" = cfg.storagebox.sshHostKey;
++ systemd.tmpfiles.settings = lib.mkIf cfg.storagebox.enable {
++ "10-backup-module" = {
++ "/root/.ssh/config".f = let
++ knownHostsFile = pkgs.writeTextFile {
++ name = "known-hosts-file";
++ text = ''
++ [${cfg.storagebox.user}.your-storagebox.de]:23 ${cfg.storagebox.sshHostKey}
++ '';
++ };
++ in {
++ group = "root";
++ user = "root";
++ mode = "0755";
++
++ # Don't try to authenticate via password for these, because we need to use the
++ # forced commands, and they are only provided via the ssh key login.
++ # So password login is a footgun (it is, however, valid to use it for non-root
++ # use-cases)
++ argument = ''
++ Host *.your-storagebox.de
++ PasswordAuthentication no
++ Port 23
++ UserKnownHostsFile ${knownHostsFile}
++ '';
++ };
+ };
+ };
+
+diff --git a/modules/by-name/bl/bluetooth/module.nix b/modules/by-name/bl/bluetooth/module.nix
+index 7750e70d..14f47129 100644
+--- a/modules/by-name/bl/bluetooth/module.nix
++++ b/modules/by-name/bl/bluetooth/module.nix
+@@ -19,7 +19,7 @@ in {
+ };
+
+ config = lib.mkIf cfg.enable {
+- soispha.impermanence.directories = [
++ vhack.persist.directories = [
+ "/var/lib/bluetooth"
+ ];
+
+diff --git a/modules/by-name/bo/boot/module.nix b/modules/by-name/bo/boot/module.nix
+index 8d3cbe5f..f26ce8f7 100644
+--- a/modules/by-name/bo/boot/module.nix
++++ b/modules/by-name/bo/boot/module.nix
+@@ -100,7 +100,7 @@ in {
+ config = lib.mkIf cfg.enable {
+ # This should only be necessary for `lanzaboote`, but that is the current default in
+ # this module.
+- soispha.impermanence.directories = [
++ vhack.persist.directories = [
+ "/var/lib/sbctl"
+ ];
+
+diff --git a/modules/by-name/ca/calibre/module.nix b/modules/by-name/ca/calibre/module.nix
+index 76b245e0..f56c8490 100644
+--- a/modules/by-name/ca/calibre/module.nix
++++ b/modules/by-name/ca/calibre/module.nix
+@@ -20,7 +20,7 @@ in {
+ };
+
+ config = lib.mkIf cfg.enable {
+- soispha.impermanence.userDirectories = [
++ vhack.persist.userDirectories.soispha = [
+ ".config/calibre"
+ ];
+ soispha.services.unison.pathsToSync = [
+diff --git a/modules/by-name/co/constants/module.nix b/modules/by-name/co/constants/module.nix
+index de094cdd..51bf68b7 100644
+--- a/modules/by-name/co/constants/module.nix
++++ b/modules/by-name/co/constants/module.nix
+@@ -68,6 +68,10 @@
+ nm-iodine = 354;
+ fwupd-refresh = 355;
+ avahi = 356;
++ adbusers = 357;
++ lpadmin = 358;
++ msr = 359;
++ polkituser = 360;
+
+ # As per the NixOS file, the uids should not be greater or equal to 400;
+ };
+diff --git a/modules/by-name/di/direnv/module.nix b/modules/by-name/di/direnv/module.nix
+index 97e56827..e868ebba 100644
+--- a/modules/by-name/di/direnv/module.nix
++++ b/modules/by-name/di/direnv/module.nix
+@@ -17,14 +17,14 @@
+ cfg = config.soispha.programs.direnv;
+ direnvCfg = config.home-manager.users.soispha.programs.direnv;
+
+- inherit (sources) devshells nixpkgs;
++ inherit (sources) devshells nixpkgs-unstable;
+
+ pre-cache = pkgs.runCommand "pre-cache.sh" {} ''
+ cat "${./pre-cache.sh}" > $out
+
+ substituteInPlace $out \
+ --replace-fail "%DEVSHELLS_REPO%" "${devshells}" \
+- --replace-fail "%DEVSHELLS_REPO_REF%" "${devshells.sourceInfo.rev}.${builtins.readFile "${nixpkgs}/.git-revision"}"
++ --replace-fail "%DEVSHELLS_REPO_REF%" "${devshells.sourceInfo.rev}.${builtins.readFile "${nixpkgs-unstable}/.git-revision"}"
+ '';
+
+ landrun-fish = pkgs.writeShellApplication {
+diff --git a/modules/by-name/fi/fish/keymappings.nix b/modules/by-name/fi/fish/keymappings.nix
+index fe9ab86e..187c5d5a 100644
+--- a/modules/by-name/fi/fish/keymappings.nix
++++ b/modules/by-name/fi/fish/keymappings.nix
+@@ -227,7 +227,7 @@ in {
+ cmd = "__fish_man_page";
+ sets_mode_to = "default";
+ };
+- "\\e\\[1\;9A" = {
++ "\\e\\[1\\;9A" = {
+ cmd = "history-token-search-backward";
+ sets_mode_to = "default";
+ };
+@@ -305,7 +305,7 @@ in {
+ cmd = "fish_clipboard_copy";
+ sets_mode_to = "default";
+ };
+- "\\e\\[1\;9D" = {
++ "\\e\\[1\\;9D" = {
+ cmd = "prevd-or-backward-word";
+ sets_mode_to = "default";
+ };
+@@ -349,7 +349,7 @@ in {
+ cmd = "commandline -i \\n (commandline --search-field >/dev/null && echo --search-field) expand-abbr";
+ sets_mode_to = "default";
+ };
+- "\\e\\[1\;9B" = {
++ "\\e\\[1\\;9B" = {
+ cmd = "history-token-search-forward";
+ sets_mode_to = "default";
+ };
+@@ -490,10 +490,10 @@ in {
+ };
+ };
+ "default" = {
+- # "\\e\\[1\;9A" = {cmd = "history-token-search-backward";};
+- # "\\e\\[1\;9B" = {cmd = "history-token-search-forward";};
+- # "\\e\\[1\;9C" = {cmd = "nextd-or-forward-word";};
+- # "\\e\\[1\;9D" = {cmd = "prevd-or-backward-word";};
++ # "\\e\\[1\\;9A" = {cmd = "history-token-search-backward";};
++ # "\\e\\[1\\;9B" = {cmd = "history-token-search-forward";};
++ # "\\e\\[1\\;9C" = {cmd = "nextd-or-forward-word";};
++ # "\\e\\[1\\;9D" = {cmd = "prevd-or-backward-word";};
+
+ "down" = {cmd = "down-or-search";};
+ "ctrl-y" = {cmd = "yank";};
+@@ -1015,7 +1015,7 @@ in {
+ cmd = "kill-whole-line end-selection repaint-mode";
+ sets_mode_to = "default";
+ };
+- "\\e\\[1\;9B" = {
++ "\\e\\[1\\;9B" = {
+ cmd = "history-token-search-forward";
+ sets_mode_to = "default";
+ };
+@@ -1051,11 +1051,11 @@ in {
+ cmd = "end-selection repaint-mode";
+ sets_mode_to = "default";
+ };
+- "\\e\\[1\;9D" = {
++ "\\e\\[1\\;9D" = {
+ cmd = "prevd-or-backward-word";
+ sets_mode_to = "default";
+ };
+- "\\e\\[1\;9C" = {
++ "\\e\\[1\\;9C" = {
+ cmd = "nextd-or-forward-word";
+ sets_mode_to = "default";
+ };
+@@ -1099,7 +1099,7 @@ in {
+ cmd = "__fish_whatis_current_token";
+ sets_mode_to = "default";
+ };
+- "\\e\\[1\;9A" = {
++ "\\e\\[1\\;9A" = {
+ cmd = "history-token-search-backward";
+ sets_mode_to = "default";
+ };
+diff --git a/modules/by-name/fw/fwupd/module.nix b/modules/by-name/fw/fwupd/module.nix
+index 7252c170..4a58101a 100644
+--- a/modules/by-name/fw/fwupd/module.nix
++++ b/modules/by-name/fw/fwupd/module.nix
+@@ -22,8 +22,8 @@ in {
+ services.fwupd.enable = true;
+
+ users = {
+- users.fwupd-refresh.uid = config.soispha.constants.ids.uids.fwupd-refresh;
+- groups.fwupd-refresh.gid = config.soispha.constants.ids.gids.fwupd-refresh;
++ users.fwupd-refresh.uid = config.vhack.constants.ids.uids.fwupd-refresh;
++ groups.fwupd-refresh.gid = config.vhack.constants.ids.gids.fwupd-refresh;
+ };
+ };
+ }
+diff --git a/modules/by-name/ia/iamb/module.nix b/modules/by-name/ia/iamb/module.nix
+index 8b8697ac..ee466d4e 100644
+--- a/modules/by-name/ia/iamb/module.nix
++++ b/modules/by-name/ia/iamb/module.nix
+@@ -20,7 +20,7 @@ in {
+ };
+
+ config = lib.mkIf cfg.enable {
+- soispha.impermanence.userDirectories = [
++ vhack.persist.userDirectories.soispha = [
+ ".config/iamb/profiles"
+ ];
+
+diff --git a/modules/by-name/im/impermanence/module.nix b/modules/by-name/im/impermanence/module.nix
+index 0de6f3e6..a0c308d5 100644
+--- a/modules/by-name/im/impermanence/module.nix
++++ b/modules/by-name/im/impermanence/module.nix
+@@ -6,11 +6,11 @@
+ }: let
+ cfg = config.vhack.persist;
+
+- userDirectories = lib.debug.traceValSeqN 2 (lib.mapAttrs (_: dirs: {
+- directories =
+- dirs;
++ userDirectories =
++ lib.mapAttrs (_: dirs: {
++ directories = dirs;
+ })
+- cfg.userDirectories);
++ cfg.userDirectories;
+ in {
+ options.vhack.persist = {
+ enable = lib.mkEnableOption "persisting directories and files with impermanence";
+@@ -30,7 +30,7 @@ in {
+ };
+
+ userDirectories = lib.mkOption {
+- type = lib.attrsOf lib.types.listOf (lib.types.either lib.types.str (lib.types.submodule {
++ type = lib.types.attrsOf (lib.types.listOf (lib.types.either lib.types.str (lib.types.submodule {
+ options = {
+ directory = lib.mkOption {
+ type = lib.types.str;
+@@ -39,7 +39,7 @@ in {
+ type = lib.types.str;
+ };
+ };
+- }));
++ })));
+ default = [];
+ description = "The directories to persist, for each user.";
+ };
+diff --git a/modules/by-name/lu/lutris/module.nix b/modules/by-name/lu/lutris/module.nix
+index 7772b269..54f8f955 100644
+--- a/modules/by-name/lu/lutris/module.nix
++++ b/modules/by-name/lu/lutris/module.nix
+@@ -23,7 +23,7 @@ in {
+ };
+
+ config = lib.mkIf cfg.enable {
+- soispha.impermanence.userDirectories = [
++ vhack.persist.userDirectories.soispha = [
+ ".config/lutris"
+ ];
+ soispha.services.unison.pathsToSync = [
+@@ -33,6 +33,9 @@ in {
+ "${homeDirectory}/.local/share/lutris/install"
+ ];
+
++ # For some reason `lutris` depends on `gtk+-2`.
++ soispha.nixpkgs.problemHandlers."gtk+".broken = "warn";
++
+ # TODO: This should also have something, to avoid giving the games network access: 'https://github.com/lutris/docs/blob/master/DisableNetworkAccess.md' <2026-07-10>
+ home-manager.users.soispha = {
+ programs.lutris = {
+diff --git a/modules/by-name/ma/mail/module.nix b/modules/by-name/ma/mail/module.nix
+index e4cb83cc..540dc1fa 100644
+--- a/modules/by-name/ma/mail/module.nix
++++ b/modules/by-name/ma/mail/module.nix
+@@ -1,10 +1,15 @@
+ {
+ config,
+ lib,
++ extra_modules,
+ ...
+ }: let
+ cfg = config.vhack.mail;
+ in {
++ imports = [
++ extra_modules.nixos.simple-nixos-mailserver
++ ];
++
+ options.vhack.mail = {
+ enable = lib.mkEnableOption "sophisticated mail setup with simple-nixos-mailserver";
+ fqdn = lib.mkOption {
+@@ -323,11 +328,14 @@ in {
+
+ dkim = let
+ dkimKeys =
+- builtins.mapAttrs (name: value: {
+- selectors."mail".keyFile =
+- value.dkimPrivateKeyPath;
+- })
+- cfg.security.dkimKeys;
++ if cfg.security.dkimKeys == null
++ then {}
++ else
++ builtins.mapAttrs (name: value: {
++ selectors."mail".keyFile =
++ value.dkimPrivateKeyPath;
++ })
++ cfg.security.dkimKeys;
+ in {
+ domains = lib.mkIf (cfg.security.dkimKeys != null) dkimKeys;
+ keyDirectory = lib.mkIf (cfg.security.dkimKeys == null) "/var/lib/mail/dkim";
+diff --git a/modules/by-name/ma/mandb/module.nix b/modules/by-name/ma/mandb/module.nix
+index 83992729..a2467070 100644
+--- a/modules/by-name/ma/mandb/module.nix
++++ b/modules/by-name/ma/mandb/module.nix
+@@ -21,8 +21,8 @@ in {
+
+ config = lib.mkIf cfg.enable {
+ users = {
+- users.mandb.uid = config.soispha.constants.ids.uids.mandb;
+- groups.mandb.gid = config.soispha.constants.ids.gids.mandb;
++ users.mandb.uid = config.vhack.constants.ids.uids.mandb;
++ groups.mandb.gid = config.vhack.constants.ids.gids.mandb;
+ };
+ };
+ }
+diff --git a/modules/by-name/mp/mpv/module.nix b/modules/by-name/mp/mpv/module.nix
+index fed2074d..6843b4fd 100644
+--- a/modules/by-name/mp/mpv/module.nix
++++ b/modules/by-name/mp/mpv/module.nix
+@@ -23,7 +23,7 @@ in {
+ soispha.services.unison.pathsToSync = [
+ "~/.local/state/mpv"
+ ];
+- soispha.impermanance.userDirectories = [
++ vhack.persist.userDirectories.soispha = [
+ ".local/state/mpv"
+ ];
+
+diff --git a/modules/by-name/ms/msr/module.nix b/modules/by-name/ms/msr/module.nix
+index 521b3a40..4aa02b9c 100644
+--- a/modules/by-name/ms/msr/module.nix
++++ b/modules/by-name/ms/msr/module.nix
+@@ -11,7 +11,7 @@ in {
+
+ config = lib.mkIf cfg.enable {
+ users = {
+- groups.msr.gid = config.soispha.constants.ids.gids.msr;
++ groups.msr.gid = config.vhack.constants.ids.gids.msr;
+ };
+ };
+ }
+diff --git a/modules/by-name/ne/networking/module.nix b/modules/by-name/ne/networking/module.nix
+index 075a1a5a..94c50af0 100644
+--- a/modules/by-name/ne/networking/module.nix
++++ b/modules/by-name/ne/networking/module.nix
+@@ -96,7 +96,7 @@ in {
+ };
+ };
+
+- soispha.impermanence.directories = [
++ vhack.persist.directories = [
+ "/etc/NetworkManager"
+ ];
+ users = {
+@@ -104,11 +104,11 @@ in {
+ "${cfg.userName}".extraGroups = [
+ "networkmanager" # allows to configure NetworkManager as this user
+ ];
+- nm-iodine.uid = config.soispha.constants.ids.uids.nm-iodine;
+- wpa_supplicant.uid = config.soispha.constants.ids.uids.wpa_supplicant;
++ nm-iodine.uid = config.vhack.constants.ids.uids.nm-iodine;
++ wpa_supplicant.uid = config.vhack.constants.ids.uids.wpa_supplicant;
+ };
+ groups = {
+- wpa_supplicant.gid = config.soispha.constants.ids.gids.wpa_supplicant;
++ wpa_supplicant.gid = config.vhack.constants.ids.gids.wpa_supplicant;
+ };
+ };
+ })
+diff --git a/modules/by-name/ni/nixpkgs/module.nix b/modules/by-name/ni/nixpkgs/module.nix
+index 1ded8444..2971c0e3 100644
+--- a/modules/by-name/ni/nixpkgs/module.nix
++++ b/modules/by-name/ni/nixpkgs/module.nix
+@@ -27,10 +27,15 @@ in {
+ example = "[ steam steam-unwrapped ]";
+ type = lib.types.listOf lib.types.str;
+ };
++ problemHandlers = lib.mkOption {
++ description = "Decide how to handle a package marked with problems.";
++ example = "{ \"gtk+\".broken = \"warn\"; }";
++ type = lib.types.attrsOf (lib.types.attrsOf lib.types.anything);
++ };
+ };
+
+ config = let
+- myPkgsOverlay = self: super: packageSets.soispha;
++ myPkgsOverlay = self: super: packageSets.in_tree;
+ in
+ lib.mkIf cfg.enable
+ {
+@@ -44,6 +49,8 @@ in {
+ config = {
+ hostSystem = cfg.systemName;
+
++ problems.handlers = cfg.problemHandlers;
++
+ allowUnfreePredicate = pkg:
+ builtins.elem (lib.getName pkg) cfg.unfreePackageNames;
+ };
+diff --git a/modules/by-name/nv/nvim/module.nix b/modules/by-name/nv/nvim/module.nix
+index e63c9565..17cc8dcc 100644
+--- a/modules/by-name/nv/nvim/module.nix
++++ b/modules/by-name/nv/nvim/module.nix
+@@ -45,7 +45,7 @@ in {
+ soispha.services.unison.pathsToSync = [
+ "~/.local/state/nvim"
+ ];
+- soispha.impermanence.userDiretories = [
++ vhack.persist.userDirectories.soispha = [
+ ".local/state/nvim"
+ ];
+
+diff --git a/modules/by-name/nv/nvim/plgs/lsp/servers/servers/ltex.nix b/modules/by-name/nv/nvim/plgs/lsp/servers/servers/ltex.nix
+index e55cf377..5c0024f0 100644
+--- a/modules/by-name/nv/nvim/plgs/lsp/servers/servers/ltex.nix
++++ b/modules/by-name/nv/nvim/plgs/lsp/servers/servers/ltex.nix
+@@ -10,6 +10,7 @@
+ {
+ config,
+ lib,
++ pkgs,
+ ...
+ }: let
+ cfg = config.soispha.programs.nvim;
+@@ -41,6 +42,7 @@ in {
+ ];
+ in {
+ enable = true;
++ package = pkgs.ltex-ls-plus;
+ inherit filetypes;
+ settings = {
+ enabled = filetypes;
+diff --git a/modules/by-name/ol/ollama/module.nix b/modules/by-name/ol/ollama/module.nix
+index f819c035..ebc1fbf9 100644
+--- a/modules/by-name/ol/ollama/module.nix
++++ b/modules/by-name/ol/ollama/module.nix
+@@ -19,7 +19,7 @@ in {
+ };
+
+ config = lib.mkIf cfg.enable {
+- soispha.impermanence.directories = [
++ vhack.persist.directories = [
+ # Set the mode to 700, so that it is private enough for systemd.
+ {
+ directory = "/var/lib/private";
+diff --git a/modules/by-name/pi/pipewire/module.nix b/modules/by-name/pi/pipewire/module.nix
+index df8eca0a..5bec816d 100644
+--- a/modules/by-name/pi/pipewire/module.nix
++++ b/modules/by-name/pi/pipewire/module.nix
+@@ -20,7 +20,7 @@ in {
+ };
+
+ config = lib.mkIf cfg.enable {
+- soispha.impermanence.userDirectories = [
++ vhack.persist.userDirectories.soispha = [
+ ".local/state/wireplumber"
+ ];
+ };
+diff --git a/modules/by-name/po/polkit/module.nix b/modules/by-name/po/polkit/module.nix
+index d8dd51b0..ae9dc775 100644
+--- a/modules/by-name/po/polkit/module.nix
++++ b/modules/by-name/po/polkit/module.nix
+@@ -21,6 +21,6 @@ in {
+ config = lib.mkIf cfg.enable {
+ security.polkit.enable = true;
+
+- users.groups.polkituser.gid = config.soispha.constants.ids.gids.polkituser;
++ users.groups.polkituser.gid = config.vhack.constants.ids.gids.polkituser;
+ };
+ }
+diff --git a/modules/by-name/pr/printing/module.nix b/modules/by-name/pr/printing/module.nix
+index 2e230570..bd554856 100644
+--- a/modules/by-name/pr/printing/module.nix
++++ b/modules/by-name/pr/printing/module.nix
+@@ -19,7 +19,7 @@ in {
+ };
+
+ config = lib.mkIf cfg.enable {
+- soispha.impermanence.directories = [
++ vhack.persist.directories = [
+ "/var/lib/cups"
+ ];
+
+@@ -31,9 +31,9 @@ in {
+ };
+
+ users = {
+- users.avahi.uid = config.soispha.constants.ids.uids.avahi;
+- groups.avahi.gid = config.soispha.constants.ids.gids.avahi;
+- groups.lpadmin.gid = config.soispha.constants.ids.gids.lpadmin;
++ users.avahi.uid = config.vhack.constants.ids.uids.avahi;
++ groups.avahi.gid = config.vhack.constants.ids.gids.avahi;
++ groups.lpadmin.gid = config.vhack.constants.ids.gids.lpadmin;
+ };
+
+ services.printing = {
+diff --git a/modules/by-name/ri/river/keymap.nix b/modules/by-name/ri/river/keymap.nix
+index feabf379..af16da26 100644
+--- a/modules/by-name/ri/river/keymap.nix
++++ b/modules/by-name/ri/river/keymap.nix
+@@ -5,7 +5,7 @@
+ config,
+ ...
+ }: let
+- index2tag = input: builtins.toString (libraries.base.pow 2 (input - 1));
++ index2tag = input: builtins.toString (extra_lib.math.pow 2 (input - 1));
+
+ mkTagCommand = name: index: [name (index2tag index)];
+ mkSpawn' = pkg: binaryName: args: further: (further
+@@ -94,7 +94,7 @@ in {
+ "T" = ["send-to-output" "next"];
+ "N" = ["send-to-output" "previous"];
+
+- "0" = ["set-view-tags" (builtins.toString ((libraries.base.pow 2 32) - 1))];
++ "0" = ["set-view-tags" (builtins.toString ((extra_lib.math.pow 2 32) - 1))];
+ "p" = ["send-to-previous-tags"];
+
+ "1" = mkTagCommand "set-view-tags" 1;
+@@ -132,7 +132,7 @@ in {
+ "T" = ["focus-output" "next"];
+ "N" = ["focus-output" "previous"];
+
+- "0" = ["set-focused-tags" (builtins.toString ((libraries.base.pow 2 32) - 1))];
++ "0" = ["set-focused-tags" (builtins.toString ((extra_lib.math.pow 2 32) - 1))];
+ "p" = ["focus-previous-tags"];
+
+ "1" = mkTagCommand "set-focused-tags" 1;
+diff --git a/modules/by-name/ri/river/module.nix b/modules/by-name/ri/river/module.nix
+index f9ecea0f..a381e897 100644
+--- a/modules/by-name/ri/river/module.nix
++++ b/modules/by-name/ri/river/module.nix
+@@ -12,7 +12,7 @@
+ lib,
+ system,
+ pkgs,
+- externalBinaries,
++ sources,
+ ...
+ }: let
+ cfg = config.soispha.programs.river;
+@@ -200,7 +200,7 @@ in {
+ ];
+
+ config = lib.mkIf cfg.enable {
+- services.udev.packages = lib.mkIf cfg.unicodeInput.enable [externalBinaries.qmk_firmware.packages.${system}.qmk_unicode_type];
++ services.udev.packages = lib.mkIf cfg.unicodeInput.enable [sources.qmk_firmware.packages.${system}.qmk_unicode_type];
+
+ home-manager.users.soispha = {
+ xdg.desktopEntries."river" = {
+diff --git a/modules/by-name/ro/rocie/module.nix b/modules/by-name/ro/rocie/module.nix
+index 1e419b82..54af3f40 100644
+--- a/modules/by-name/ro/rocie/module.nix
++++ b/modules/by-name/ro/rocie/module.nix
+@@ -1,11 +1,16 @@
+ {
+ config,
+ lib,
++ extra_modules,
+ ...
+ }: let
+ cfg = config.vhack.rocie;
+ data = "/var/lib/rocie";
+ in {
++ imports = [
++ extra_modules.nixos.rocie
++ ];
++
+ options.vhack.rocie = {
+ enable = lib.mkEnableOption "Rocie integration into vhack.eu";
+
+diff --git a/modules/by-name/si/signal/module.nix b/modules/by-name/si/signal/module.nix
+index e7cef901..4506517f 100644
+--- a/modules/by-name/si/signal/module.nix
++++ b/modules/by-name/si/signal/module.nix
+@@ -10,7 +10,7 @@ in {
+ enable = extra_lib.options.mkDefaultEnabled "signal";
+ };
+ config = lib.mkIf cfg.enable {
+- soispha.impermanence.userDirectories = [
++ vhack.persist.userDirectories.soispha = [
+ ".config/Signal"
+ ];
+ };
+diff --git a/modules/by-name/so/sound/module.nix b/modules/by-name/so/sound/module.nix
+index 67187ff3..732a78e2 100644
+--- a/modules/by-name/so/sound/module.nix
++++ b/modules/by-name/so/sound/module.nix
+@@ -32,8 +32,8 @@ in {
+ };
+
+ users = {
+- users.rtkit.uid = config.soispha.constants.ids.uids.rtkit;
+- groups.rtkit.gid = config.soispha.constants.ids.gids.rtkit;
++ users.rtkit.uid = config.vhack.constants.ids.uids.rtkit;
++ groups.rtkit.gid = config.vhack.constants.ids.gids.rtkit;
+ };
+
+ # TODO: Find a better way to set the default volume <2024-03-10>
+diff --git a/modules/by-name/ss/ssh/module.nix b/modules/by-name/ss/ssh/module.nix
+index 39c203fd..6926547e 100644
+--- a/modules/by-name/ss/ssh/module.nix
++++ b/modules/by-name/ss/ssh/module.nix
+@@ -29,53 +29,19 @@
+ in {
+ options.soispha.programs.ssh = {
+ enable = lib.mkEnableOption "ssh config";
+- rootKnownHosts = lib.mkOption {
+- type = lib.types.attrsOf lib.types.str;
+- description = ''
+- An attrset of keys (the domain) and values (the host key.)
+- These are only applied to the root user.
+- '';
+- default = {};
+- apply = value:
+- builtins.concatStringsSep "\n"
+- (lib.attrsets.mapAttrsToList (hostName: hostKey: "${hostName} ${hostKey}") value);
+- };
+ };
+
+ config = lib.mkIf cfg.enable {
+- home-manager.users = {
+- root.programs.ssh = {
+- enable = true;
+- enableDefaultConfig = false;
++ home-manager.users.soispha.programs.ssh = {
++ enable = true;
++ enableDefaultConfig = false;
+
+- settings = {
+- "Host *" = mkDefaultMatchBlock (
+- builtins.toString (pkgs.writeTextFile {
+- name = "root-known-hosts";
+- text = cfg.rootKnownHosts;
+- })
+- );
+- "Host *.your-storagebox.de" = {
+- # Don't try to authenticate via password for these, because we need to use the
+- # forced commands, and they are only provided via the ssh key login.
+- # So password login is a footgun (it is, however, valid to use it for non-root
+- # use-cases)
+- PasswordAuthentication = false;
+- };
+- };
+- };
+-
+- soispha.programs.ssh = {
+- enable = true;
+- enableDefaultConfig = false;
+-
+- settings = {
+- "Host *" = mkDefaultMatchBlock "${config.home-manager.users.soispha.xdg.dataHome}/ssh/known_hosts";
+- "Host *.your-storagebox.de" = {
+- # Port 22 is for sftp, and when we connect as user, we probably want an
+- # interactive shell.
+- Port = 23;
+- };
++ settings = {
++ "Host *" = mkDefaultMatchBlock "${config.home-manager.users.soispha.xdg.dataHome}/ssh/known_hosts";
++ "Host *.your-storagebox.de" = {
++ # Port 22 is for sftp, and when we connect as user, we probably want an
++ # interactive shell.
++ Port = 23;
+ };
+ };
+ };
+diff --git a/modules/by-name/us/users/module.nix b/modules/by-name/us/users/module.nix
+index 0f84b58b..b7f6297f 100644
+--- a/modules/by-name/us/users/module.nix
++++ b/modules/by-name/us/users/module.nix
+@@ -11,6 +11,8 @@
+ hashedPassword,
+ uid,
+ sshKey,
++ groups,
++ enableDeprecatedPlugdev,
+ }: {
+ inherit name;
+ value = {
+@@ -18,7 +20,7 @@
+ isNormalUser = true;
+ createHome = true;
+ home = "/home/${name}";
+- extraGroups = cfg.groups ++ lib.optional cfg.enableDeprecatedPlugdev "plugdev";
++ extraGroups = groups ++ lib.optional enableDeprecatedPlugdev "plugdev";
+ openssh.authorizedKeys.keys = [
+ sshKey
+ ];
+diff --git a/modules/by-name/wa/waydroid/module.nix b/modules/by-name/wa/waydroid/module.nix
+index a55ccf90..aa4e1911 100644
+--- a/modules/by-name/wa/waydroid/module.nix
++++ b/modules/by-name/wa/waydroid/module.nix
+@@ -21,7 +21,7 @@ in {
+ # FIXME: Running `waydroid session start` causes all fuse mounts instances to coredump <2023-09-02>
+ # Thus this setting must be false.
+ virtualisation.waydroid.enable = false;
+- soispha.impermanence.directories = [
++ vhack.persist.directories = [
+ "/var/lib/waydroid"
+ ];
+ };
+diff --git a/modules/by-name/xd/xdg/module.nix b/modules/by-name/xd/xdg/module.nix
+index 21f18874..92bb3059 100644
+--- a/modules/by-name/xd/xdg/module.nix
++++ b/modules/by-name/xd/xdg/module.nix
+@@ -49,7 +49,7 @@ in {
+ };
+
+ config = lib.mkIf cfg.enable {
+- soispha.impermanance.userDirectories = [
++ vhack.persist.userDirectories.soispha = [
+ ".local/share"
+ ".cache"
+
+diff --git a/modules/common/default.nix b/modules/common/soispha/default.nix
+similarity index 90%
+rename from modules/common/default.nix
+rename to modules/common/soispha/default.nix
+index facc9e9f..9d6038cb 100644
+--- a/modules/common/default.nix
++++ b/modules/common/soispha/default.nix
+@@ -17,19 +17,34 @@
+ }: {
+ # TODO(@bpeetz): Move this file to default options in their respective modules. <2025-05-31>
+
+- home-manager.users = {
+- soispha.home = {
+- username = "soispha";
+- homeDirectory = config.users.users.soispha.home;
+- stateVersion = "23.05";
+- enableNixpkgsReleaseCheck = true;
++ home-manager.users.soispha.home = {
++ username = "soispha";
++ homeDirectory = config.users.users.soispha.home;
++ stateVersion = "23.05";
++ enableNixpkgsReleaseCheck = true;
++ };
++
++ vhack = {
++ postgresql.enable = false;
++ persist = {
++ enable = true;
++
++ directories = [
++ "/etc/nixos"
++ "/var/lib/systemd"
++ "/var/log"
++ ];
+ };
+
+- root.home = {
+- username = "root";
+- homeDirectory = config.users.users.root.home;
+- stateVersion = "23.05";
+- enableNixpkgsReleaseCheck = true;
++ services.backup = {
++ storagebox = {
++ enable = lib.mkDefault true;
++ user = "u459143-sub1";
++ sshHostKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIICf9svRenC/PLKIL9nk6K/pxQgoiFC41wTNvoIncOxs";
++ };
++ local = {
++ enable = lib.mkDefault true;
++ };
+ };
+ };
+
+@@ -48,14 +63,6 @@
+ enable = lib.mkDefault true;
+ };
+ home-manager.enable = true;
+- impermanence = {
+- enable = true;
+-
+- directories = [
+- "/etc/nixos"
+- "/var/lib/systemd"
+- ];
+- };
+
+ polkit.enable = true;
+ xdg.enable = true;
+@@ -65,15 +72,6 @@
+ enable = true;
+ user = "soispha";
+ };
+- backup = {
+- storagebox = {
+- enable = lib.mkDefault true;
+- user = "u459143-sub1";
+- };
+- local = {
+- enable = lib.mkDefault true;
+- };
+- };
+ fwupd.enable = true;
+ mako.enable = true;
+ mpd = {
+@@ -92,7 +90,6 @@
+ };
+ };
+ ollama.enable = false;
+- postgresql.enable = false;
+ printing.enable = true;
+ scanning.enable = true;
+ snapper.enable = true;
+diff --git a/modules/common/hooks/default.nix b/modules/common/soispha/hooks/default.nix
+similarity index 100%
+rename from modules/common/hooks/default.nix
+rename to modules/common/soispha/hooks/default.nix
+diff --git a/modules/common/hooks/scripts/sync-git-repo.sh b/modules/common/soispha/hooks/scripts/sync-git-repo.sh
+similarity index 100%
+rename from modules/common/hooks/scripts/sync-git-repo.sh
+rename to modules/common/soispha/hooks/scripts/sync-git-repo.sh
+diff --git a/modules/common/projects.json b/modules/common/soispha/projects.json
+similarity index 100%
+rename from modules/common/projects.json
+rename to modules/common/soispha/projects.json
+diff --git a/modules/common/projects.json.license b/modules/common/soispha/projects.json.license
+similarity index 100%
+rename from modules/common/projects.json.license
+rename to modules/common/soispha/projects.json.license
+--
+2.55.0
+
diff --git a/pkgs/by-name/ro/rollup/patches2/0006-lib-Merge-with-the-extraLib.patch b/pkgs/by-name/ro/rollup/patches2/0006-lib-Merge-with-the-extraLib.patch
new file mode 100644
index 00000000..1cca069c
--- /dev/null
+++ b/pkgs/by-name/ro/rollup/patches2/0006-lib-Merge-with-the-extraLib.patch
@@ -0,0 +1,145 @@
+From b30b9eed670d9f02eccb1120f18cbf084caf32f0 Mon Sep 17 00:00:00 2001
+From: Benedikt Peetz <benedikt.peetz@b-peetz.de>
+Date: Mon, 2 Nov 2026 19:56:15 +0100
+Subject: [PATCH 6/7] lib: Merge with the `extraLib`
+
+---
+ lib/default.nix | 126 ------------------------------------------------
+ 1 file changed, 126 deletions(-)
+ delete mode 100644 lib/default.nix
+
+diff --git a/lib/default.nix b/lib/default.nix
+deleted file mode 100644
+index 1cdbf936..00000000
+--- a/lib/default.nix
++++ /dev/null
+@@ -1,126 +0,0 @@
+-# nixos-config - My current NixOS configuration
+-#
+-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
+-# SPDX-License-Identifier: GPL-3.0-or-later
+-#
+-# This file is part of my nixos-config.
+-#
+-# You should have received a copy of the License along with this program.
+-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
+-{lib}: rec {
+- /*
+- Converts `number` from a binary number to a decimal one.
+-
+- The input is indented to be a number composed only of `1`s and `0` (e.g., 10010.)
+-
+- # Type
+-
+- binaryToDecimal :: Int -> Int
+-
+- # Arguments
+-
+- number
+- : The sequence of `1`s and `0`s defining a binary number, in little endian.
+-
+- # Examples
+-
+- binaryToDecimal 1001
+- => 9
+- */
+- binaryToDecimal = number: let
+- binaryList =
+- builtins.map lib.strings.toInt (lib.lists.reverseList (lib.strings.stringToCharacters (builtins.toString number)));
+- in
+- builtins.foldl' (acc: num: acc + num) 0
+- (lib.lists.imap0 (index: elem: elem * (pow 2 index)) binaryList);
+-
+- /*
+- Converts `string` to a (probably) unique numerical id.
+-
+- This is achieved by hashing the string and returning the first six hex-digits
+- converted to a base 10 number.
+-
+- # Type
+-
+- idFromString :: String -> Int
+-
+- # Arguments
+-
+- string
+- : The string to use as seed for the id generation.
+-
+- # Examples
+-
+- idFromString "3d-printer"
+- => 10365713
+- */
+- idFromString = string: let
+- inputSeed =
+- builtins.concatStringsSep ""
+- (lib.lists.take 6
+- (lib.strings.stringToCharacters (builtins.hashString "sha256" string)));
+- in
+- lib.trivial.fromHexString inputSeed;
+-
+- /*
+- source: https://github.com/NixOS/nix/issues/10387#issuecomment-2494597690
+-
+- Raises the `base` to the power of `power`.
+-
+- Considering the small input size and the lack of a built-in power function [2],
+- this naive power implementation should satisfy reasonable performance
+- requirements.
+-
+- Due to the lack of a modulo and bitwise AND operator, it is questionable whether
+- the recursive exponentiation by squaring [1] implementation would even be
+- faster.
+-
+- [1]: https://en.wikipedia.org/wiki/Exponentiation_by_squaring
+- [2]: https://github.com/NixOS/nix/issues/10387
+-
+- # Type
+-
+- pow :: Number -> Number -> Number
+-
+- # Arguments
+-
+- base
+- : The base number to be raised.
+-
+- power
+- : The exponent to raise `base` to.
+-
+- # Examples
+-
+- pow 2 5
+- => 32
+- */
+- pow = base: power:
+- if power == 0
+- then 1
+- else if power > 0
+- then (base * (pow base (power - 1)))
+- else builtins.throw "Negative powers are not supported";
+-
+- options = {
+- /*
+- Generate an enable option definition, that defaults to true.
+-
+- This conveniently allows the composition of a “common” module set.
+-
+- # Type
+-
+- mkEnable :: String -> AttrSet
+-
+- # Arguments
+-
+- name
+- : The name to use in the option description.
+- */
+- mkEnable = name:
+- (lib.mkEnableOption name)
+- // {
+- default = true;
+- };
+- };
+-}
+--
+2.55.0
+
diff --git a/pkgs/by-name/ro/rollup/patches2/0007-flake.nix-Don-t-perform-source-mapping-via-sources-a.patch b/pkgs/by-name/ro/rollup/patches2/0007-flake.nix-Don-t-perform-source-mapping-via-sources-a.patch
new file mode 100644
index 00000000..83b4beaa
--- /dev/null
+++ b/pkgs/by-name/ro/rollup/patches2/0007-flake.nix-Don-t-perform-source-mapping-via-sources-a.patch
@@ -0,0 +1,65 @@
+From d0ff20e0e24023c120f47cc3a7b9782152daaa19 Mon Sep 17 00:00:00 2001
+From: Benedikt Peetz <benedikt.peetz@b-peetz.de>
+Date: Mon, 2 Nov 2026 19:56:49 +0100
+Subject: [PATCH 7/7] flake.nix: Don't perform source mapping via sources and
+ raw_sources
+
+---
+ flake.nix | 16 +++++++---------
+ 1 file changed, 7 insertions(+), 9 deletions(-)
+
+diff --git a/flake.nix b/flake.nix
+index 860ce277..9b729bd0 100644
+--- a/flake.nix
++++ b/flake.nix
+@@ -4,16 +4,13 @@
+ inputs = {};
+
+ outputs = {self, ...}: let
+- raw_sources = import ./unflake.nix;
++ sources = import ./unflake.nix;
+
+ system = "x86_64-linux";
+
+- # Filter out the nixpkgs's from the sources, so we always use the `packageSets`.
+- sources = builtins.removeAttrs raw_sources ["nixpkgs-stable" "nixpkgs-unstable" "library"];
+-
+ packageSets = rec {
+- stable = raw_sources.nixpkgs-stable.legacyPackages.${system};
+- unstable = raw_sources.nixpkgs-unstable.legacyPackages.${system};
++ stable = sources.nixpkgs-stable.legacyPackages.${system};
++ unstable = sources.nixpkgs-unstable.legacyPackages.${system};
+
+ in_tree = import ./pkgs {
+ unstable_pkgs = unstable;
+@@ -22,7 +19,7 @@
+ };
+ };
+ lib = packageSets.unstable.lib;
+- extra_lib = raw_sources.library.nixLib;
++ extra_lib = sources.library.extraLib {inherit lib;};
+
+ extra_modules = {
+ nixos = {
+@@ -37,7 +34,8 @@
+ };
+ home = {
+ nix-index-database = sources.nix-index-database.homeModules.nix-index;
+- nixvim = sources.nixvim.homeManagerModule;
++ nixvim = sources.nixvim.homeModules.nixvim;
++ turtle = sources.turtle.nixosModules.home-manager;
+ };
+ };
+ module_args = {
+@@ -76,7 +74,7 @@
+ system
+ ;
+ inherit
+- (raw_sources)
++ (sources)
+ nixpkgs-unstable
+ nixpkgs-stable
+ deploy-rs
+--
+2.55.0
+
diff --git a/pkgs/by-name/ro/rollup/src/main.rs b/pkgs/by-name/ro/rollup/src/main.rs
new file mode 100644
index 00000000..8285e702
--- /dev/null
+++ b/pkgs/by-name/ro/rollup/src/main.rs
@@ -0,0 +1,106 @@
+use core::fmt;
+use std::{path::PathBuf, process::Command};
+
+use anyhow::{Context, Result};
+use clap::Parser;
+
+#[derive(Parser)]
+struct Cli {
+ /// The file to pull the patch to rollup from.
+ patch_file: PathBuf,
+}
+
+struct Diff {
+ files: Vec<FileDiff>,
+}
+
+struct FileDiff {
+ from: PathBuf,
+ to: PathBuf,
+ diff: String,
+ index: String,
+}
+
+impl fmt::Display for FileDiff {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ writeln!(
+ f,
+ "diff --git a/{} b/{}",
+ self.from.display(),
+ self.to.display()
+ )?;
+ writeln!(f, "--- a/{}", self.from.display())?;
+ writeln!(f, "+++ b/{}", self.to.display())?;
+ writeln!(f, "index {}", self.index)?;
+ writeln!(f, "{}", self.diff)?;
+
+ Ok(())
+ }
+}
+
+macro_rules! take {
+ ($line:expr, $prefix:literal) => {
+ $line.strip_prefix($prefix).unwrap().trim()
+ };
+}
+
+fn main() -> Result<()> {
+ let args = Cli::parse();
+
+ let data = Command::new("filterdiff")
+ .arg(&args.patch_file)
+ .output()
+ .context("Failed to run `filterdiff` for patch analysis")?;
+
+ let stdout = String::from_utf8(data.stdout).unwrap();
+
+ let mut diff = Diff { files: vec![] };
+ let mut file_diff_from = None;
+ let mut file_diff_to = None;
+ let mut file_diff_diff: Option<String> = None;
+ let mut file_diff_index: Option<String> = None;
+ for (idx, line) in stdout.lines().enumerate() {
+ eprintln!("{}", line);
+
+ if line.starts_with("---") {
+ file_diff_from = Some(PathBuf::from(take!(line, "--- a/")));
+ } else if line.starts_with("+++") {
+ file_diff_to = Some(PathBuf::from(take!(line, "+++ b/")));
+ } else if line.starts_with("index") {
+ file_diff_index = Some(take!(line, "index").to_owned());
+ } else if line.starts_with("diff --git") {
+ if idx != 0 {
+ diff.files.push(FileDiff {
+ from: file_diff_from.take().unwrap(),
+ to: file_diff_to.take().unwrap(),
+ diff: file_diff_diff.take().unwrap(),
+ index: file_diff_index.take().unwrap(),
+ });
+ }
+ } else {
+ match file_diff_diff.as_mut() {
+ Some(str) => {
+ str.push_str(line);
+ str.push('\n');
+ }
+ None => {
+ let mut base = line.to_owned();
+ base.push('\n');
+ file_diff_diff = Some(base);
+ }
+ }
+ }
+ }
+ diff.files.push(FileDiff {
+ from: file_diff_from.unwrap(),
+ to: file_diff_to.unwrap(),
+ diff: file_diff_diff.unwrap(),
+ index: file_diff_index.unwrap(),
+ });
+
+ for file in diff.files {
+ eprintln!("{}", file)
+ }
+
+ Ok(())
+}
diff --git a/pkgs/by-name/ro/rollup/update.sh b/pkgs/by-name/ro/rollup/update.sh
new file mode 100755
index 00000000..5aedf3b3
--- /dev/null
+++ b/pkgs/by-name/ro/rollup/update.sh
@@ -0,0 +1,14 @@
+#!/usr/bin/env sh
+
+# Mpdpopm - A mpd rating tracker
+#
+# Copyright (C) 2026 Benedikt Peetz, Michael Herstine <sp1ff@pobox.com> <benedikt.peetz@b-peetz.de, sp1ff@pobox.com>
+# SPDX-License-Identifier: AGPL-3.0-or-later
+#
+# This file is part of Mpdpopm.
+#
+# You should have received a copy of the License along with this program.
+# If not, see <https://www.gnu.org/licenses/agpl.txt>.
+
+[ "$1" = "upgrade" ] && cargo upgrade --incompatible allow --pinned allow --recursive true
+cargo update --recursive