diff --git a/flake.lock b/flake.lock
new file mode 100644
index 000000000..937db8871
--- /dev/null
+++ b/flake.lock
@@ -0,0 +1,44 @@
+{
+  "nodes": {
+    "nix-writers": {
+      "flake": false,
+      "locked": {
+        "lastModified": 1677612737,
+        "narHash": "sha256-UaCKZ4PbMZU6UZH7XNFcjRtd5jheswl66rjZDBfQgp8=",
+        "ref": "refs/heads/master",
+        "rev": "66a1f6833464bbb121b6d94247ad769f277351f8",
+        "revCount": 39,
+        "type": "git",
+        "url": "https://cgit.krebsco.de/nix-writers"
+      },
+      "original": {
+        "type": "git",
+        "url": "https://cgit.krebsco.de/nix-writers"
+      }
+    },
+    "nixpkgs": {
+      "locked": {
+        "lastModified": 1686135559,
+        "narHash": "sha256-pY8waAV8K/sbHBdLn5diPFnQKpNg0YS9w03MrD2lUGE=",
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "rev": "381e92a35e2d196fdd6077680dca0cd0197e75cb",
+        "type": "github"
+      },
+      "original": {
+        "owner": "NixOS",
+        "ref": "nixos-unstable",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
+    "root": {
+      "inputs": {
+        "nix-writers": "nix-writers",
+        "nixpkgs": "nixpkgs"
+      }
+    }
+  },
+  "root": "root",
+  "version": 7
+}
diff --git a/flake.nix b/flake.nix
new file mode 100644
index 000000000..6c094b6a9
--- /dev/null
+++ b/flake.nix
@@ -0,0 +1,41 @@
+{
+  inputs = {
+    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
+    nix-writers = {
+      url = "git+https://cgit.krebsco.de/nix-writers";
+      flake = false;
+    };
+    # disko.url = "github:nix-community/disko";
+    # disko.inputs.nixpkgs.follows = "nixpkgs";
+  };
+
+  description = "stockholm";
+
+  outputs = { self, nixpkgs, nix-writers }: {
+    nixosConfigurations.hotdog = nixpkgs.lib.nixosSystem {
+      system = "x86_64-linux";
+      specialArgs.stockholm = self;
+      specialArgs.nix-writers = nix-writers;
+      specialArgs.secrets = toString ./krebs/0tests/data/secrets;
+      modules = [
+        ./krebs/1systems/hotdog/config.nix
+      ];
+    };
+
+    nixosModules =
+    let
+      inherit (nixpkgs) lib;
+    in builtins.listToAttrs
+      (map
+        (name: {name = lib.removeSuffix ".nix" name; value = import (./krebs/3modules + "/${name}");})
+        (lib.filter
+          (name: name != "default.nix" && !lib.hasPrefix "." name)
+          (lib.attrNames (builtins.readDir ./krebs/3modules))));
+
+    kartei = {
+      hosts = self.nixosConfigurations.hotdog.config.krebs.hosts;
+      users = self.nixosConfigurations.hotdog.config.krebs.users;
+    };
+    lib = import (self.outPath + "/lib/pure.nix") { lib = nixpkgs.lib; };
+  };
+}
diff --git a/kartei/0x4A6F/default.nix b/kartei/0x4A6F/default.nix
index 8939f267d..eb3d08e8d 100644
--- a/kartei/0x4A6F/default.nix
+++ b/kartei/0x4A6F/default.nix
@@ -1,12 +1,13 @@
-with import ../../lib;
-{ config, ... }: let
+{ config, lib, ... }: let
+  inherit (lib) flip mapAttrs optionalAttrs recursiveUpdate;
+  slib = import ../../lib/pure.nix { inherit lib; };
   hostDefaults = hostName: host: flip recursiveUpdate host ({
     ci = false;
     external = true;
     monitoring = false;
   } // optionalAttrs (host.nets?retiolum) {
     nets.retiolum.ip6.addr =
-      (krebs.genipv6 "retiolum" "external" { inherit hostName; }).address;
+      (slib.krebs.genipv6 "retiolum" "external" { inherit hostName; }).address;
   });
 in {
   users = {
diff --git a/kartei/dave/default.nix b/kartei/dave/default.nix
index 053ec412b..04f226cc1 100644
--- a/kartei/dave/default.nix
+++ b/kartei/dave/default.nix
@@ -1,5 +1,5 @@
-{ config, ... }: let
-  lib = import ../../lib;
+{ config, lib, ... }: let
+  slib = import ../../lib/pure.nix { inherit lib; };
 in {
   users.dave = {
     mail = "hsngrmpf@gmail.com";
@@ -8,7 +8,7 @@ in {
     owner = config.krebs.users.dave;
     nets.retiolum = {
       aliases = [ "dave.r" ];
-      ip6.addr = (lib.krebs.genipv6 "retiolum" "dave" { hostName = "dave"; }).address;
+      ip6.addr = (slib.krebs.genipv6 "retiolum" "dave" { hostName = "dave"; }).address;
       ip4.addr = "10.243.0.6";
       tinc.pubkey = ''
         -----BEGIN RSA PUBLIC KEY-----
diff --git a/kartei/dbalan/default.nix b/kartei/dbalan/default.nix
index fadf187db..6bf10b921 100644
--- a/kartei/dbalan/default.nix
+++ b/kartei/dbalan/default.nix
@@ -1,6 +1,7 @@
-with import ../../lib;
-{ config, ... }:
+{ config, lib, ... }:
 let
+  inherit (lib) flip mapAttrs optionalAttrs recursiveUpdate;
+  slib = import ../../lib/pure.nix { inherit lib; };
   hostDefaults = hostName: host: flip recursiveUpdate host ({
     ci = false;
     external = true;
@@ -8,11 +9,11 @@ let
     owner = config.krebs.users.dbalan;
   } // optionalAttrs (host.nets?retiolum) {
     nets.retiolum = {
-      ip6.addr = (krebs.genipv6 "retiolum" "external" { inherit hostName; }).address;
+      ip6.addr = (slib.krebs.genipv6 "retiolum" "external" { inherit hostName; }).address;
     };
   } // optionalAttrs (host.nets?wiregrill) {
     nets.wiregrill = {
-      ip6.addr = (krebs.genipv6 "wiregrill" "external" { inherit hostName; }).address;
+      ip6.addr = (slib.krebs.genipv6 "wiregrill" "external" { inherit hostName; }).address;
     };
   });
 in
diff --git a/kartei/default.nix b/kartei/default.nix
index 6024e2351..046efdd7b 100644
--- a/kartei/default.nix
+++ b/kartei/default.nix
@@ -9,7 +9,7 @@ in {
         (name: _type: let
           path = ./. + "/${name}";
         in {
-          krebs = import path { inherit config; };
+          krebs = import path { inherit config lib; };
         })
         (removeTemplate
           (lib.filterAttrs
diff --git a/kartei/feliks/default.nix b/kartei/feliks/default.nix
index e98da7bc6..96c20f602 100644
--- a/kartei/feliks/default.nix
+++ b/kartei/feliks/default.nix
@@ -1,5 +1,6 @@
-with import ../../lib;
-{ config, ... }: let
+{ config, lib, ... }: let
+  inherit (lib) flip mapAttrs optionalAttrs recursiveUpdate;
+  slib = import ../../lib/pure.nix { inherit lib; };
   hostDefaults = hostName: host: flip recursiveUpdate host ({
     owner = config.krebs.users.feliks;
     ci = false;
@@ -7,10 +8,10 @@ with import ../../lib;
     monitoring = false;
   } // optionalAttrs (host.nets?retiolum) {
     nets.retiolum.ip6.addr =
-      (krebs.genipv6 "retiolum" "external" { inherit hostName; }).address;
+      (slib.krebs.genipv6 "retiolum" "external" { inherit hostName; }).address;
   } // optionalAttrs (host.nets?wiregrill) {
     nets.wiregrill.ip6.addr =
-      (krebs.genipv6 "wiregrill" "external" { inherit hostName; }).address;
+      (slib.krebs.genipv6 "wiregrill" "external" { inherit hostName; }).address;
   });
 in {
   users.feliks = {
diff --git a/kartei/jan/default.nix b/kartei/jan/default.nix
index 6b90cfdc4..2276758b6 100644
--- a/kartei/jan/default.nix
+++ b/kartei/jan/default.nix
@@ -1,5 +1,5 @@
-{ config, ... }: let
-  lib = import ../../lib;
+{ config, lib, ... }: let
+  slib = import ../../lib/pure.nix { inherit lib; };
 in {
 
   users.jan = {
@@ -68,7 +68,7 @@ in {
     nets.retiolum = {
       aliases = [ "grill.r" ];
       ip4.addr = "10.243.217.217";
-      ip6.addr = (lib.krebs.genipv6 "retiolum" "jan" { hostName = "grill"; }).address;
+      ip6.addr = (slib.krebs.genipv6 "retiolum" "jan" { hostName = "grill"; }).address;
       tinc.pubkey = ''
         -----BEGIN RSA PUBLIC KEY-----
         MIICCgKCAgEAs4P6CfRcwFGCqkfv1tyTbbk2eHh08kEqxPNQ655sMKWxMhgRnRII
diff --git a/kartei/jeschli/default.nix b/kartei/jeschli/default.nix
index fe12c16a4..a53ff7a22 100644
--- a/kartei/jeschli/default.nix
+++ b/kartei/jeschli/default.nix
@@ -1,12 +1,12 @@
-with import ../../lib;
-{ config, ... }: let
-
+{ config, lib, ... }: let
+  inherit (lib) flip mapAttrs optionalAttrs recursiveUpdate;
+  slib = import ../../lib/pure.nix { inherit lib; };
   hostDefaults = hostName: host: flip recursiveUpdate host ({
     ci = true;
     owner = config.krebs.users.jeschli;
   } // optionalAttrs (host.nets?retiolum) {
     nets.retiolum.ip6.addr =
-      (krebs.genipv6 "retiolum" "jeschli" { inherit hostName; }).address;
+      (slib.krebs.genipv6 "retiolum" "jeschli" { inherit hostName; }).address;
   });
 
 in {
diff --git a/kartei/kmein/default.nix b/kartei/kmein/default.nix
index 1a5a57d1a..b096e2843 100644
--- a/kartei/kmein/default.nix
+++ b/kartei/kmein/default.nix
@@ -1,6 +1,7 @@
-with import ../../lib;
-{ config, ... }:
+{ config, lib, ... }:
 let
+  inherit (lib) flip mapAttrs optionalAttrs recursiveUpdate;
+  slib = import ../../lib/pure.nix { inherit lib; };
   maybeEmpty = attrset: key: if (attrset?key) then attrset.${key} else [];
   hostDefaults = hostName: host: flip recursiveUpdate host ({
     ci = false;
@@ -9,11 +10,11 @@ let
     owner = config.krebs.users.kmein;
   } // optionalAttrs (host.nets?retiolum) {
     nets.retiolum = {
-      ip6.addr = (krebs.genipv6 "retiolum" "external" { inherit hostName; }).address;
+      ip6.addr = (slib.krebs.genipv6 "retiolum" "external" { inherit hostName; }).address;
     };
   } // optionalAttrs (host.nets?wiregrill) {
     nets.wiregrill = {
-      ip6.addr = (krebs.genipv6 "wiregrill" "external" { inherit hostName; }).address;
+      ip6.addr = (slib.krebs.genipv6 "wiregrill" "external" { inherit hostName; }).address;
     };
   });
   ssh-for = name: builtins.readFile (./ssh + "/${name}.pub");
diff --git a/kartei/krebs/default.nix b/kartei/krebs/default.nix
index 414b66e9f..8a12d6f24 100644
--- a/kartei/krebs/default.nix
+++ b/kartei/krebs/default.nix
@@ -1,11 +1,12 @@
-with import ../../lib;
-{ config, ... }: let
+{ config, lib, ... }: let
+  inherit (lib) flip genAttrs mapAttrs optionalAttrs recursiveUpdate;
+  slib = import ../../lib/pure.nix { inherit lib; };
 
   hostDefaults = hostName: host: flip recursiveUpdate host ({
     owner = config.krebs.users.krebs;
   } // optionalAttrs (host.nets?retiolum) {
     nets.retiolum.ip6.addr =
-      (krebs.genipv6 "retiolum" "krebs" { inherit hostName; }).address;
+      (slib.krebs.genipv6 "retiolum" "krebs" { inherit hostName; }).address;
   });
 
   testHosts = genAttrs [
@@ -66,7 +67,6 @@ in {
           tinc.pubkey_ed25519 = "D5TYSZW9OAkdnvQ/NL98UgheRC2Zg4SMNZ8M4/KwdeL";
         };
       };
-      ssh.privkey.path = <secrets/ssh.id_ed25519>;
       ssh.pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKRpjW68lSlTL8jBQcXKOTdGa+olQw5ghaU5df2yAE64";
     };
     hotdog = {
@@ -100,7 +100,6 @@ in {
           tinc.pubkey_ed25519 = "ugy/sGReVro3YzjDuroV/5hdeBdqD18no9dMhTy9DYL";
         };
       };
-      ssh.privkey.path = <secrets/ssh.id_ed25519>;
       ssh.pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICxFkBln23wUxt4RhIHE3GvdKeBpJbjn++6maupHqUHp";
     };
     news = {
@@ -133,7 +132,6 @@ in {
           '';
         };
       };
-      ssh.privkey.path = <secrets/ssh.id_ed25519>;
       ssh.pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHl5cDF9QheXyMlNYIX17ILbgd94K50fZy7w0fDLvZlo ";
     };
     onebutton = {
@@ -161,7 +159,6 @@ in {
           '';
         };
       };
-      ssh.privkey.path = <secrets/ssh.id_ed25519>;
       ssh.pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAcZg+iLaPZ0SpLM+nANxIjZC/RIsansjyutK0+gPhIe ";
     };
     ponte = {
@@ -208,7 +205,6 @@ in {
           };
         };
       };
-      ssh.privkey.path = <secrets/ssh.id_ed25519>;
       ssh.pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJEw9fo8Qtb/DTLacdrJP7Ti7c4UXTm6wUUX+iRFweEo ";
     };
     puyak = {
@@ -234,7 +230,6 @@ in {
           '';
         };
       };
-      ssh.privkey.path = <secrets/ssh.id_ed25519>;
       ssh.pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPpVwKv9mQGfcn5oFwuitq+b6Dz4jBG9sGhVoCYFw5RY";
       syncthing.id = "DK5CEE2-PNUXYCE-Q42H2HP-623GART-B7KS4VK-HU2RBGQ-EK6QPUP-HUL3PAR";
     };
@@ -259,7 +254,6 @@ in {
           '';
         };
       };
-      ssh.privkey.path = <secrets/ssh.id_ed25519>;
       ssh.pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOu6EVN3928qWiWszqBUzOjeQJRvFozTBl4xAhBP/Ymc";
     };
     wolf = {
@@ -296,7 +290,6 @@ in {
           '';
         };
       };
-      ssh.privkey.path = <secrets/ssh.id_ed25519>;
       ssh.pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKYMXMWZIK0jjnZDM9INiYAKcwjXs2241vew54K8veCR";
     };
   } // testHosts);
diff --git a/kartei/lass/default.nix b/kartei/lass/default.nix
index de776fca0..e5b12f1cb 100644
--- a/kartei/lass/default.nix
+++ b/kartei/lass/default.nix
@@ -1,8 +1,8 @@
-with import ../../lib;
-{ config, ... }: let
+{ config, lib, ... }: let
+  slib = import ../../lib/pure.nix { inherit lib; };
 
-  r6 = ip: (krebs.genipv6 "retiolum" "lass" ip).address;
-  w6 = ip: (krebs.genipv6 "wiregrill" "lass" ip).address;
+  r6 = ip: (slib.krebs.genipv6 "retiolum" "lass" ip).address;
+  w6 = ip: (slib.krebs.genipv6 "wiregrill" "lass" ip).address;
   hostFiles =
     builtins.map (lib.removeSuffix ".nix") (
       builtins.filter
@@ -14,14 +14,17 @@ in {
   dns.providers = {
     "lassul.us" = "zones";
   };
-  hosts = mapAttrs (_: recursiveUpdate {
+  hosts = lib.mapAttrs (_: lib.recursiveUpdate {
     owner = config.krebs.users.lass;
     consul = true;
     ci = true;
     monitoring = true;
     ssh.privkey.path = <secrets/ssh.id_ed25519>;
   }) (
-    lib.genAttrs hostFiles (host: import (./. + "/${host}.nix") { inherit config krebs lib r6 w6; })
+    lib.genAttrs hostFiles (host: import (./. + "/${host}.nix") {
+      inherit config lib r6 w6;
+      inherit (slib) krebs;
+    })
   );
   users = rec {
     lass = lass-yubikey;
diff --git a/kartei/makefu/default.nix b/kartei/makefu/default.nix
index f98521e25..bf50d6a62 100644
--- a/kartei/makefu/default.nix
+++ b/kartei/makefu/default.nix
@@ -2,8 +2,10 @@
 # tinc generate-keys
 # ssh-keygen -f ssh.id_ed25519 -t ed25519 -C host
 
-with import ../../lib;
-{ config, ... }: let
+{ config, lib, ... }: let
+  inherit (builtins) foldl' mapAttrs pathExists readFile;
+  inherit (lib) optionalAttrs recursiveUpdate;
+  slib = import ../../lib/pure.nix { inherit lib; };
 
   hostDefaults = hostName: host: foldl' recursiveUpdate {} [
     {
@@ -19,7 +21,7 @@ with import ../../lib;
           "${hostName}.r"
         ];
         ip6.addr =
-          (krebs.genipv6 "retiolum" "makefu" { inherit hostName; }).address;
+          (slib.krebs.genipv6 "retiolum" "makefu" { inherit hostName; }).address;
       };
     })
     # Retiolum ed25519 keys
@@ -37,7 +39,7 @@ with import ../../lib;
           "${hostName}.w"
         ];
         ip6.addr =
-          (krebs.genipv6 "wiregrill" "makefu" { inherit hostName; }).address;
+          (slib.krebs.genipv6 "wiregrill" "makefu" { inherit hostName; }).address;
         wireguard.pubkey = readFile pubkey-path;
       };
     })
@@ -54,7 +56,7 @@ with import ../../lib;
   ];
 
   pub-for = name: builtins.readFile (./ssh + "/${name}.pub");
-  w6 = ip: (krebs.genipv6 "wiregrill" "makefu" ip).address;
+  w6 = ip: (slib.krebs.genipv6 "wiregrill" "makefu" ip).address;
 in {
   hosts = mapAttrs hostDefaults {
     cake = rec {
@@ -156,7 +158,7 @@ in {
     # pixel3a
     telex.nets.wiregrill = {
       aliases =  ["telex.w"];
-      ip6.addr = (krebs.genipv6 "wiregrill" "makefu" { hostName = "telex"; }).address;
+      ip6.addr = (slib.krebs.genipv6 "wiregrill" "makefu" { hostName = "telex"; }).address;
       ip4.addr = "10.244.245.4";
     };
 
@@ -263,7 +265,7 @@ in {
           ip6.addr = w6 "1";
           wireguard.port = 51821;
           wireguard.subnets = [
-              (krebs.genipv6 "wiregrill" "makefu" 0).subnetCIDR
+              (slib.krebs.genipv6 "wiregrill" "makefu" 0).subnetCIDR
               "10.244.245.0/24" # required for routing directly to gum via rockit
           ];
         };
diff --git a/kartei/mic92/default.nix b/kartei/mic92/default.nix
index 003c66c66..5b9d41413 100644
--- a/kartei/mic92/default.nix
+++ b/kartei/mic92/default.nix
@@ -1,12 +1,13 @@
-with import ../../lib;
-{ config, ... }: let
+{ config, lib, ... }: let
+  inherit (lib) flip mapAttrs optionalAttrs recursiveUpdate;
+  slib = import ../../lib/pure.nix { inherit lib; };
   hostDefaults = hostName: host: flip recursiveUpdate host ({
     ci = false;
     external = true;
     monitoring = false;
   } // optionalAttrs (host.nets?retiolum) {
     nets.retiolum.ip6.addr =
-      (krebs.genipv6 "retiolum" "external" { inherit hostName; }).address;
+      (slib.krebs.genipv6 "retiolum" "external" { inherit hostName; }).address;
   });
 in {
   hosts = mapAttrs hostDefaults {
diff --git a/kartei/others/default.nix b/kartei/others/default.nix
index 68097cdf8..fc4f8644d 100644
--- a/kartei/others/default.nix
+++ b/kartei/others/default.nix
@@ -1,5 +1,6 @@
-with import ../../lib;
-{ config, ... }: let
+{ config, lib, ... }: let
+  inherit (lib) flip mapAttrs optionalAttrs recursiveUpdate;
+  slib = import ../../lib/pure.nix { inherit lib; };
 
   hostDefaults = hostName: host: flip recursiveUpdate host ({
     ci = false;
@@ -7,10 +8,10 @@ with import ../../lib;
     monitoring = false;
   } // optionalAttrs (host.nets?retiolum) {
     nets.retiolum.ip6.addr =
-      (krebs.genipv6 "retiolum" "external" { inherit hostName; }).address;
+      (slib.krebs.genipv6 "retiolum" "external" { inherit hostName; }).address;
   } // optionalAttrs (host.nets?wiregrill) {
     nets.wiregrill.ip6.addr =
-      (krebs.genipv6 "wiregrill" "external" { inherit hostName; }).address;
+      (slib.krebs.genipv6 "wiregrill" "external" { inherit hostName; }).address;
   });
   ssh-for = name: builtins.readFile (./ssh + "/${name}.pub");
   tinc-for = name: builtins.readFile (./tinc + "/${name}.pub");
diff --git a/kartei/oxzi/default.nix b/kartei/oxzi/default.nix
index a4d23b01a..a1b5a766d 100644
--- a/kartei/oxzi/default.nix
+++ b/kartei/oxzi/default.nix
@@ -1,5 +1,5 @@
-{ config, ... }: let
-  lib = import ../../lib;
+{ config, lib, ... }: let
+  slib = import ../../lib/pure.nix { inherit lib; };
 in {
   users.oxzi = {
     mail = "post@0x21.biz";
@@ -13,7 +13,7 @@ in {
           "gosh.r"
         ];
         ip4.addr = "10.243.32.1";
-        ip6.addr = (lib.krebs.genipv6 "retiolum" "oxzi" { hostName = "ancha"; }).address;
+        ip6.addr = (slib.krebs.genipv6 "retiolum" "oxzi" { hostName = "ancha"; }).address;
         tinc.pubkey = ''
           -----BEGIN RSA PUBLIC KEY-----
           MIICCgKCAgEA5RSP7nWZ1c04kvQBxoHqcdRKpJuRDzD3f0Nl2KhS7QsAqHJGdK7T
@@ -39,7 +39,7 @@ in {
           "marohu.oxzi.r"
         ];
         ip4.addr = "10.243.32.2";
-        ip6.addr = (lib.krebs.genipv6 "retiolum" "oxzi" { hostName = "marohu"; }).address;
+        ip6.addr = (slib.krebs.genipv6 "retiolum" "oxzi" { hostName = "marohu"; }).address;
         tinc.pubkey = ''
           -----BEGIN RSA PUBLIC KEY-----
           MIICCgKCAgEAxHLkvuH9JMXay/fEmoWTEqLHg9A50EzkxPVBn4nyezgp5vxsUqJz
diff --git a/kartei/palo/default.nix b/kartei/palo/default.nix
index 6fc9a594f..487261acf 100644
--- a/kartei/palo/default.nix
+++ b/kartei/palo/default.nix
@@ -1,6 +1,7 @@
-with import ../../lib;
-{ config, ... }:
+{ config, lib, ... }:
 let
+  inherit (lib) flip mapAttrs optionalAttrs recursiveUpdate;
+  slib = import ../../lib/pure.nix { inherit lib; };
 
   hostDefaults = hostName: host: flip recursiveUpdate host ({
     ci = false;
@@ -8,10 +9,10 @@ let
     monitoring = false;
   } // optionalAttrs (host.nets?retiolum) {
     nets.retiolum.ip6.addr =
-      (krebs.genipv6 "retiolum" "external" { inherit hostName; }).address;
+      (slib.krebs.genipv6 "retiolum" "external" { inherit hostName; }).address;
   } // optionalAttrs (host.nets?wiregrill) {
     nets.wiregrill.ip6.addr =
-      (krebs.genipv6 "wiregrill" "external" { inherit hostName; }).address;
+      (slib.krebs.genipv6 "wiregrill" "external" { inherit hostName; }).address;
   });
 
 in
diff --git a/kartei/rtunreal/default.nix b/kartei/rtunreal/default.nix
index 9d57c0fce..de6c528fa 100644
--- a/kartei/rtunreal/default.nix
+++ b/kartei/rtunreal/default.nix
@@ -1,6 +1,8 @@
-with import ../../lib;
-{ config, ... }:
+{ config, lib, ... }:
 let
+  inherit (lib) flip mapAttrs optionalAttrs recursiveUpdate;
+  slib = import ../../lib/pure.nix { inherit lib; };
+
   hostDefaults = hostName: host: flip recursiveUpdate host ({
     ci = false;
     external = true;
@@ -8,11 +10,11 @@ let
     owner = config.krebs.users.rtunreal;
   } // optionalAttrs (host.nets?retiolum) {
     nets.retiolum = {
-      ip6.addr = (krebs.genipv6 "retiolum" "external" { inherit hostName; }).address;
+      ip6.addr = (slib.krebs.genipv6 "retiolum" "external" { inherit hostName; }).address;
     };
   } // optionalAttrs (host.nets?wiregrill) {
     nets.wiregrill = {
-      ip6.addr = (krebs.genipv6 "wiregrill" "external" { inherit hostName; }).address;
+      ip6.addr = (slib.krebs.genipv6 "wiregrill" "external" { inherit hostName; }).address;
     };
   });
   ssh-for = name: builtins.readFile (./ssh + "/${name}.pub");
diff --git a/kartei/srounce/default.nix b/kartei/srounce/default.nix
index ef37cbcd1..e0c1be963 100644
--- a/kartei/srounce/default.nix
+++ b/kartei/srounce/default.nix
@@ -1,13 +1,12 @@
-{ config, ... }: let
-  lib = import ../../lib;
-
+{ config, lib, ... }: let
+  slib = import ../../lib/pure.nix { inherit lib; };
   hostDefaults = hostName: host: lib.flip lib.recursiveUpdate host ({
     ci = false;
     external = true;
     monitoring = false;
   } // lib.optionalAttrs (host.nets?retiolum) {
     nets.retiolum.ip6.addr =
-      (lib.krebs.genipv6 "retiolum" "external" { inherit hostName; }).address;
+      (slib.krebs.genipv6 "retiolum" "external" { inherit hostName; }).address;
   });
 
 in {
diff --git a/kartei/template/default.nix b/kartei/template/default.nix
index 2acf78d38..2d595f9b4 100644
--- a/kartei/template/default.nix
+++ b/kartei/template/default.nix
@@ -1,5 +1,5 @@
-{ config, ... }: let
-  lib = import ../../lib;
+{ config, lib, ... }: let
+  slib = import ../../lib/pure.nix { inherit lib; };
 in {
   users.DUMMYUSER = {
     mail = "DUMMYUSER@example.ork";
@@ -8,7 +8,7 @@ in {
     owner = config.krebs.users.DUMMYUSER;
     nets.retiolum = {
       aliases = [ "DUMMYHOST.DUMMYUSER.r" ];
-      ip6.addr = (lib.krebs.genipv6 "retiolum" "DUMMYUSER" { hostName = "DUMMYHOST"; }).address;
+      ip6.addr = (slib.krebs.genipv6 "retiolum" "DUMMYUSER" { hostName = "DUMMYHOST"; }).address;
       tinc.pubkey = ''
         -----BEGIN RSA PUBLIC KEY-----
         DUMMYTINCPUBKEYRSA
diff --git a/kartei/tv/default.nix b/kartei/tv/default.nix
index eacb40af3..2f23324cc 100644
--- a/kartei/tv/default.nix
+++ b/kartei/tv/default.nix
@@ -1,5 +1,11 @@
-with import ../../lib;
-{ config, ... }: {
+{ config, lib, ... }@attrs: let
+  inherit (builtins)
+    getAttr head mapAttrs match pathExists readDir readFile typeOf;
+  inherit (lib)
+    const hasAttrByPath mapAttrs' mkDefault mkIf optionalAttrs removeSuffix
+    toList;
+  slib = import ../../lib/pure.nix { inherit lib; };
+in {
   dns.providers = {
     "viljetic.de" = "regfish";
   };
@@ -8,10 +14,10 @@ with import ../../lib;
       (hostName: hostFile: let
         hostSource = import hostFile;
         hostConfig = getAttr (typeOf hostSource) {
-          lambda = hostSource { inherit config lib; };
+          lambda = hostSource attrs;
           set = hostSource;
         };
-      in evalSubmodule types.host [
+      in slib.evalSubmodule slib.types.host [
         hostConfig
         {
           name = hostName;
@@ -20,7 +26,7 @@ with import ../../lib;
         (optionalAttrs (hasAttrByPath ["nets" "retiolum"] hostConfig) {
           nets.retiolum = {
             ip6.addr =
-              (krebs.genipv6 "retiolum" "tv" { inherit hostName; }).address;
+              (slib.krebs.genipv6 "retiolum" "tv" { inherit hostName; }).address;
           };
         })
         (let
@@ -31,14 +37,14 @@ with import ../../lib;
               "${hostName}.w"
             ];
             ip6.addr =
-              (krebs.genipv6 "wiregrill" "tv" { inherit hostName; }).address;
+              (slib.krebs.genipv6 "wiregrill" "tv" { inherit hostName; }).address;
             wireguard.pubkey = readFile pubkey-path;
           };
         })
         (host: mkIf (host.config.ssh.pubkey != null) {
           ssh.privkey = mapAttrs (const mkDefault) {
             path = config.krebs.secret.file "ssh.id_${host.config.ssh.privkey.type}";
-            type = head (toList (match "ssh-([^ ]+) .*" host.config.ssh.pubkey));
+            type = head (toList (builtins.match "ssh-([^ ]+) .*" host.config.ssh.pubkey));
           };
         })
       ])
diff --git a/kartei/tv/hosts/ni.nix b/kartei/tv/hosts/ni.nix
index aae5c5cd4..d64874d9c 100644
--- a/kartei/tv/hosts/ni.nix
+++ b/kartei/tv/hosts/ni.nix
@@ -1,4 +1,6 @@
-{ config, lib, ... }: {
+{ config, lib, ... }: let
+  slib = import ../../../lib/pure.nix { inherit lib; };
+in {
   extraZones = {
     "krebsco.de" = ''
       ni          60 IN A ${config.krebs.hosts.ni.nets.internet.ip4.addr}
@@ -60,7 +62,7 @@
       via = config.krebs.hosts.ni.nets.internet;
       ip4.addr = "10.244.3.1";
       wireguard.subnets = [
-        (lib.krebs.genipv6 "wiregrill" "tv" 0).subnetCIDR
+        (slib.krebs.genipv6 "wiregrill" "tv" 0).subnetCIDR
       ];
     };
   };
diff --git a/kartei/xkey/default.nix b/kartei/xkey/default.nix
index 939e04c7b..9f80288f6 100644
--- a/kartei/xkey/default.nix
+++ b/kartei/xkey/default.nix
@@ -1,6 +1,7 @@
-with import ../../lib;
-{ config, ... }:
+{ config, lib, ... }:
 let
+  inherit (lib) flip mapAttrs optionalAttrs recursiveUpdate;
+  slib = import ../../lib/pure.nix { inherit lib; };
   maybeEmpty = attrset: key: if (attrset?key) then attrset.${key} else [];
   hostDefaults = hostName: host: flip recursiveUpdate host ({
     ci = false;
@@ -9,11 +10,11 @@ let
     owner = config.krebs.users.xkey;
   } // optionalAttrs (host.nets?retiolum) {
     nets.retiolum = {
-      ip6.addr = (krebs.genipv6 "retiolum" "external" { inherit hostName; }).address;
+      ip6.addr = (slib.krebs.genipv6 "retiolum" "external" { inherit hostName; }).address;
     };
   } // optionalAttrs (host.nets?wiregrill) {
     nets.wiregrill = {
-      ip6.addr = (krebs.genipv6 "wiregrill" "external" { inherit hostName; }).address;
+      ip6.addr = (slib.krebs.genipv6 "wiregrill" "external" { inherit hostName; }).address;
     };
   });
   ssh-for = name: builtins.readFile (./ssh + "/${name}.pub");
diff --git a/kartei/ynnel/default.nix b/kartei/ynnel/default.nix
index e7d985278..9d8b80a2f 100644
--- a/kartei/ynnel/default.nix
+++ b/kartei/ynnel/default.nix
@@ -1,6 +1,6 @@
-{ config, ... }:
+{ config, lib, ... }:
 let
-  lib = import ../../lib;
+  slib = import ../../lib/pure.nix { inherit lib; };
 in
 {
   users.ynnel = {
@@ -10,7 +10,7 @@ in
     owner = config.krebs.users.ynnel;
     nets.retiolum = {
       aliases = [ "mokemoke.ynnel.r" ];
-      ip6.addr = (lib.krebs.genipv6 "retiolum" "ynnel" { hostName = "mokemoke"; }).address;
+      ip6.addr = (slib.krebs.genipv6 "retiolum" "ynnel" { hostName = "mokemoke"; }).address;
       tinc.pubkey = ''
         -----BEGIN RSA PUBLIC KEY-----
         MIICCgKCAgEA7rS560SZEPcSekW30dRF6ZTHOnb8WvuVgt3BFLRWhTgV5DqLqFa8
diff --git a/krebs/1systems/arcadeomat/config.nix b/krebs/1systems/arcadeomat/config.nix
index cdeaae180..7439e687e 100644
--- a/krebs/1systems/arcadeomat/config.nix
+++ b/krebs/1systems/arcadeomat/config.nix
@@ -9,15 +9,15 @@ in
 {
   imports = [
     ./hw.nix
-    <stockholm/krebs>
-    <stockholm/krebs/2configs>
+    ../../../krebs
+    ../../../krebs/2configs
 
-    #<stockholm/krebs/2configs/binary-cache/nixos.nix>
-    #<stockholm/krebs/2configs/binary-cache/prism.nix>
+    #../../../krebs/2configs/binary-cache/nixos.nix
+    #../../../krebs/2configs/binary-cache/prism.nix
 
-    <stockholm/krebs/2configs/shack/ssh-keys.nix>
-    <stockholm/krebs/2configs/save-diskspace.nix>
-    <stockholm/krebs/2configs/shack/prometheus/node.nix>
+    ../../../krebs/2configs/shack/ssh-keys.nix
+    ../../../krebs/2configs/save-diskspace.nix
+    ../../../krebs/2configs/shack/prometheus/node.nix
 
   ];
   # use your own binary cache, fallback use cache.nixos.org (which is used by
diff --git a/krebs/1systems/filebitch/config.nix b/krebs/1systems/filebitch/config.nix
index a71e14f3e..254306ecb 100644
--- a/krebs/1systems/filebitch/config.nix
+++ b/krebs/1systems/filebitch/config.nix
@@ -5,16 +5,16 @@ in
 {
   imports = [
     ./hardware-configuration.nix
-    <stockholm/krebs>
-    <stockholm/krebs/2configs>
-    # <stockholm/krebs/2configs/secret-passwords.nix>
+    ../../../krebs
+    ../../../krebs/2configs
+    # ../../../krebs/2configs/secret-passwords.nix
 
-    # <stockholm/krebs/2configs/binary-cache/nixos.nix>
-    # <stockholm/krebs/2configs/binary-cache/prism.nix>
-    <stockholm/krebs/2configs/shack/ssh-keys.nix>
-    <stockholm/krebs/2configs/shack/prometheus/node.nix>
+    # ../../../krebs/2configs/binary-cache/nixos.nix
+    # ../../../krebs/2configs/binary-cache/prism.nix
+    ../../../krebs/2configs/shack/ssh-keys.nix
+    ../../../krebs/2configs/shack/prometheus/node.nix
     # provides access to /home/share for smbuser via smb
-    <stockholm/krebs/2configs/shack/share.nix>
+    ../../../krebs/2configs/shack/share.nix
     {
       fileSystems."/home/share" =
         { device = "/serve";
@@ -23,8 +23,8 @@ in
     }
 
     ## Collect local statistics via collectd and send to collectd
-    # <stockholm/krebs/2configs/stats/shack-client.nix>
-    # <stockholm/krebs/2configs/stats/shack-debugging.nix>
+    # ../../../krebs/2configs/stats/shack-client.nix
+    # ../../../krebs/2configs/stats/shack-debugging.nix
   ];
 
   krebs.build.host = config.krebs.hosts.filebitch;
diff --git a/krebs/1systems/hotdog/config.nix b/krebs/1systems/hotdog/config.nix
index 683556081..e5cfad564 100644
--- a/krebs/1systems/hotdog/config.nix
+++ b/krebs/1systems/hotdog/config.nix
@@ -2,23 +2,23 @@
 
 {
   imports = [
-    <stockholm/krebs>
-    <stockholm/krebs/2configs>
+    ../../../krebs
+    ../../../krebs/2configs
 
-    <stockholm/krebs/2configs/buildbot-stockholm.nix>
-    <stockholm/krebs/2configs/binary-cache/nixos.nix>
-    <stockholm/krebs/2configs/ircd.nix>
-    <stockholm/krebs/2configs/reaktor2.nix>
-    <stockholm/krebs/2configs/wiki.nix>
-    <stockholm/krebs/2configs/acme.nix>
-    <stockholm/krebs/2configs/mud.nix>
-    <stockholm/krebs/2configs/repo-sync.nix>
+    ../../../krebs/2configs/buildbot-stockholm.nix
+    ../../../krebs/2configs/binary-cache/nixos.nix
+    ../../../krebs/2configs/ircd.nix
+    ../../../krebs/2configs/reaktor2.nix
+    ../../../krebs/2configs/wiki.nix
+    ../../../krebs/2configs/acme.nix
+    ../../../krebs/2configs/mud.nix
+    ../../../krebs/2configs/repo-sync.nix
 
-    <stockholm/krebs/2configs/cal.nix>
-    <stockholm/krebs/2configs/mastodon.nix>
+    ../../../krebs/2configs/cal.nix
+    ../../../krebs/2configs/mastodon.nix
 
-    ## shackie irc bot
-    <stockholm/krebs/2configs/shack/reaktor.nix>
+    ## (shackie irc bot
+    ../../../krebs/2configs/shack/reaktor.nix
   ];
 
   krebs.build.host = config.krebs.hosts.hotdog;
diff --git a/krebs/1systems/news/config.nix b/krebs/1systems/news/config.nix
index b27fc3737..b5a2b21ba 100644
--- a/krebs/1systems/news/config.nix
+++ b/krebs/1systems/news/config.nix
@@ -2,15 +2,15 @@
 
 {
   imports = [
-    <stockholm/krebs>
-    <stockholm/krebs/2configs>
+    ../../../krebs
+    ../../../krebs/2configs
 
-    <stockholm/krebs/2configs/ircd.nix>
-    <stockholm/krebs/2configs/go.nix>
+    ../../../krebs/2configs/ircd.nix
+    ../../../krebs/2configs/go.nix
 
     #### NEWS ####
-    <stockholm/krebs/2configs/ircd.nix>
-    <stockholm/krebs/2configs/news.nix>
+    ../../../krebs/2configs/ircd.nix
+    ../../../krebs/2configs/news.nix
   ];
 
   krebs.build.host = config.krebs.hosts.news;
diff --git a/krebs/2configs/backup.nix b/krebs/2configs/backup.nix
index 7ee438784..83dbf66fb 100644
--- a/krebs/2configs/backup.nix
+++ b/krebs/2configs/backup.nix
@@ -1,5 +1,5 @@
 { config, lib, ... }:
-with import <stockholm/lib>;
+with lib;
 {
   krebs.backup.plans = {
   } // mapAttrs (_: recursiveUpdate {
diff --git a/krebs/2configs/buildbot-stockholm.nix b/krebs/2configs/buildbot-stockholm.nix
index f0b6c324d..32452e010 100644
--- a/krebs/2configs/buildbot-stockholm.nix
+++ b/krebs/2configs/buildbot-stockholm.nix
@@ -1,5 +1,5 @@
-{ config, ... }: with import <stockholm/lib>;
-
+{ config, lib, ... }:
+with import ../../lib/pure.nix { inherit lib; };
 {
   networking.firewall.allowedTCPPorts = [ 80 ];
   services.nginx = {
diff --git a/krebs/2configs/cal.nix b/krebs/2configs/cal.nix
index 15f0027b3..a1fe47b5d 100644
--- a/krebs/2configs/cal.nix
+++ b/krebs/2configs/cal.nix
@@ -1,4 +1,5 @@
 { config, lib, pkgs, ... }: let
+  slib = import ../../lib/pure.nix { inherit lib; };
 
   setupGit = ''
     export PATH=${lib.makeBinPath [
@@ -23,13 +24,13 @@
     git add .gitignore
   '';
 
-  pushCal = pkgs.writeDash "push_cal" ''
+  pushCal = pkgs.writers.writeDash "push_cal" ''
     ${setupGit}
     git fetch origin
     git merge --ff-only origin/master || :
   '';
 
-  pushCgit = pkgs.writeDash "push_cgit" ''
+  pushCgit = pkgs.writers.writeDash "push_cgit" ''
     ${setupGit}
     git push origin master
   '';
@@ -73,7 +74,7 @@ in {
     cgit.settings = {
       root-title = "krebs repos";
     };
-    rules = with pkgs.stockholm.lib.git; [
+    rules = with slib.git; [
       {
         user = [
           {
diff --git a/krebs/2configs/default.nix b/krebs/2configs/default.nix
index eda03cc10..bd4f36cbe 100644
--- a/krebs/2configs/default.nix
+++ b/krebs/2configs/default.nix
@@ -1,6 +1,6 @@
 { config, lib, pkgs, ... }:
 
-with import <stockholm/lib>;
+with import ../../lib/pure.nix { inherit lib; };
 {
   imports = [
     ./backup.nix
diff --git a/krebs/2configs/exim-smarthost.nix b/krebs/2configs/exim-smarthost.nix
index 01597f49f..c2f6b4dc0 100644
--- a/krebs/2configs/exim-smarthost.nix
+++ b/krebs/2configs/exim-smarthost.nix
@@ -1,5 +1,6 @@
-with import <stockholm/lib>;
-{ config, ... }: let
+{ config, lib, ... }:
+with import ../../lib/pure.nix { inherit lib; };
+let
 
   format = from: to: {
     inherit from;
diff --git a/krebs/2configs/go.nix b/krebs/2configs/go.nix
index ce5db62d4..ea3258b9c 100644
--- a/krebs/2configs/go.nix
+++ b/krebs/2configs/go.nix
@@ -1,6 +1,5 @@
 { config, lib, pkgs, ... }:
 
-with import <stockholm/lib>;
 {
   krebs.go = {
     enable = true;
diff --git a/krebs/2configs/hw/x220.nix b/krebs/2configs/hw/x220.nix
index bb273652d..980c2c9aa 100644
--- a/krebs/2configs/hw/x220.nix
+++ b/krebs/2configs/hw/x220.nix
@@ -1,6 +1,5 @@
 { config, lib, pkgs, ... }:
 
-with import <stockholm/lib>;
 {
   networking.wireless.enable = lib.mkDefault true;
 
diff --git a/krebs/2configs/reaktor2.nix b/krebs/2configs/reaktor2.nix
index 45ff61baf..231c3d46c 100644
--- a/krebs/2configs/reaktor2.nix
+++ b/krebs/2configs/reaktor2.nix
@@ -1,5 +1,5 @@
-with import <stockholm/lib>;
-{ config, pkgs, ... }:
+{ config, lib, pkgs, ... }:
+with import ../../lib/pure.nix { inherit lib; };
 
 let
   #for shared state directory
@@ -22,7 +22,7 @@ let
         # TODO; get state as argument
         state_file = "${stateDir}/ledger";
       };
-      filename = pkgs.writeDash "bedger-add" ''
+      filename = pkgs.writers.writeDash "bedger-add" ''
         set -x
         tonick=$1
         amt=$2
@@ -42,7 +42,7 @@ let
       env = {
         state_file = "${stateDir}/ledger";
       };
-      filename = pkgs.writeDash "bedger-balance" ''
+      filename = pkgs.writers.writeDash "bedger-balance" ''
         ${pkgs.hledger}/bin/hledger -f $state_file bal -N -O csv \
           | ${pkgs.coreutils}/bin/tail +2 \
           | ${pkgs.miller}/bin/mlr --icsv --opprint cat \
@@ -57,7 +57,7 @@ let
     arguments = [1];
     timeoutSec = 1337;
     command = {
-      filename = pkgs.writeDash "bing" ''
+      filename = pkgs.writers.writeDash "bing" ''
         set -efu
         report_error() {
           printf '%s' "$*" |
@@ -97,7 +97,7 @@ let
     arguments = [1];
     timeoutSec = 1337;
     command = {
-      filename = pkgs.writeDash "bing-img" ''
+      filename = pkgs.writers.writeDash "bing-img" ''
         set -efu
         report_error() {
           printf '%s' "$*" |
@@ -142,7 +142,7 @@ let
     activate = "match";
     arguments = [1];
     command = {
-      filename = pkgs.writeDash "confuse" ''
+      filename = pkgs.writers.writeDash "confuse" ''
         set -efux
 
         export PATH=${makeBinPath [
@@ -164,7 +164,7 @@ let
     activate = "match";
     arguments = [1];
     command = {
-      filename = pkgs.writeDash "interrogate" ''
+      filename = pkgs.writers.writeDash "interrogate" ''
         set -efux
 
         export PATH=${makeBinPath [
@@ -181,7 +181,7 @@ let
     activate = "match";
     arguments = [1];
     command = {
-      filename = pkgs.writeDash "confuse" ''
+      filename = pkgs.writers.writeDash "confuse" ''
         set -efu
         export PATH=${makeBinPath [
           pkgs.coreutils
@@ -204,7 +204,7 @@ let
     activate = "match";
     arguments = [1];
     command = {
-      filename = pkgs.writeDash "say" ''
+      filename = pkgs.writers.writeDash "say" ''
         set -efu
 
         export PATH=${makeBinPath [
@@ -234,20 +234,20 @@ let
     arguments = [2];
     env.TASKDATA = "${stateDir}/${name}";
     commands = rec {
-      add.filename = pkgs.writeDash "${name}-task-add" ''
+      add.filename = pkgs.writers.writeDash "${name}-task-add" ''
         ${pkgs.taskwarrior}/bin/task rc:${taskRcFile} add "$1"
       '';
-      list.filename = pkgs.writeDash "${name}-task-list" ''
+      list.filename = pkgs.writers.writeDash "${name}-task-list" ''
         ${pkgs.taskwarrior}/bin/task rc:${taskRcFile} export \
           | ${pkgs.jq}/bin/jq -r '
               .[] | select(.id != 0) | "\(.id) \(.description)"
             '
       '';
-      delete.filename = pkgs.writeDash "${name}-task-delete" ''
+      delete.filename = pkgs.writers.writeDash "${name}-task-delete" ''
         ${pkgs.taskwarrior}/bin/task rc:${taskRcFile} delete "$1"
       '';
       del = delete;
-      done.filename = pkgs.writeDash "${name}-task-done" ''
+      done.filename = pkgs.writers.writeDash "${name}-task-done" ''
         ${pkgs.taskwarrior}/bin/task rc:${taskRcFile} done "$1"
       '';
     };
@@ -293,8 +293,7 @@ let
         {
           activate = "always";
           command = {
-            filename =
-              <stockholm/krebs/5pkgs/simple/Reaktor/scripts/tell-on_join.sh>;
+            filename = ../5pkgs/simple/Reaktor/scripts/tell-on_join.sh;
             env = {
               PATH = makeBinPath [
                 pkgs.coreutils # XXX env, touch
@@ -311,7 +310,7 @@ let
           pattern = "^list-locations";
           activate = "match";
           command = {
-            filename = pkgs.writeDash "list-locations" ''
+            filename = pkgs.writers.writeDash "list-locations" ''
               export PATH=${makeBinPath [
                 pkgs.curl
                 pkgs.jq
@@ -328,7 +327,7 @@ let
           activate = "match";
           arguments = [1 2 3];
           command = {
-            filename = pkgs.writeDash "add-location" ''
+            filename = pkgs.writers.writeDash "add-location" ''
               export PATH=${makeBinPath [
                 pkgs.curl
                 pkgs.jq
@@ -345,7 +344,7 @@ let
           activate = "match";
           arguments = [1];
           command = {
-            filename = pkgs.writeDash "add-location" ''
+            filename = pkgs.writers.writeDash "add-location" ''
               export PATH=${makeBinPath [
                 pkgs.curl
                 pkgs.jq
@@ -374,7 +373,7 @@ let
                 sha256 = "sha256-J7jGWZeAULDA1EkO50qx+hjl+5IsUj389pUUMreKeNE=";
               };
               osm-restaurants = pkgs.callPackage "${osm-restaurants-src}/osm-restaurants" {};
-            in pkgs.writeDash "krebsfood" ''
+            in pkgs.writers.writeDash "krebsfood" ''
               set -efu
               export PATH=${makeBinPath [
                 osm-restaurants
@@ -417,8 +416,7 @@ let
         (generators.command_hook {
           inherit (commands) dance random-emoji nixos-version;
           tell = {
-            filename =
-              <stockholm/krebs/5pkgs/simple/Reaktor/scripts/tell-on_privmsg.sh>;
+            filename = ../5pkgs/simple/Reaktor/scripts/tell-on_privmsg.sh;
             env = {
               PATH = makeBinPath [
                 pkgs.coreutils # XXX date, env
@@ -452,7 +450,7 @@ in {
      name = "reaktor2";
      home = stateDir;
     };
-    script = ''. ${pkgs.writeDash "agenda" ''
+    script = ''. ${pkgs.writers.writeDash "agenda" ''
       echo "$Method $Request_URI" >&2
       case "$Method" in
         "GET")
diff --git a/krebs/2configs/repo-sync.nix b/krebs/2configs/repo-sync.nix
index 9f129d81c..1b72924a6 100644
--- a/krebs/2configs/repo-sync.nix
+++ b/krebs/2configs/repo-sync.nix
@@ -1,6 +1,5 @@
 { config, lib, pkgs, ... }:
-
-with import <stockholm/lib>;
+with import ../../lib/pure.nix { inherit lib; };
 
 let
   konsens-user = {
diff --git a/krebs/2configs/secret-passwords.nix b/krebs/2configs/secret-passwords.nix
index 5d265eba6..0f0d068aa 100644
--- a/krebs/2configs/secret-passwords.nix
+++ b/krebs/2configs/secret-passwords.nix
@@ -1,4 +1,5 @@
-{ ... }: with import <stockholm/lib>;
+{ lib, ... }:
+with lib;
 {
   users.extraUsers =
     mapAttrs (_: h: { hashedPassword = h; })
diff --git a/krebs/2configs/shack/drivedroid.nix b/krebs/2configs/shack/drivedroid.nix
index 12e4a39c3..e00db8b8d 100644
--- a/krebs/2configs/shack/drivedroid.nix
+++ b/krebs/2configs/shack/drivedroid.nix
@@ -1,5 +1,5 @@
-{ config, pkgs, ... }:
-with import <stockholm/lib>;
+{ config, lib, pkgs, ... }:
+with import ../../../lib/pure.nix { inherit lib; };
 let
   root = "/var/srv/drivedroid";
 in
diff --git a/krebs/2configs/shack/mqtt_sub.nix b/krebs/2configs/shack/mqtt_sub.nix
index af2bc1e66..45065cfc8 100644
--- a/krebs/2configs/shack/mqtt_sub.nix
+++ b/krebs/2configs/shack/mqtt_sub.nix
@@ -1,6 +1,6 @@
 { config, lib, pkgs, ... }:
 
-with import <stockholm/lib>;
+with import ../../../lib/pure.nix { inherit lib; };
 let
   pkg = pkgs.stdenv.mkDerivation {
     name = "mqtt2graphite-2017-05-29";
diff --git a/krebs/2configs/shack/muell_caller.nix b/krebs/2configs/shack/muell_caller.nix
index 33f6b8c89..f3007dd1d 100644
--- a/krebs/2configs/shack/muell_caller.nix
+++ b/krebs/2configs/shack/muell_caller.nix
@@ -1,6 +1,6 @@
 { config, lib, pkgs, ... }:
 
-with import <stockholm/lib>;
+with import ../../../lib/pure.nix { inherit lib; };
 let
   pkg = pkgs.stdenv.mkDerivation {
     name = "muell_caller-2017-06-01";
diff --git a/krebs/2configs/shack/nix-cacher.nix b/krebs/2configs/shack/nix-cacher.nix
index 8feeca9af..131525a3e 100644
--- a/krebs/2configs/shack/nix-cacher.nix
+++ b/krebs/2configs/shack/nix-cacher.nix
@@ -1,5 +1,5 @@
 { config, pkgs, ... }:
-with import <stockholm/lib>;
+with import ../../../lib/pure.nix { inherit lib; };
 let
   cfg = config.krebs.apt-cacher-ng;
 in
diff --git a/krebs/2configs/shack/radioactive.nix b/krebs/2configs/shack/radioactive.nix
index 286a73aae..e24121038 100644
--- a/krebs/2configs/shack/radioactive.nix
+++ b/krebs/2configs/shack/radioactive.nix
@@ -1,6 +1,6 @@
 { config, lib, pkgs, ... }:
 
-with import <stockholm/lib>;
+with import ../../../lib/pure.nix { inherit lib; };
 let
   pkg = pkgs.stdenv.mkDerivation {
     name = "radioactive-2017-06-01";
diff --git a/krebs/2configs/shack/worlddomination.nix b/krebs/2configs/shack/worlddomination.nix
index e339d3174..b7a8f18df 100644
--- a/krebs/2configs/shack/worlddomination.nix
+++ b/krebs/2configs/shack/worlddomination.nix
@@ -1,6 +1,6 @@
 { config, lib, pkgs, ... }:
 
-with import <stockholm/lib>;
+with import ../../../lib/pure.nix { inherit lib; };
 let
   pkg = pkgs.stdenv.mkDerivation {
     name = "worlddomination-2020-12-01";
diff --git a/krebs/2configs/stats/shack-debugging.nix b/krebs/2configs/stats/shack-debugging.nix
index b5a0cf05e..79730adad 100644
--- a/krebs/2configs/stats/shack-debugging.nix
+++ b/krebs/2configs/stats/shack-debugging.nix
@@ -1,7 +1,7 @@
 { config, lib, pkgs, ... }:
 
 # TODO: krebs.collectd.plugins
-with import <stockholm/lib>;
+with import ../../../lib/pure.nix { inherit lib; };
 let
   connect-time-cfg = with pkgs; writeText "collectd-connect-time.conf" ''
     LoadPlugin python
diff --git a/krebs/2configs/syncthing.nix b/krebs/2configs/syncthing.nix
index d6d42ca11..59178516c 100644
--- a/krebs/2configs/syncthing.nix
+++ b/krebs/2configs/syncthing.nix
@@ -1,4 +1,6 @@
-{ options, config, pkgs, ... }: with import <stockholm/lib>; let
+{ config, lib, options, pkgs, ... }:
+with import ../../lib/pure.nix { inherit lib; };
+let
   mk_peers = mapAttrs (n: v: { id = v.syncthing.id; });
 
   all_peers = filterAttrs (n: v: v.syncthing.id != null) config.krebs.hosts;
diff --git a/krebs/2configs/wiki.nix b/krebs/2configs/wiki.nix
index 40d946f7d..a227ceb4a 100644
--- a/krebs/2configs/wiki.nix
+++ b/krebs/2configs/wiki.nix
@@ -1,5 +1,5 @@
-{ config, pkgs, ... }:
-with import <stockholm/lib>;
+{ config, lib, pkgs, ... }:
+with import ../../lib/pure.nix { inherit lib; };
 let
 
   setupGit = ''
@@ -14,13 +14,13 @@ let
     fi
   '';
 
-  pushGollum = pkgs.writeDash "push_gollum" ''
+  pushGollum = pkgs.writers.writeDash "push_gollum" ''
     ${setupGit}
     git fetch origin
     git merge --ff-only origin/master
   '';
 
-  pushCgit = pkgs.writeDash "push_cgit" ''
+  pushCgit = pkgs.writers.writeDash "push_cgit" ''
     ${setupGit}
     git push origin master
   '';
diff --git a/krebs/3modules/airdcpp.nix b/krebs/3modules/airdcpp.nix
index 259f613cc..acd007cb8 100644
--- a/krebs/3modules/airdcpp.nix
+++ b/krebs/3modules/airdcpp.nix
@@ -1,6 +1,7 @@
 { config, lib, pkgs, ... }:
-with import <stockholm/lib>; #genid
+with lib;
 let
+  slib = import ../../lib/pure.nix { inherit lib; };
   cfg = config.krebs.airdcpp;
 
   out = {
@@ -265,14 +266,14 @@ let
     };
     users = lib.mkIf (cfg.user == "airdcpp") {
       users.airdcpp = {
-        uid = genid "airdcpp";
+        uid = slib.genid "airdcpp";
         home = cfg.stateDir;
         createHome = true;
         isSystemUser = true;
         group = "airdcpp";
         inherit (cfg) extraGroups;
       };
-      groups.airdcpp.gid = genid "airdcpp";
+      groups.airdcpp.gid = slib.genid "airdcpp";
     };
   };
 in
diff --git a/krebs/3modules/announce-activation.nix b/krebs/3modules/announce-activation.nix
index a40ae8cef..fa0f1530c 100644
--- a/krebs/3modules/announce-activation.nix
+++ b/krebs/3modules/announce-activation.nix
@@ -1,20 +1,21 @@
-with import <stockholm/lib>;
-{ config, pkgs, ... }: let
+{ config, pkgs, lib, ... }:
+let
+  slib = import ../../lib/pure.nix { inherit lib; };
   cfg = config.krebs.announce-activation;
   announce-activation = pkgs.writeDash "announce-activation" ''
     set -efu
     message=$(${cfg.get-message})
     exec ${pkgs.irc-announce}/bin/irc-announce \
-        ${shell.escape cfg.irc.server} \
-        ${shell.escape (toString cfg.irc.port)} \
-        ${shell.escape cfg.irc.nick} \
-        ${shell.escape cfg.irc.channel} \
-        ${escapeShellArg cfg.irc.tls} \
+        ${slib.shell.escape cfg.irc.server} \
+        ${slib.shell.escape (toString cfg.irc.port)} \
+        ${slib.shell.escape cfg.irc.nick} \
+        ${slib.shell.escape cfg.irc.channel} \
+        ${lib.escapeShellArg cfg.irc.tls} \
         "$message"
   '';
   default-get-message = pkgs.writeDash "announce-activation-get-message" ''
     set -efu
-    PATH=${makeBinPath [
+    PATH=${lib.makeBinPath [
       pkgs.coreutils
       pkgs.gawk
       pkgs.gnused
@@ -28,37 +29,37 @@ with import <stockholm/lib>;
   '';
 in {
   options.krebs.announce-activation = {
-    enable = mkEnableOption "announce-activation";
-    get-message = mkOption {
+    enable = lib.mkEnableOption "announce-activation";
+    get-message = lib.mkOption {
       default = default-get-message;
-      type = types.package;
+      type = lib.types.package;
     };
     irc = {
       # TODO rename channel to target?
-      channel = mkOption {
+      channel = lib.mkOption {
         default = "#xxx";
-        type = types.str; # TODO types.irc-channel
+        type = lib.types.str; # TODO types.irc-channel
       };
-      nick = mkOption {
+      nick = lib.mkOption {
         default = config.krebs.build.host.name;
-        type = types.label;
+        type = slib.types.label;
       };
-      port = mkOption {
+      port = lib.mkOption {
         default = 6667;
-        type = types.int;
+        type = lib.types.int;
       };
-      server = mkOption {
+      server = lib.mkOption {
         default = "irc.r";
-        type = types.hostname;
+        type = slib.types.hostname;
       };
-      tls = mkOption {
+      tls = lib.mkOption {
         default = false;
-        type = types.bool;
+        type = lib.types.bool;
       };
     };
   };
-  config = mkIf cfg.enable {
-    system.activationScripts.announce-activation = stringAfter [ "etc" ] ''
+  config = lib.mkIf cfg.enable {
+    system.activationScripts.announce-activation = lib.stringAfter [ "etc" ] ''
       ${announce-activation}
     '';
   };
diff --git a/krebs/3modules/apt-cacher-ng.nix b/krebs/3modules/apt-cacher-ng.nix
index f3c8ff0cd..0efe9ed43 100644
--- a/krebs/3modules/apt-cacher-ng.nix
+++ b/krebs/3modules/apt-cacher-ng.nix
@@ -1,6 +1,6 @@
 { config, pkgs, lib, ... }:
 
-with import <stockholm/lib>;
+with lib;
 let
   acng-config = pkgs.writeTextFile {
     name = "acng-configuration";
diff --git a/krebs/3modules/backup.nix b/krebs/3modules/backup.nix
index c1d4d7211..900be5139 100644
--- a/krebs/3modules/backup.nix
+++ b/krebs/3modules/backup.nix
@@ -1,5 +1,5 @@
 { config, lib, pkgs, ... }:
-with import <stockholm/lib>;
+with import ../../lib/pure.nix { inherit lib; };
 let
   out = {
     options.krebs.backup = api;
diff --git a/krebs/3modules/bepasty-server.nix b/krebs/3modules/bepasty-server.nix
index c374aa9af..33c825a80 100644
--- a/krebs/3modules/bepasty-server.nix
+++ b/krebs/3modules/bepasty-server.nix
@@ -1,6 +1,6 @@
 { config, lib, pkgs, ... }:
 
-with import <stockholm/lib>;
+with lib;
 let
   gunicorn = pkgs.python3Packages.gunicorn;
   bepasty = pkgs.bepasty;
diff --git a/krebs/3modules/bindfs.nix b/krebs/3modules/bindfs.nix
index 7e3730e86..60736710f 100644
--- a/krebs/3modules/bindfs.nix
+++ b/krebs/3modules/bindfs.nix
@@ -1,5 +1,5 @@
-with import <stockholm/lib>;
-{ config, pkgs, ... }:
+{ config, pkgs, lib, ... }:
+with lib;
 let
   cfg = config.krebs.bindfs;
 in {
diff --git a/krebs/3modules/brockman.nix b/krebs/3modules/brockman.nix
index 8427ca50b..3f0dd0861 100644
--- a/krebs/3modules/brockman.nix
+++ b/krebs/3modules/brockman.nix
@@ -1,6 +1,7 @@
-{ pkgs, config, ... }:
-with import <stockholm/lib>;
+{ pkgs, config, lib, ... }:
+with lib;
 let
+  slib = import ../../lib/pure.nix { inherit lib; };
   cfg = config.krebs.brockman;
 in {
   options.krebs.brockman = {
@@ -14,7 +15,7 @@ in {
       group = "brockman";
       createHome = true;
       isSystemUser = true;
-      uid = genid_uint31 "brockman";
+      uid = slib.genid_uint31 "brockman";
     };
     users.groups.brockman = {};
 
diff --git a/krebs/3modules/build.nix b/krebs/3modules/build.nix
index 5f961617f..bf20cb099 100644
--- a/krebs/3modules/build.nix
+++ b/krebs/3modules/build.nix
@@ -1,6 +1,6 @@
-{ config, ... }:
+{ config, lib, pkgs, ... }:
 
-with import <stockholm/lib>;
+with import ../../lib/pure.nix { inherit lib; };
 
 {
   options.krebs.build = {
diff --git a/krebs/3modules/ci/default.nix b/krebs/3modules/ci/default.nix
index 022da5884..5035a11a8 100644
--- a/krebs/3modules/ci/default.nix
+++ b/krebs/3modules/ci/default.nix
@@ -1,6 +1,5 @@
 { config, lib, pkgs, ... }:
-
-with import <stockholm/lib>;
+with import ../../../lib/pure.nix { inherit lib; };
 
 let
   cfg = config.krebs.ci;
@@ -25,7 +24,7 @@ let
   };
 
   hostname = config.networking.hostName;
-  getJobs = pkgs.writeDash "get_jobs" ''
+  getJobs = pkgs.writers.writeDash "get_jobs" ''
     set -efu
     ${pkgs.nix}/bin/nix-build --no-out-link --quiet --show-trace -Q ./ci.nix >&2
     json="$(${pkgs.nix}/bin/nix-instantiate --quiet -Q --eval --strict --json ./ci.nix)"
@@ -116,7 +115,7 @@ let
                             build_script = stages[stage],
                           ),
                           timeout = 3600,
-                          command="${pkgs.writeDash "build.sh" ''
+                          command="${pkgs.writers.writeDash "build.sh" ''
                             set -xefu
                             profile=${shell.escape profileRoot}/$build_name
                             result=$("$build_script")
diff --git a/krebs/3modules/current.nix b/krebs/3modules/current.nix
index e97e53479..5c32203fd 100644
--- a/krebs/3modules/current.nix
+++ b/krebs/3modules/current.nix
@@ -1,6 +1,6 @@
 { config, pkgs, lib, ... }:
 
-with import <stockholm/lib>;
+with lib;
 
 let
   cfg = config.krebs.current;
diff --git a/krebs/3modules/default.nix b/krebs/3modules/default.nix
index 6d763afed..28ce09941 100644
--- a/krebs/3modules/default.nix
+++ b/krebs/3modules/default.nix
@@ -1,170 +1,62 @@
 { config, lib, ... }:
-
-with import <stockholm/lib>;
-let
-  cfg = config.krebs;
-
-  out = {
-    imports = [
-      ../../kartei
-      ../../submodules/disko/module.nix
-      ./acl.nix
-      ./airdcpp.nix
-      ./announce-activation.nix
-      ./apt-cacher-ng.nix
-      ./backup.nix
-      ./bepasty-server.nix
-      ./bindfs.nix
-      ./brockman.nix
-      ./build.nix
-      ./cachecache.nix
-      ./ci
-      ./current.nix
-      ./dns.nix
-      ./exim-retiolum.nix
-      ./exim-smarthost.nix
-      ./exim.nix
-      ./fetchWallpaper.nix
-      ./git.nix
-      ./github
-      ./go.nix
-      ./hidden-ssh.nix
-      ./hosts.nix
-      ./htgen.nix
-      ./iana-etc.nix
-      ./iptables.nix
-      ./kapacitor.nix
-      ./konsens.nix
-      ./krebs-pages.nix
-      ./monit.nix
-      ./nixpkgs.nix
-      ./on-failure.nix
-      ./os-release.nix
-      ./per-user.nix
-      ./permown.nix
-      ./power-action.nix
-      ./reaktor2.nix
-      ./realwallpaper.nix
-      ./repo-sync.nix
-      ./retiolum-bootstrap.nix
-      ./secret.nix
-      ./setuid.nix
-      ./shadow.nix
-      ./sitemap.nix
-      ./ssl.nix
-      ./sync-containers.nix
-      ./sync-containers3.nix
-      ./systemd.nix
-      ./tinc.nix
-      ./tinc_graphs.nix
-      ./upstream
-      ./urlwatch.nix
-      ./users.nix
-      ./xresources.nix
-      ./zones.nix
-    ];
-    options.krebs = api;
-    config = lib.mkIf cfg.enable imp;
-  };
-
-  api = {
-    enable = mkEnableOption "krebs";
-
-    zone-head-config  = mkOption {
-      type = with types; attrsOf str;
-      description = ''
-        The zone configuration head which is being used to create the
-        zone files. The string for each key is pre-pended to the zone file.
-      '';
-      # TODO: configure the default somewhere else,
-      # maybe use krebs.dns.providers
-      default = {
-
-        # github.io -> 192.30.252.154
-        "krebsco.de" = ''
-          $TTL 86400
-          @ IN SOA dns19.ovh.net. tech.ovh.net. (2015052000 86400 3600 3600000 86400)
-                                IN NS     ns19.ovh.net.
-                                IN NS     dns19.ovh.net.
-        '';
-      };
-    };
-  };
-
-  imp = lib.mkMerge [
-    {
-      services.openssh.hostKeys =
-        let inherit (config.krebs.build.host.ssh) privkey; in
-        mkIf (privkey != null) [privkey];
-
-      services.openssh.knownHosts =
-        filterAttrs
-          (knownHostName: knownHost:
-            knownHost.publicKey != null &&
-            knownHost.hostNames != []
-          )
-          (mapAttrs
-            (hostName: host: {
-              hostNames =
-                concatLists
-                  (mapAttrsToList
-                    (netName: net:
-                      let
-                        aliases =
-                          concatLists [
-                            shortAliases
-                            net.aliases
-                            net.addrs
-                          ];
-                        shortAliases =
-                          optionals
-                            (cfg.dns.search-domain != null)
-                            (map (removeSuffix ".${cfg.dns.search-domain}")
-                                 (filter (hasSuffix ".${cfg.dns.search-domain}")
-                                         net.aliases));
-                        addPort = alias:
-                          if net.ssh.port != 22
-                            then "[${alias}]:${toString net.ssh.port}"
-                            else alias;
-                      in
-                      map addPort aliases
-                    )
-                    host.nets);
-              publicKey = host.ssh.pubkey;
-            })
-            (foldl' mergeAttrs {} [
-              cfg.hosts
-              {
-                localhost = {
-                  nets.local = {
-                    addrs = [ "127.0.0.1" "::1" ];
-                    aliases = [ "localhost" ];
-                    ssh.port = 22;
-                  };
-                  ssh.pubkey = config.krebs.build.host.ssh.pubkey;
-                };
-              }
-            ]));
-
-      programs.ssh.extraConfig = concatMapStrings
-        (net: ''
-          Host ${toString (net.aliases ++ net.addrs)}
-            Port ${toString net.ssh.port}
-        '')
-        (filter
-          (net: net.ssh.port != 22)
-          (concatMap (host: attrValues host.nets)
-            (mapAttrsToList
-              (_: host: recursiveUpdate host
-                (optionalAttrs (cfg.dns.search-domain != null &&
-                                hasAttr cfg.dns.search-domain host.nets) {
-                  nets."" = host.nets.${cfg.dns.search-domain} // {
-                    aliases = [host.name];
-                    addrs = [];
-                  };
-                }))
-              config.krebs.hosts)));
-    }
+{
+  imports = [
+    ../../kartei
+    ./acl.nix
+    ./airdcpp.nix
+    ./announce-activation.nix
+    ./apt-cacher-ng.nix
+    ./backup.nix
+    ./bepasty-server.nix
+    ./bindfs.nix
+    ./brockman.nix
+    ./build.nix
+    ./cachecache.nix
+    ./ci
+    ./current.nix
+    ./dns.nix
+    ./exim-retiolum.nix
+    ./exim-smarthost.nix
+    ./exim.nix
+    ./fetchWallpaper.nix
+    ./git.nix
+    ./github
+    ./go.nix
+    ./hidden-ssh.nix
+    ./hosts.nix
+    ./htgen.nix
+    ./iana-etc.nix
+    ./iptables.nix
+    ./kapacitor.nix
+    ./konsens.nix
+    ./krebs.nix
+    ./krebs-pages.nix
+    ./monit.nix
+    ./nixpkgs.nix
+    ./on-failure.nix
+    ./os-release.nix
+    ./per-user.nix
+    ./permown.nix
+    ./power-action.nix
+    ./reaktor2.nix
+    ./realwallpaper.nix
+    ./repo-sync.nix
+    ./retiolum-bootstrap.nix
+    ./secret.nix
+    ./setuid.nix
+    ./shadow.nix
+    ./ssh.nix
+    ./sitemap.nix
+    ./ssl.nix
+    ./sync-containers.nix
+    ./sync-containers3.nix
+    ./systemd.nix
+    ./tinc.nix
+    ./tinc_graphs.nix
+    ./upstream
+    ./urlwatch.nix
+    ./users.nix
+    ./xresources.nix
+    ./zones.nix
   ];
-
-in out
+}
diff --git a/krebs/3modules/dns.nix b/krebs/3modules/dns.nix
index 8a74d3067..a268b931c 100644
--- a/krebs/3modules/dns.nix
+++ b/krebs/3modules/dns.nix
@@ -1,5 +1,5 @@
-with import <stockholm/lib>;
-{ config, ... }: {
+{ config, lib, pkgs, ... }:
+with import ../../lib/pure.nix { inherit lib; }; {
   options = {
     krebs.dns.providers = mkOption {
       type = types.attrsOf types.str;
@@ -8,7 +8,7 @@ with import <stockholm/lib>;
       type = types.nullOr types.hostname;
     };
   };
-  config = mkIf config.krebs.enable {
+  config = lib.mkIf config.krebs.enable {
     krebs.dns.providers = {
       "krebsco.de" = "zones";
       shack = "hosts";
diff --git a/krebs/3modules/exim-retiolum.nix b/krebs/3modules/exim-retiolum.nix
index a16661c9f..f78f1746c 100644
--- a/krebs/3modules/exim-retiolum.nix
+++ b/krebs/3modules/exim-retiolum.nix
@@ -1,5 +1,5 @@
-with import <stockholm/lib>;
-{ config, pkgs, lib, ... }: let
+{ config, pkgs, lib, ... }:
+with import ../../lib/pure.nix { inherit lib; }; let
   cfg = config.krebs.exim-retiolum;
 
   # Due to improvements to the JSON notation, braces around top-level objects
diff --git a/krebs/3modules/exim-smarthost.nix b/krebs/3modules/exim-smarthost.nix
index 62f15027a..7b3dace6a 100644
--- a/krebs/3modules/exim-smarthost.nix
+++ b/krebs/3modules/exim-smarthost.nix
@@ -1,6 +1,6 @@
 { config, pkgs, lib, ... }:
 
-with import <stockholm/lib>;
+with import ../../lib/pure.nix { inherit lib; };
 let
   cfg = config.krebs.exim-smarthost;
 
diff --git a/krebs/3modules/exim.nix b/krebs/3modules/exim.nix
index 0f0aa67f0..917a8e5a4 100644
--- a/krebs/3modules/exim.nix
+++ b/krebs/3modules/exim.nix
@@ -1,4 +1,4 @@
-{ config, lib, pkgs, ... }: with import <stockholm/lib>; let
+{ config, lib, pkgs, ... }: with import ../../lib/pure.nix { inherit lib; }; let
   cfg = config.krebs.exim;
 in {
   options.krebs.exim = {
diff --git a/krebs/3modules/fetchWallpaper.nix b/krebs/3modules/fetchWallpaper.nix
index dc0133a63..79187adfa 100644
--- a/krebs/3modules/fetchWallpaper.nix
+++ b/krebs/3modules/fetchWallpaper.nix
@@ -1,6 +1,6 @@
 { config, lib, pkgs, ... }:
 
-with import <stockholm/lib>;
+with import ../../lib/pure.nix { inherit lib; };
 
 let
   cfg = config.krebs.fetchWallpaper;
diff --git a/krebs/3modules/git.nix b/krebs/3modules/git.nix
index 02c673e43..1ec216f62 100644
--- a/krebs/3modules/git.nix
+++ b/krebs/3modules/git.nix
@@ -6,14 +6,14 @@
 # TODO when authorized_keys changes, then restart ssh
 #       (or kill already connected users somehow)
 
-with import <stockholm/lib>;
+with import ../../lib/pure.nix { inherit lib; };
 let
   cfg = config.krebs.git;
 
   out = {
     options.krebs.git = api;
-    config = with lib; mkIf cfg.enable (mkMerge [
-      (mkIf cfg.cgit.enable cgit-imp)
+    config = with lib; lib.mkIf cfg.enable (mkMerge [
+      (lib.mkIf cfg.cgit.enable cgit-imp)
       git-imp
     ]);
   };
@@ -446,7 +446,7 @@ let
       ];
       locations."/".extraConfig = ''
         include             ${pkgs.nginx}/conf/fastcgi_params;
-        fastcgi_param       SCRIPT_FILENAME ${pkgs.writeDash "cgit-wrapper" ''
+        fastcgi_param       SCRIPT_FILENAME ${pkgs.writers.writeDash "cgit-wrapper" ''
           set -efu
           exec 3>&1
           ${pkgs.cgit}/cgit/cgit.cgi "$@" 2>&1 >&3 3>&- \
diff --git a/krebs/3modules/github/hosts-sync.nix b/krebs/3modules/github/hosts-sync.nix
index 71eed6c69..6f9aee0ce 100644
--- a/krebs/3modules/github/hosts-sync.nix
+++ b/krebs/3modules/github/hosts-sync.nix
@@ -1,6 +1,6 @@
 { config, lib, pkgs, ... }:
 
-with import <stockholm/lib>;
+with lib;
 let
   cfg = config.krebs.github-hosts-sync;
 
diff --git a/krebs/3modules/go.nix b/krebs/3modules/go.nix
index 80cd90e27..9dc8fe6d2 100644
--- a/krebs/3modules/go.nix
+++ b/krebs/3modules/go.nix
@@ -1,6 +1,6 @@
 { config, lib, pkgs, ... }:
 
-with import <stockholm/lib>;
+with lib;
 
 let
   cfg = config.krebs.go;
diff --git a/krebs/3modules/hidden-ssh.nix b/krebs/3modules/hidden-ssh.nix
index acbe717d9..9ee4409e6 100644
--- a/krebs/3modules/hidden-ssh.nix
+++ b/krebs/3modules/hidden-ssh.nix
@@ -1,6 +1,6 @@
 { config, lib, pkgs, ... }:
 
-with import <stockholm/lib>;
+with lib;
 let
   cfg = config.krebs.hidden-ssh;
 
diff --git a/krebs/3modules/hosts.nix b/krebs/3modules/hosts.nix
index bd1bb1652..2333d0a8d 100644
--- a/krebs/3modules/hosts.nix
+++ b/krebs/3modules/hosts.nix
@@ -1,17 +1,19 @@
-with import <stockholm/lib>;
-{ config, ... }: let
+{ config, lib, pkgs, ... }:
+with lib; let
   check = hostname: any (domain: hasSuffix ".${domain}" hostname) domains;
-  domains = attrNames (filterAttrs (_: eq "hosts") config.krebs.dns.providers);
+  domains = attrNames (filterAttrs (_: slib.eq "hosts") config.krebs.dns.providers);
+  # we need this import because we have infinite recursion otherwise
+  slib = import ../../lib/pure.nix { inherit lib; };
 in {
 
   options = {
     krebs.hosts = mkOption {
       default = {};
-      type = types.attrsOf types.host;
+      type = types.attrsOf slib.types.host;
     };
   };
 
-  config = mkIf config.krebs.enable {
+  config = lib.mkIf config.krebs.enable {
     networking.hosts =
       filterAttrs
         (_name: value: value != [])
@@ -91,7 +93,7 @@ in {
             (concatLists (attrValues netAliases));
       }
       //
-      genAttrs' (attrNames netAliases) (netname: rec {
+      slib.genAttrs' (attrNames netAliases) (netname: rec {
         name = "krebs-hosts-${netname}";
         value = writeHosts name netAliases.${netname};
       });
diff --git a/krebs/3modules/htgen.nix b/krebs/3modules/htgen.nix
index b760ea671..334a83cb3 100644
--- a/krebs/3modules/htgen.nix
+++ b/krebs/3modules/htgen.nix
@@ -1,6 +1,6 @@
 { config, lib, pkgs, ... }:
 
-with import <stockholm/lib>;
+with import ../../lib/pure.nix { inherit lib; };
 let
   optionalAttr = name: value:
     if name != null then
diff --git a/krebs/3modules/iana-etc.nix b/krebs/3modules/iana-etc.nix
index 9ed5f29c5..3195f71d9 100644
--- a/krebs/3modules/iana-etc.nix
+++ b/krebs/3modules/iana-etc.nix
@@ -1,5 +1,5 @@
-with import <stockholm/lib>;
-{ config, pkgs, ... }: {
+{ config, pkgs, lib, ... }:
+with lib; {
 
   options.krebs.iana-etc.services = mkOption {
     default = {};
diff --git a/krebs/3modules/iptables.nix b/krebs/3modules/iptables.nix
index 052dad9c6..c1c5b68c8 100644
--- a/krebs/3modules/iptables.nix
+++ b/krebs/3modules/iptables.nix
@@ -1,6 +1,6 @@
 { config, lib, pkgs, ... }:
 
-with import <stockholm/lib>;
+with lib;
 
 let
   inherit (pkgs) writeText;
diff --git a/krebs/3modules/kapacitor.nix b/krebs/3modules/kapacitor.nix
index 2ec67c73d..89d2e2c14 100644
--- a/krebs/3modules/kapacitor.nix
+++ b/krebs/3modules/kapacitor.nix
@@ -1,7 +1,7 @@
 { config, lib, pkgs, ... }:
 
 with builtins;
-with import <stockholm/lib>;
+with lib;
 
 let
   cfg = config.krebs.kapacitor;
diff --git a/krebs/3modules/konsens.nix b/krebs/3modules/konsens.nix
index 81dbb33e1..0463de53f 100644
--- a/krebs/3modules/konsens.nix
+++ b/krebs/3modules/konsens.nix
@@ -1,6 +1,5 @@
 { config, lib, pkgs, ... }:
-
-with import <stockholm/lib>;
+with import ../../lib/pure.nix { inherit lib; };
 
 let
   cfg = config.krebs.konsens;
@@ -68,7 +67,7 @@ let
         serviceConfig = {
           Type = "simple";
           PermissionsStartOnly = true;
-          ExecStart = pkgs.writeDash "konsens-${name}" ''
+          ExecStart = pkgs.writers.writeDash "konsens-${name}" ''
             set -efu
             git config --global --replace-all safe.directory *
             if ! test -e ${name}; then
diff --git a/krebs/3modules/krebs-pages.nix b/krebs/3modules/krebs-pages.nix
index 6dd046a8b..face9e3a0 100644
--- a/krebs/3modules/krebs-pages.nix
+++ b/krebs/3modules/krebs-pages.nix
@@ -1,6 +1,5 @@
-{ config, modulesPath, pkgs, ... }: let
+{ config, modulesPath, pkgs, lib, ... }: let
   cfg = config.krebs.pages;
-  lib = import ../../lib;
   extraTypes.nginx-vhost = lib.types.submodule (
     lib.recursiveUpdate
       (import (modulesPath + "/services/web-servers/nginx/vhost-options.nix")
@@ -11,7 +10,7 @@ in {
   options.krebs.pages = {
     enable = lib.mkEnableOption "krebs-pages";
     domain = lib.mkOption {
-      type = lib.types.hostname;
+      type = pkgs.stockholm.lib.types.hostname;
       default = "krebsco.de";
     };
     nginx = lib.mkOption {
diff --git a/krebs/3modules/krebs.nix b/krebs/3modules/krebs.nix
new file mode 100644
index 000000000..ce63135ec
--- /dev/null
+++ b/krebs/3modules/krebs.nix
@@ -0,0 +1,8 @@
+{ config, lib, ... }:
+with lib;
+let
+  cfg = config.krebs;
+in {
+    options.krebs.enable = mkEnableOption "krebs";
+    config = lib.mkIf config.krebs.enable {};
+}
diff --git a/krebs/3modules/monit.nix b/krebs/3modules/monit.nix
index cc4a1b208..717316224 100644
--- a/krebs/3modules/monit.nix
+++ b/krebs/3modules/monit.nix
@@ -1,7 +1,7 @@
 { config, lib, pkgs, ... }:
 
 with builtins;
-with import <stockholm/lib>;
+with lib;
 
 let
   cfg = config.krebs.monit;
diff --git a/krebs/3modules/nixpkgs.nix b/krebs/3modules/nixpkgs.nix
index 796ee537e..e560df51d 100644
--- a/krebs/3modules/nixpkgs.nix
+++ b/krebs/3modules/nixpkgs.nix
@@ -1,5 +1,5 @@
 { config, lib, pkgs, ... }:
-with import <stockholm/lib>;
+with lib;
 let
   cfg = config.krebs.nixpkgs;
 
diff --git a/krebs/3modules/on-failure.nix b/krebs/3modules/on-failure.nix
index 4da303dec..11d2b4194 100644
--- a/krebs/3modules/on-failure.nix
+++ b/krebs/3modules/on-failure.nix
@@ -1,4 +1,4 @@
-{ config, lib, pkgs, ... }: with import <stockholm/lib>; let
+{ config, lib, pkgs, ... }: with import ../../lib/pure.nix { inherit lib; }; let
   out = {
     options.krebs.on-failure = api;
     config = lib.mkIf cfg.enable imp;
diff --git a/krebs/3modules/os-release.nix b/krebs/3modules/os-release.nix
index 5fbfe6614..bfd352825 100644
--- a/krebs/3modules/os-release.nix
+++ b/krebs/3modules/os-release.nix
@@ -1,5 +1,5 @@
-{ config, ... }:
-with import <stockholm/lib>;
+{ config, lib, ... }:
+with lib;
 let
   nixos-version-id = if (hasAttr "nixos" config.system) then
     "${config.system.nixos.version}" else "${config.system.nixosVersion}";
@@ -9,7 +9,7 @@ let
   nixos-pretty-name = "NixOS ${nixos-version}";
 
   stockholm-version-id = let
-    eval = tryEval (removeSuffix "\n" (readFile <stockholm-version>));
+    eval = builtins.tryEval (removeSuffix "\n" (readFile <stockholm-version>));
   in
     if eval.success then eval.value else "unknown";
 
diff --git a/krebs/3modules/per-user.nix b/krebs/3modules/per-user.nix
index 5beb859aa..c0368ee85 100644
--- a/krebs/3modules/per-user.nix
+++ b/krebs/3modules/per-user.nix
@@ -1,5 +1,5 @@
-with import <stockholm/lib>;
-{ config, pkgs, ... }: let
+{ config, pkgs, lib, ... }:
+with lib; let
   cfg = config.krebs.per-user;
 in {
   options.krebs.per-user = mkOption {
diff --git a/krebs/3modules/permown.nix b/krebs/3modules/permown.nix
index a4dd40386..3ebbc44fe 100644
--- a/krebs/3modules/permown.nix
+++ b/krebs/3modules/permown.nix
@@ -1,5 +1,5 @@
-with import <stockholm/lib>;
-{ config, pkgs, ... }: {
+{ config, pkgs, lib, ... }:
+with lib; {
 
   options.krebs.permown = mkOption {
     default = {};
diff --git a/krebs/3modules/reaktor2.nix b/krebs/3modules/reaktor2.nix
index 26aac5d5a..978e0c9c0 100644
--- a/krebs/3modules/reaktor2.nix
+++ b/krebs/3modules/reaktor2.nix
@@ -1,5 +1,5 @@
-with import <stockholm/lib>;
-{ config, pkgs, ... }: {
+{ config, pkgs, lib, ... }:
+with import ../../lib/pure.nix { inherit lib; }; {
 
   options.krebs.reaktor2 = mkOption {
     default = {};
diff --git a/krebs/3modules/realwallpaper.nix b/krebs/3modules/realwallpaper.nix
index f2b34e8c4..a65a22b29 100644
--- a/krebs/3modules/realwallpaper.nix
+++ b/krebs/3modules/realwallpaper.nix
@@ -1,6 +1,6 @@
 { config, lib, pkgs, ... }:
 
-with import <stockholm/lib>;
+with import ../../lib/pure.nix { inherit lib; };
 let
   cfg = config.krebs.realwallpaper;
 
diff --git a/krebs/3modules/repo-sync.nix b/krebs/3modules/repo-sync.nix
index 5b8a53be8..a6de3f3f6 100644
--- a/krebs/3modules/repo-sync.nix
+++ b/krebs/3modules/repo-sync.nix
@@ -1,6 +1,6 @@
 { config, lib, pkgs, ... }:
 
-with import <stockholm/lib>;
+with import ../../lib/pure.nix { inherit lib; };
 let
   cfg = config.krebs.repo-sync;
 
diff --git a/krebs/3modules/retiolum-bootstrap.nix b/krebs/3modules/retiolum-bootstrap.nix
index faa3dd714..c9ea8a619 100644
--- a/krebs/3modules/retiolum-bootstrap.nix
+++ b/krebs/3modules/retiolum-bootstrap.nix
@@ -1,5 +1,5 @@
-{ config, pkgs, ... }:
-with import <stockholm/lib>;
+{ config, pkgs, lib, ... }:
+with lib;
 let
   cfg = config.krebs.retiolum-bootstrap;
 in
diff --git a/krebs/3modules/secret.nix b/krebs/3modules/secret.nix
index 0c5e1cdcd..90c2f6a6d 100644
--- a/krebs/3modules/secret.nix
+++ b/krebs/3modules/secret.nix
@@ -1,5 +1,5 @@
-with import <stockholm/lib>;
-{ config, lib, pkgs, ... }: let
+{ config, lib, pkgs, ... }:
+with import ../../lib/pure.nix { inherit lib; }; let
   cfg = config.krebs.secret;
 in {
   options.krebs.secret = {
@@ -12,7 +12,7 @@ in {
       readOnly = true;
     };
     files = mkOption {
-      type = with types; attrsOf secret-file;
+      type = with pkgs.stockholm.lib.types; attrsOf secret-file;
       default = {};
     };
   };
diff --git a/krebs/3modules/setuid.nix b/krebs/3modules/setuid.nix
index e186478eb..53fed0e36 100644
--- a/krebs/3modules/setuid.nix
+++ b/krebs/3modules/setuid.nix
@@ -1,5 +1,6 @@
-with import <stockholm/lib>;
-{ config, pkgs, ... }: let
+{ config, pkgs, lib, ... }:
+with import ../../lib/pure.nix { inherit lib; };
+let
 
   out = {
     options.krebs.setuid = api;
diff --git a/krebs/3modules/shadow.nix b/krebs/3modules/shadow.nix
index f056cfd8e..281b446bb 100644
--- a/krebs/3modules/shadow.nix
+++ b/krebs/3modules/shadow.nix
@@ -1,5 +1,6 @@
-with import <stockholm/lib>;
-{ config, pkgs, ... }: let
+{ config, pkgs, lib, ... }:
+with lib;
+let
 
   cfg = config.krebs.shadow;
 
@@ -47,7 +48,7 @@ in {
       default = cfg.overridesFile != null;
     };
     overridesFile = mkOption {
-      apply = x: if typeOf x == "path" then toString x else x;
+      apply = x: if builtins.typeOf x == "path" then toString x else x;
       default = null;
       description = ''
         Path to a file containing additional shadow entries, used for adding
diff --git a/krebs/3modules/sitemap.nix b/krebs/3modules/sitemap.nix
index ec2179db1..906d556be 100644
--- a/krebs/3modules/sitemap.nix
+++ b/krebs/3modules/sitemap.nix
@@ -1,6 +1,5 @@
-let
-  lib = import ../../lib;
-in {
+{ lib, ... }:
+{
   options.krebs.sitemap = lib.mkOption {
     type = with lib.types; attrsOf sitemap.entry;
     default = {};
diff --git a/krebs/3modules/ssh.nix b/krebs/3modules/ssh.nix
new file mode 100644
index 000000000..58f3a3c10
--- /dev/null
+++ b/krebs/3modules/ssh.nix
@@ -0,0 +1,109 @@
+{ config, lib, ... }:
+with lib;
+let
+  cfg = config.krebs;
+
+  out = {
+    options.krebs = api;
+    config = lib.mkIf cfg.enable imp;
+  };
+
+  api = {
+    zone-head-config  = mkOption {
+      type = with types; attrsOf str;
+      description = ''
+        The zone configuration head which is being used to create the
+        zone files. The string for each key is pre-pended to the zone file.
+      '';
+      # TODO: configure the default somewhere else,
+      # maybe use krebs.dns.providers
+      default = {
+
+        # github.io -> 192.30.252.154
+        "krebsco.de" = ''
+          $TTL 86400
+          @ IN SOA dns19.ovh.net. tech.ovh.net. (2015052000 86400 3600 3600000 86400)
+                                IN NS     ns19.ovh.net.
+                                IN NS     dns19.ovh.net.
+        '';
+      };
+    };
+  };
+
+  imp = lib.mkMerge [
+    {
+      services.openssh.hostKeys =
+        let inherit (config.krebs.build.host.ssh) privkey; in
+        mkIf (privkey != null) [privkey];
+
+      services.openssh.knownHosts =
+        filterAttrs
+          (knownHostName: knownHost:
+            knownHost.publicKey != null &&
+            knownHost.hostNames != []
+          )
+          (mapAttrs
+            (hostName: host: {
+              hostNames =
+                concatLists
+                  (mapAttrsToList
+                    (netName: net:
+                      let
+                        aliases =
+                          concatLists [
+                            shortAliases
+                            net.aliases
+                            net.addrs
+                          ];
+                        shortAliases =
+                          optionals
+                            (cfg.dns.search-domain != null)
+                            (map (removeSuffix ".${cfg.dns.search-domain}")
+                                 (filter (hasSuffix ".${cfg.dns.search-domain}")
+                                         net.aliases));
+                        addPort = alias:
+                          if net.ssh.port != 22
+                            then "[${alias}]:${toString net.ssh.port}"
+                            else alias;
+                      in
+                      map addPort aliases
+                    )
+                    host.nets);
+              publicKey = host.ssh.pubkey;
+            })
+            (foldl' mergeAttrs {} [
+              cfg.hosts
+              {
+                localhost = {
+                  nets.local = {
+                    addrs = [ "127.0.0.1" "::1" ];
+                    aliases = [ "localhost" ];
+                    ssh.port = 22;
+                  };
+                  ssh.pubkey = config.krebs.build.host.ssh.pubkey;
+                };
+              }
+            ]));
+
+      programs.ssh.extraConfig = concatMapStrings
+        (net: ''
+          Host ${toString (net.aliases ++ net.addrs)}
+            Port ${toString net.ssh.port}
+        '')
+        (filter
+          (net: net.ssh.port != 22)
+          (concatMap (host: attrValues host.nets)
+            (mapAttrsToList
+              (_: host: recursiveUpdate host
+                (optionalAttrs (cfg.dns.search-domain != null &&
+                                hasAttr cfg.dns.search-domain host.nets) {
+                  nets."" = host.nets.${cfg.dns.search-domain} // {
+                    aliases = [host.name];
+                    addrs = [];
+                  };
+                }))
+              config.krebs.hosts)));
+    }
+  ];
+
+in out
diff --git a/krebs/3modules/sync-containers.nix b/krebs/3modules/sync-containers.nix
index 60ca993e6..fe64657dc 100644
--- a/krebs/3modules/sync-containers.nix
+++ b/krebs/3modules/sync-containers.nix
@@ -1,5 +1,6 @@
-with import <stockholm/lib>;
-{ config, pkgs, ... }: let
+{ config, pkgs, lib, ... }:
+with lib;
+let
   cfg = config.krebs.sync-containers;
   paths = cname: {
     plain = "/var/lib/containers/${cname}/var/state";
diff --git a/krebs/3modules/sync-containers3.nix b/krebs/3modules/sync-containers3.nix
index ed147b30e..c88dd5919 100644
--- a/krebs/3modules/sync-containers3.nix
+++ b/krebs/3modules/sync-containers3.nix
@@ -1,6 +1,6 @@
 { config, lib, pkgs, ... }: let
   cfg = config.krebs.sync-containers3;
-  slib = pkgs.stockholm.lib;
+  slib = import ../../lib/pure.nix { inherit lib; };
 in {
   options.krebs.sync-containers3 = {
     inContainer = {
diff --git a/krebs/3modules/systemd.nix b/krebs/3modules/systemd.nix
index 3e524d3b5..754b25675 100644
--- a/krebs/3modules/systemd.nix
+++ b/krebs/3modules/systemd.nix
@@ -1,5 +1,6 @@
-{ config, pkgs, ... }: let {
-  lib = import ../../lib;
+{ config, pkgs, lib, ... }: let {
+
+  slib = import ../../lib/pure.nix { inherit lib; };
 
   body.options.krebs.systemd.services = lib.mkOption {
     default = {};
@@ -13,14 +14,14 @@
             lib.sort
               lib.lessThan
               (lib.filter
-                lib.types.absolute-pathname.check
+                slib.types.absolute-pathname.check
                 (map
-                  (lib.compose [ lib.maybeHead (lib.match "[^:]*:(.*)") ])
+                  (slib.compose [ slib.maybeHead (builtins.match "[^:]*:(.*)") ])
                   (lib.toList cfg.serviceConfig.LoadCredential)));
           readOnly = true;
         };
         credentialUnitName = lib.mkOption {
-          default = "trigger-${lib.systemd.encodeName serviceName}";
+          default = "trigger-${slib.systemd.encodeName serviceName}";
           readOnly = true;
         };
         restartIfCredentialsChange = lib.mkOption {
@@ -54,7 +55,7 @@
             pkgs.systemd
           ]}
 
-          cache=/var/lib/credentials/${lib.shell.escape serviceName}.sha1sum
+          cache=/var/lib/credentials/${slib.shell.escape serviceName}.sha1sum
           tmpfile=$(mktemp -t "$(basename "$cache")".XXXXXXXX)
           trap 'rm -f "$tmpfile"' EXIT
 
@@ -64,7 +65,7 @@
           fi
           mv "$tmpfile" "$cache"
 
-          systemctl restart ${lib.shell.escape serviceName}
+          systemctl restart ${slib.shell.escape serviceName}
         '';
       };
     };
diff --git a/krebs/3modules/tinc.nix b/krebs/3modules/tinc.nix
index 437f3b633..2f9efad46 100644
--- a/krebs/3modules/tinc.nix
+++ b/krebs/3modules/tinc.nix
@@ -1,5 +1,5 @@
-with import <stockholm/lib>;
-{ config, pkgs, ... }: {
+{ config, pkgs, lib, ... }:
+with import ../../lib/pure.nix { inherit lib; }; {
   options.krebs.tinc = mkOption {
     default = {};
     description = ''
diff --git a/krebs/3modules/tinc_graphs.nix b/krebs/3modules/tinc_graphs.nix
index 733db69ca..dd132a2de 100644
--- a/krebs/3modules/tinc_graphs.nix
+++ b/krebs/3modules/tinc_graphs.nix
@@ -1,6 +1,6 @@
 { config, lib, pkgs, ... }:
 
-with import <stockholm/lib>;
+with import ../../lib/pure.nix { inherit lib; };
 let
   cfg = config.krebs.tinc_graphs;
   internal_dir = "${cfg.workingDir}/internal";
diff --git a/krebs/3modules/upstream/default.nix b/krebs/3modules/upstream/default.nix
index ce7bd1644..91de6beeb 100644
--- a/krebs/3modules/upstream/default.nix
+++ b/krebs/3modules/upstream/default.nix
@@ -1,4 +1,5 @@
-with import <stockholm/lib>;
+{ pkgs, lib, ... }:
+with lib;
 
 {
   imports =
@@ -6,5 +7,5 @@ with import <stockholm/lib>;
       (name: ./. + "/${name}")
       (filter
         (name: name != "default.nix" && !hasPrefix "." name)
-        (attrNames (readDir ./.)));
+        (attrNames (builtins.readDir ./.)));
 }
diff --git a/krebs/3modules/upstream/desktop-managers/coma.nix b/krebs/3modules/upstream/desktop-managers/coma.nix
index 95db7fb5c..e12f4b981 100644
--- a/krebs/3modules/upstream/desktop-managers/coma.nix
+++ b/krebs/3modules/upstream/desktop-managers/coma.nix
@@ -1,5 +1,6 @@
-with import <stockholm/lib>;
-{ config, pkgs, ... }: {
+{ config, pkgs, lib, ... }:
+with lib;
+{
   options = {
     services.xserver.desktopManager.coma = {
       enable = mkEnableOption "sleep as a desktop manager";
diff --git a/krebs/3modules/upstream/desktop-managers/none.nix b/krebs/3modules/upstream/desktop-managers/none.nix
index 892def985..77f7ad513 100644
--- a/krebs/3modules/upstream/desktop-managers/none.nix
+++ b/krebs/3modules/upstream/desktop-managers/none.nix
@@ -1,9 +1,9 @@
+{ lib, ... }:
 # Replace upstream none desktop-manager by a real none, that doesn't pull in
 # any dependencies.
-with import <stockholm/lib>;
 {
-  disabledModules = singleton "services/x11/desktop-managers/none.nix";
-  config.services.xserver.desktopManager.session = singleton {
+  disabledModules = lib.singleton "services/x11/desktop-managers/none.nix";
+  config.services.xserver.desktopManager.session = lib.singleton {
     name = "none";
     bgSupport = true;
     start = "";
diff --git a/krebs/3modules/upstream/window-managers/default.nix b/krebs/3modules/upstream/window-managers/default.nix
index eecadca7e..cdd82076d 100644
--- a/krebs/3modules/upstream/window-managers/default.nix
+++ b/krebs/3modules/upstream/window-managers/default.nix
@@ -13,8 +13,8 @@
       imports = [ ./xmonad.nix ];
       nixpkgs.overlays = [(self: super: {
         writers = super.writers // {
-          writeHaskellBin = name: spec: with import <stockholm/lib>;
-            super.writers.writeHaskellBin name (removeAttrs spec ["ghcArgs"]);
+          writeHaskellBin = name: spec:
+            super.writers.writeHaskellBin name (builtins.removeAttrs spec ["ghcArgs"]);
         };
       })];
     }
diff --git a/krebs/3modules/urlwatch.nix b/krebs/3modules/urlwatch.nix
index 113f6e65d..b811b6fa6 100644
--- a/krebs/3modules/urlwatch.nix
+++ b/krebs/3modules/urlwatch.nix
@@ -4,7 +4,7 @@
 # TODO inform about unused caches
 # cache = url: "${cfg.dataDir}/.urlwatch/cache/${hashString "sha1" url}"
 
-with import <stockholm/lib>;
+with import ../../lib/pure.nix { inherit lib; };
 let
   cfg = config.krebs.urlwatch;
 
diff --git a/krebs/3modules/users.nix b/krebs/3modules/users.nix
index c1ad4b44b..614e6ab42 100644
--- a/krebs/3modules/users.nix
+++ b/krebs/3modules/users.nix
@@ -1,8 +1,8 @@
-{ config, ... }: let
-  lib = import ../../lib;
+{ config, lib, pkgs, ... }: let
+  slib = import ../../lib/pure.nix { inherit lib; };
 in {
   options.krebs.users = lib.mkOption {
-    type = with lib.types; attrsOf user;
+    type = lib.types.attrsOf slib.types.user;
   };
   config = lib.mkIf config.krebs.enable {
     krebs.users = {
diff --git a/krebs/3modules/zones.nix b/krebs/3modules/zones.nix
index 51ced6f95..7771d3b51 100644
--- a/krebs/3modules/zones.nix
+++ b/krebs/3modules/zones.nix
@@ -1,5 +1,5 @@
-with import <stockholm/lib>;
-{ config, pkgs, ... }: {
+{ config, pkgs, lib, ... }:
+with lib; {
 
   config = {
     environment.etc =
diff --git a/krebs/5pkgs/default.nix b/krebs/5pkgs/default.nix
index f9ed6439c..866796a4e 100644
--- a/krebs/5pkgs/default.nix
+++ b/krebs/5pkgs/default.nix
@@ -1,8 +1,11 @@
-let
-  stockholm.lib = import ../../lib;
+self: super: let
+  stockholm = {
+    lib = import ../../lib/pure.nix { lib = super.lib; };
+    outPath = toString ../.;
+  };
 in
 with stockholm.lib;
-self: super:
+
 fix (foldl' (flip extends) (self: super) (
   [
     (self: super: { inherit stockholm; })
diff --git a/krebs/5pkgs/simple/reaktor2-plugins.nix b/krebs/5pkgs/simple/reaktor2-plugins.nix
index 052e389a6..651062b0a 100644
--- a/krebs/5pkgs/simple/reaktor2-plugins.nix
+++ b/krebs/5pkgs/simple/reaktor2-plugins.nix
@@ -1,5 +1,5 @@
 { lib, pkgs, stockholm, ... }:
-with stockholm.lib;
+with (builtins.trace (lib.attrNames stockholm) stockholm).lib;
 
 rec {
   generators = {
@@ -15,27 +15,27 @@ rec {
   commands = {
 
     random-emoji = {
-      filename = <stockholm/krebs/5pkgs/simple/Reaktor/scripts/random-emoji.sh>;
+      filename = stockholm.outPath + "/krebs/5pkgs/simple/Reaktor/scripts/random-emoji.sh";
       env = {
         PATH = makeBinPath (with pkgs; [ coreutils gnused gnugrep xmlstarlet wget ]);
       };
     };
 
     dance = {
-      filename = pkgs.writeDash "dance" ''
+      filename = pkgs.writers.writeDash "dance" ''
         ${pkgs.krebsdance}/bin/krebsdance --dance "$@";
       '';
     };
 
     nixos-version = {
-      filename = pkgs.writeDash "nixos-version" ''
+      filename = pkgs.writers.writeDash "nixos-version" ''
         . /etc/os-release
         echo "$PRETTY_NAME"
       '';
     };
 
     stockholm-issue = {
-      filename = <stockholm/krebs/5pkgs/simple/Reaktor/scripts/random-issue.sh>;
+      filename = stockholm.outPath + "/krebs/5pkgs/simple/Reaktor/scripts/random-issue.sh";
       env = {
         PATH = makeBinPath (with pkgs; [ coreutils git gnused haskellPackages.lentil ]);
         origin = "http://cgit.gum/stockholm";
@@ -56,10 +56,10 @@ rec {
           PATH = makeBinPath (with pkgs; [ gnused ]);
           state_dir = "/tmp";
         };
-        filename = pkgs.writeDash "sed-plugin" ''
+        filename = pkgs.writers.writeDash "sed-plugin" ''
           set -efu
           exec ${pkgs.python3}/bin/python \
-              ${<stockholm/krebs/5pkgs/simple/Reaktor/scripts/sed-plugin.py>} "$@"
+              ${stockholm.outPath + "/krebs/5pkgs/simple/Reaktor/scripts/sed-plugin.py"} "$@"
         '';
       };
     };
@@ -68,7 +68,7 @@ rec {
       activate = "match";
       pattern = "^(.*Shack.*)$";
       arguments = [1];
-      command.filename = <stockholm/krebs/5pkgs/simple/Reaktor/scripts/shack-correct.sh>;
+      command.filename = stockholm.outPath + "/krebs/5pkgs/simple/Reaktor/scripts/shack-correct.sh";
     };
 
 
diff --git a/krebs/default.nix b/krebs/default.nix
index 577cc269e..8cfdae484 100644
--- a/krebs/default.nix
+++ b/krebs/default.nix
@@ -1,4 +1,4 @@
-{
+args: {
 
   imports = [
     ./3modules
@@ -6,7 +6,7 @@
 
   nixpkgs = {
     overlays = [
-      (import ../submodules/nix-writers/pkgs)
+      (import ((args.nix-writers or ../submodules/nix-writers) + "/pkgs"))
       (import ./5pkgs)
     ];
   };
diff --git a/lass/2configs/baseX.nix b/lass/2configs/baseX.nix
index bb01d3dcd..654247728 100644
--- a/lass/2configs/baseX.nix
+++ b/lass/2configs/baseX.nix
@@ -99,7 +99,6 @@ in {
       ${pkgs.flameshot}/bin/flameshot gui
       ${pkgs.klem}/bin/klem
     '')
-
   ];
 
   services.udev.extraRules = ''
diff --git a/lass/3modules/default.nix b/lass/3modules/default.nix
index 0e1a794ca..4082c8bd2 100644
--- a/lass/3modules/default.nix
+++ b/lass/3modules/default.nix
@@ -1,6 +1,7 @@
 _:
 {
   imports = [
+    ../../submodules/disko/module.nix
     ./dnsmasq.nix
     ./drbd.nix
     ./folderPerms.nix
diff --git a/lib/default.nix b/lib/default.nix
index 187514a30..f9f2f1579 100644
--- a/lib/default.nix
+++ b/lib/default.nix
@@ -1,225 +1 @@
-let
-  nixpkgs-lib = import <nixpkgs/lib>;
-  lib = with lib; nixpkgs-lib // builtins // {
-
-    evalModulesConfig = modules: let
-      eval = evalModules {
-        inherit modules;
-      };
-    in filterAttrsRecursive (name: _: !hasPrefix "_" name) eval.config;
-
-    evalSource = import ./eval-source.nix;
-
-    evalSubmodule = submodule: modules: let
-      prefix = ["evalSubmodule"];
-    in evalModulesConfig [
-      {
-        options = removeAttrs (submodule.getSubOptions prefix) ["_module"];
-        imports = modules;
-      }
-    ];
-
-    git = import ./git.nix { inherit lib; };
-    haskell = import ./haskell.nix { inherit lib; };
-    krebs = import ./krebs lib;
-    krops = import ../submodules/krops/lib;
-    shell = import ./shell.nix { inherit lib; };
-    systemd = {
-      encodeName = replaceChars ["/"] ["\\x2f"];
-    };
-    types = nixpkgs-lib.types // import ./types.nix { inherit lib; };
-    uri = import ./uri.nix { inherit lib; };
-    xml = import ./xml.nix { inherit lib; };
-
-    # compose a list of functions to be applied from left to right, i.e.
-    # compose :: [ (xm -> xn) ... (x1 -> x2) (x0 -> x1) ] -> x0 -> xn
-    compose = foldl' (f: g: x: f (g x)) id;
-
-    eq = x: y: x == y;
-    ne = x: y: x != y;
-    mod = x: y: x - y * (x / y);
-
-    on = b: u: x: y: b (u x) (u y);
-
-    genid = lib.genid_uint32; # TODO remove
-    genid_uint31 = x: ((lib.genid_uint32 x) + 16777216) / 2;
-    genid_uint32 = import ./genid.nix { inherit lib; };
-
-    hexchars = stringToCharacters "0123456789abcdef";
-
-    lpad = n: c: s:
-      if lib.stringLength s < n
-        then lib.lpad n c (c + s)
-        else s;
-
-    genAttrs' = names: f: listToAttrs (map f names);
-
-    getAttrs = names: set:
-      listToAttrs (map (name: nameValuePair name set.${name})
-                       (filter (flip hasAttr set) names));
-
-    maybeHead = x: if isList x && length x > 0 then head x else null;
-
-    packageName = pkg:
-      pkg.pname or (parseDrvName pkg.name).name;
-
-    test = re: x: isString x && testString re x;
-
-    testString = re: x: match re x != null;
-
-    toC = x: let
-      type = typeOf x;
-      reject = throw "cannot convert ${type}";
-    in {
-      int = toJSON x; # close enough
-      list = "{ ${concatStringsSep ", " (map toC x)} }";
-      null = "NULL";
-      set = if isDerivation x then toJSON x else reject;
-      string = toJSON x; # close enough
-    }.${type} or reject;
-
-    indent = replaceChars ["\n"] ["\n  "];
-
-    stripAttr = converge (filterAttrsRecursive (n: v: v != {} && v != null));
-
-    mapNixDir = f: x: {
-      list = foldl' mergeAttrs {} (map (mapNixDir1 f) x);
-      path = mapNixDir1 f x;
-    }.${typeOf x};
-
-    mapNixDir1 = f: dirPath:
-      let
-        toPackageName = name:
-          if test "^[0-9].*" name then "_${name}" else name;
-      in
-      listToAttrs
-        (map
-          (relPath: let
-            name = removeSuffix ".nix" relPath;
-            path = dirPath + "/${relPath}";
-          in
-            nameValuePair (toPackageName name) (f path))
-          (attrNames
-            (filterAttrs isNixDirEntry (readDir dirPath))));
-
-    isNixDirEntry = name: type:
-      (type == "regular" && hasSuffix ".nix" name && name != "default.nix") ||
-      (type == "directory" && !hasPrefix "." name);
-
-    # https://tools.ietf.org/html/rfc5952
-    normalize-ip6-addr =
-      let
-        max-run-0 =
-          let
-            both = v: { off = v; pos = v; };
-            gt = a: b: a.pos - a.off > b.pos - b.off;
-
-            chkmax = ctx: {
-              cur = both (ctx.cur.pos + 1);
-              max = if gt ctx.cur ctx.max then ctx.cur else ctx.max;
-            };
-
-            incpos = ctx: recursiveUpdate ctx {
-              cur.pos = ctx.cur.pos + 1;
-            };
-
-            f = ctx: blk: (if blk == "0" then incpos else chkmax) ctx;
-            z = { cur = both 0; max = both 0; };
-          in
-            blks: (chkmax (foldl' f z blks)).max;
-
-        group-zeros = a:
-          let
-            blks = splitString ":" a;
-            max = max-run-0 blks;
-            lhs = take max.off blks;
-            rhs = drop max.pos blks;
-          in
-            if max.pos == 0
-              then a
-              else let
-                sep =
-                  if 8 - (length lhs + length rhs) == 1
-                    then ":0:"
-                    else "::";
-              in
-                "${concatStringsSep ":" lhs}${sep}${concatStringsSep ":" rhs}";
-
-        drop-leading-zeros =
-          let
-            f = block:
-              let
-                res = match "0*(.+)" block;
-              in
-                if res == null
-                  then block # empty block
-                  else elemAt res 0;
-          in
-            a: concatStringsSep ":" (map f (splitString ":" a));
-      in
-        a:
-          toLower
-            (if test ".*::.*" a
-              then a
-              else group-zeros (drop-leading-zeros a));
-
-    hashToLength = n: s: substring 0 n (hashString "sha256" s);
-
-    dropLast = n: xs: reverseList (drop n (reverseList xs));
-    takeLast = n: xs: reverseList (take n (reverseList xs));
-
-    # Split string into list of chunks where each chunk is at most n chars long.
-    # The leftmost chunk might shorter.
-    # Example: stringToGroupsOf "123456" -> ["12" "3456"]
-    stringToGroupsOf = n: s: let
-      acc =
-        foldl'
-          (acc: c: if stringLength acc.chunk < n then {
-            chunk = acc.chunk + c;
-            chunks = acc.chunks;
-          } else {
-            chunk = c;
-            chunks = acc.chunks ++ [acc.chunk];
-          })
-          {
-            chunk = "";
-            chunks = [];
-          }
-          (stringToCharacters s);
-    in
-      filter (x: x != []) ([acc.chunk] ++ acc.chunks);
-
-    # Filter adjacent duplicate elements.
-    uniq = uniqBy eq;
-
-    # Filter adjacent duplicate elements determined via the given function.
-    uniqBy = cmp: let
-      f = a: s:
-        if length s == 0 then
-          []
-        else let
-          b = head s;
-        in
-          if cmp a b then
-            f b (tail s)
-          else
-            [b] ++ f b (tail s);
-    in
-      s:
-        if length s == 0 then
-          []
-        else let
-          b = head s;
-        in
-          [b] ++ f b (tail s);
-
-    warnOldVersion = oldName: newName:
-      if compareVersions oldName newName != -1 then
-        trace "Upstream `${oldName}' gets overridden by `${newName}'." newName
-      else
-        newName;
-  };
-in
-
-lib
-// { inherit lib; }
+import ./impure.nix
diff --git a/lib/impure.nix b/lib/impure.nix
new file mode 100644
index 000000000..3f95c375f
--- /dev/null
+++ b/lib/impure.nix
@@ -0,0 +1,3 @@
+import ./pure.nix {
+  lib = import <nixpkgs/lib>;
+}
diff --git a/lib/pure.nix b/lib/pure.nix
new file mode 100644
index 000000000..bb2d586f6
--- /dev/null
+++ b/lib/pure.nix
@@ -0,0 +1,227 @@
+{ lib, ... }:
+let
+  nixpkgs-lib = lib;
+  stockholm.lib = with stockholm.lib; nixpkgs-lib // builtins // {
+
+    evalModulesConfig = modules: let
+      eval = evalModules {
+        inherit modules;
+      };
+    in filterAttrsRecursive (name: _: !hasPrefix "_" name) eval.config;
+
+    evalSource = import ./eval-source.nix;
+
+    evalSubmodule = submodule: modules: let
+      prefix = ["evalSubmodule"];
+    in evalModulesConfig [
+      {
+        options = removeAttrs (submodule.getSubOptions prefix) ["_module"];
+        imports = modules;
+      }
+    ];
+
+    git = import ./git.nix { inherit (stockholm) lib; };
+    haskell = import ./haskell.nix { inherit (stockholm) lib; };
+    krebs = import ./krebs stockholm.lib;
+    krops = import ../submodules/krops/lib;
+    shell = import ./shell.nix { inherit (stockholm) lib; };
+    systemd = {
+      encodeName = replaceChars ["/"] ["\\x2f"];
+    };
+    types = nixpkgs-lib.types // import ./types.nix { lib = stockholm.lib; };
+    uri = import ./uri.nix { inherit (stockholm) lib; };
+    xml = import ./xml.nix { inherit (stockholm) lib; };
+
+    # compose a list of functions to be applied from left to right, i.e.
+    # compose :: [ (xm -> xn) ... (x1 -> x2) (x0 -> x1) ] -> x0 -> xn
+    compose = foldl' (f: g: x: f (g x)) id;
+
+    eq = x: y: x == y;
+    ne = x: y: x != y;
+    mod = x: y: x - y * (x / y);
+
+    on = b: u: x: y: b (u x) (u y);
+
+    genid = stockholm.lib.genid_uint32; # TODO remove
+    genid_uint31 = x: ((stockholm.lib.genid_uint32 x) + 16777216) / 2;
+    genid_uint32 = import ./genid.nix { lib = stockholm.lib; };
+
+    hexchars = stringToCharacters "0123456789abcdef";
+
+    lpad = n: c: s:
+      if lib.stringLength s < n
+        then stockholm.lib.lpad n c (c + s)
+        else s;
+
+    genAttrs' = names: f: listToAttrs (map f names);
+
+    getAttrs = names: set:
+      listToAttrs (map (name: nameValuePair name set.${name})
+                       (filter (flip hasAttr set) names));
+
+    maybeHead = x: if isList x && length x > 0 then head x else null;
+
+    packageName = pkg:
+      pkg.pname or (parseDrvName pkg.name).name;
+
+    test = re: x: isString x && testString re x;
+
+    testString = re: x: match re x != null;
+
+    toC = x: let
+      type = typeOf x;
+      reject = throw "cannot convert ${type}";
+    in {
+      int = toJSON x; # close enough
+      list = "{ ${concatStringsSep ", " (map toC x)} }";
+      null = "NULL";
+      set = if isDerivation x then toJSON x else reject;
+      string = toJSON x; # close enough
+    }.${type} or reject;
+
+    indent = replaceChars ["\n"] ["\n  "];
+
+    stripAttr = converge (filterAttrsRecursive (n: v: v != {} && v != null));
+
+    mapNixDir = f: x: {
+      list = foldl' mergeAttrs {} (map (mapNixDir1 f) x);
+      path = mapNixDir1 f x;
+    }.${typeOf x};
+
+    mapNixDir1 = f: dirPath:
+      let
+        toPackageName = name:
+          if test "^[0-9].*" name then "_${name}" else name;
+      in
+      listToAttrs
+        (map
+          (relPath: let
+            name = removeSuffix ".nix" relPath;
+            path = dirPath + "/${relPath}";
+          in
+            nameValuePair (toPackageName name) (f path))
+          (attrNames
+            (filterAttrs isNixDirEntry (readDir dirPath))));
+
+    isNixDirEntry = name: type:
+      (type == "regular" && hasSuffix ".nix" name && name != "default.nix") ||
+      (type == "directory" && !hasPrefix "." name);
+
+    # https://tools.ietf.org/html/rfc5952
+    normalize-ip6-addr =
+      let
+        max-run-0 =
+          let
+            both = v: { off = v; pos = v; };
+            gt = a: b: a.pos - a.off > b.pos - b.off;
+
+            chkmax = ctx: {
+              cur = both (ctx.cur.pos + 1);
+              max = if gt ctx.cur ctx.max then ctx.cur else ctx.max;
+            };
+
+            incpos = ctx: recursiveUpdate ctx {
+              cur.pos = ctx.cur.pos + 1;
+            };
+
+            f = ctx: blk: (if blk == "0" then incpos else chkmax) ctx;
+            z = { cur = both 0; max = both 0; };
+          in
+            blks: (chkmax (foldl' f z blks)).max;
+
+        group-zeros = a:
+          let
+            blks = splitString ":" a;
+            max = max-run-0 blks;
+            lhs = take max.off blks;
+            rhs = drop max.pos blks;
+          in
+            if max.pos == 0
+              then a
+              else let
+                sep =
+                  if 8 - (length lhs + length rhs) == 1
+                    then ":0:"
+                    else "::";
+              in
+                "${concatStringsSep ":" lhs}${sep}${concatStringsSep ":" rhs}";
+
+        drop-leading-zeros =
+          let
+            f = block:
+              let
+                res = match "0*(.+)" block;
+              in
+                if res == null
+                  then block # empty block
+                  else elemAt res 0;
+          in
+            a: concatStringsSep ":" (map f (splitString ":" a));
+      in
+        a:
+          toLower
+            (if test ".*::.*" a
+              then a
+              else group-zeros (drop-leading-zeros a));
+
+    hashToLength = n: s: substring 0 n (hashString "sha256" s);
+
+    dropLast = n: xs: reverseList (drop n (reverseList xs));
+    takeLast = n: xs: reverseList (take n (reverseList xs));
+
+    # Split string into list of chunks where each chunk is at most n chars long.
+    # The leftmost chunk might shorter.
+    # Example: stringToGroupsOf "123456" -> ["12" "3456"]
+    stringToGroupsOf = n: s: let
+      acc =
+        foldl'
+          (acc: c: if stringLength acc.chunk < n then {
+            chunk = acc.chunk + c;
+            chunks = acc.chunks;
+          } else {
+            chunk = c;
+            chunks = acc.chunks ++ [acc.chunk];
+          })
+          {
+            chunk = "";
+            chunks = [];
+          }
+          (stringToCharacters s);
+    in
+      filter (x: x != []) ([acc.chunk] ++ acc.chunks);
+
+    # Filter adjacent duplicate elements.
+    uniq = uniqBy eq;
+
+    # Filter adjacent duplicate elements determined via the given function.
+    uniqBy = cmp: let
+      f = a: s:
+        if length s == 0 then
+          []
+        else let
+          b = head s;
+        in
+          if cmp a b then
+            f b (tail s)
+          else
+            [b] ++ f b (tail s);
+    in
+      s:
+        if length s == 0 then
+          []
+        else let
+          b = head s;
+        in
+          [b] ++ f b (tail s);
+
+    warnOldVersion = oldName: newName:
+      if compareVersions oldName newName != -1 then
+        trace "Upstream `${oldName}' gets overridden by `${newName}'." newName
+      else
+        newName;
+  };
+in
+
+stockholm.lib
+// { lib = stockholm.lib; }
+
diff --git a/tv/2configs/sshd.nix b/tv/2configs/sshd.nix
index 0610e3c98..59c95ccba 100644
--- a/tv/2configs/sshd.nix
+++ b/tv/2configs/sshd.nix
@@ -1,6 +1,9 @@
 with import ./lib;
 { config, ... }: let
   cfg.host = config.krebs.build.host;
+  nets =
+    optional (cfg.host.nets?retiolum) cfg.host.nets.retiolum ++
+    optional (cfg.host.nets?wiregrill) cfg.host.nets.wiregrill;
 in {
   services.openssh = {
     enable = true;
@@ -12,15 +15,11 @@ in {
   tv.iptables.extra4.nat.PREROUTING =
     map
       (net: "-d ${net.ip4.addr} -p tcp --dport 22 -j ACCEPT")
-      (filter (net: net.ip4 != null)
-              [
-                cfg.host.nets.retiolum
-                cfg.host.nets.wiregrill
-              ]);
-  tv.iptables.extra6.nat.PREROUTING = [
-    "-d ${cfg.host.nets.retiolum.ip6.addr} -p tcp --dport 22 -j ACCEPT"
-    "-d ${cfg.host.nets.wiregrill.ip6.addr} -p tcp --dport 22 -j ACCEPT"
-  ];
+      (filter (net: net.ip4 != null) nets);
+  tv.iptables.extra6.nat.PREROUTING =
+    map
+      (net: "-d ${net.ip6.addr} -p tcp --dport 22 -j ACCEPT")
+      (filter (net: net.ip6 != null) nets);
   tv.iptables.extra.nat.PREROUTING = [
     "-p tcp --dport 22 -j REDIRECT --to-ports 0"
     "-p tcp --dport 11423 -j REDIRECT --to-ports 22"