summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--.dir-locals.el20
-rw-r--r--flake.lock439
-rw-r--r--flake.nix90
-rw-r--r--npins/sources.json34
m---------packages0
m---------private0
-rw-r--r--shell.nix2
-rw-r--r--system/linde.nix70
-rw-r--r--system/mba.nix31
-rwxr-xr-xsystem/nanopi.nix47
-rw-r--r--system/prefect.nix48
-rw-r--r--system/settings/dev.nix62
-rw-r--r--system/settings/gaming.nix4
-rw-r--r--system/settings/services/git-server.nix35
-rw-r--r--user/config.nix17
-rw-r--r--user/emacs/init.el41
-rw-r--r--user/mba.nix1
-rw-r--r--user/nanopi.nix1
-rw-r--r--user/prefect.nix1
-rw-r--r--user/settings/development/base.nix4
-rw-r--r--user/settings/development/javascript.nix4
-rw-r--r--user/settings/development/web.nix61
-rw-r--r--user/settings/emacs.nix1
-rw-r--r--user/settings/git.nix2
-rw-r--r--user/settings/nix.nix2
-rw-r--r--user/settings/nixos.nix4
-rw-r--r--user/settings/shell.nix1
-rw-r--r--user/settings/user-interface.nix4
28 files changed, 397 insertions, 629 deletions
diff --git a/.dir-locals.el b/.dir-locals.el
index e352b5ac..d9b7c0ae 100644
--- a/.dir-locals.el
+++ b/.dir-locals.el
@@ -1,4 +1,22 @@
 ;;; Directory Local Variables
 ;;; For more information see (info "(emacs) Directory Variables")
 
-((nil . ((compile-command . "./bin/home-manager switch"))))
+((nil . ((compile-command . "./bin/home-manager switch")))
+ ("system/nanopi.nix" .
+  ((nil . ((ssh-deploy-root-local . "/home/alan/projects/alanpearce.eu/nixfiles/")
+           (ssh-deploy-root-remote . "/sshx:nanopi:projects/alanpearce.eu/nixfiles/")
+           (ssh-deploy-on-explicit-save . 1)))))
+ ("user/nanopi.nix" .
+  ((nil . ((ssh-deploy-root-local . "/home/alan/projects/alanpearce.eu/nixfiles/")
+           (ssh-deploy-root-remote . "/sshx:nanopi:projects/alanpearce.eu/nixfiles/")
+           (ssh-deploy-on-explicit-save . 1)))))
+ ("system/linde.nix" .
+  ((nil . ((ssh-deploy-root-local . "/home/alan/projects/alanpearce.eu/nixfiles/")
+           (ssh-deploy-root-remote . "/sshx:linde:projects/alanpearce.eu/nixfiles/")
+           (ssh-deploy-on-explicit-save . 1)
+           (ssh-deploy-async . 1)))))
+ ("system/linde-hardware.nix" .
+  ((nil . ((ssh-deploy-root-local . "/home/alan/projects/alanpearce.eu/nixfiles/")
+           (ssh-deploy-root-remote . "/sshx:linde:projects/alanpearce.eu/nixfiles/")
+           (ssh-deploy-on-explicit-save . 1)
+           (ssh-deploy-async . 1))))))
diff --git a/flake.lock b/flake.lock
deleted file mode 100644
index 74c84f26..00000000
--- a/flake.lock
+++ /dev/null
@@ -1,439 +0,0 @@
-{
-  "nodes": {
-    "agenix": {
-      "inputs": {
-        "darwin": "darwin",
-        "home-manager": "home-manager",
-        "nixpkgs": [
-          "nixpkgs"
-        ],
-        "systems": "systems"
-      },
-      "locked": {
-        "lastModified": 1716561646,
-        "narHash": "sha256-UIGtLO89RxKt7RF2iEgPikSdU53r6v/6WYB0RW3k89I=",
-        "owner": "ryantm",
-        "repo": "agenix",
-        "rev": "c2fc0762bbe8feb06a2e59a364fa81b3a57671c9",
-        "type": "github"
-      },
-      "original": {
-        "owner": "ryantm",
-        "repo": "agenix",
-        "type": "github"
-      }
-    },
-    "darwin": {
-      "inputs": {
-        "nixpkgs": [
-          "agenix",
-          "nixpkgs"
-        ]
-      },
-      "locked": {
-        "lastModified": 1700795494,
-        "narHash": "sha256-gzGLZSiOhf155FW7262kdHo2YDeugp3VuIFb4/GGng0=",
-        "owner": "lnl7",
-        "repo": "nix-darwin",
-        "rev": "4b9b83d5a92e8c1fbfd8eb27eda375908c11ec4d",
-        "type": "github"
-      },
-      "original": {
-        "owner": "lnl7",
-        "ref": "master",
-        "repo": "nix-darwin",
-        "type": "github"
-      }
-    },
-    "flake-compat": {
-      "flake": false,
-      "locked": {
-        "lastModified": 1696426674,
-        "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
-        "owner": "edolstra",
-        "repo": "flake-compat",
-        "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
-        "type": "github"
-      },
-      "original": {
-        "owner": "edolstra",
-        "repo": "flake-compat",
-        "type": "github"
-      }
-    },
-    "flake-utils": {
-      "inputs": {
-        "systems": "systems_2"
-      },
-      "locked": {
-        "lastModified": 1709126324,
-        "narHash": "sha256-q6EQdSeUZOG26WelxqkmR7kArjgWCdw5sfJVHPH/7j8=",
-        "owner": "numtide",
-        "repo": "flake-utils",
-        "rev": "d465f4819400de7c8d874d50b982301f28a84605",
-        "type": "github"
-      },
-      "original": {
-        "owner": "numtide",
-        "repo": "flake-utils",
-        "type": "github"
-      }
-    },
-    "flake-utils_2": {
-      "inputs": {
-        "systems": "systems_3"
-      },
-      "locked": {
-        "lastModified": 1710146030,
-        "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
-        "owner": "numtide",
-        "repo": "flake-utils",
-        "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
-        "type": "github"
-      },
-      "original": {
-        "owner": "numtide",
-        "repo": "flake-utils",
-        "type": "github"
-      }
-    },
-    "gitignore": {
-      "inputs": {
-        "nixpkgs": [
-          "searchix",
-          "pre-commit-hooks",
-          "nixpkgs"
-        ]
-      },
-      "locked": {
-        "lastModified": 1709087332,
-        "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
-        "owner": "hercules-ci",
-        "repo": "gitignore.nix",
-        "rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
-        "type": "github"
-      },
-      "original": {
-        "owner": "hercules-ci",
-        "repo": "gitignore.nix",
-        "type": "github"
-      }
-    },
-    "golink": {
-      "inputs": {
-        "flake-utils": "flake-utils",
-        "nixpkgs": [
-          "nixpkgs-small"
-        ]
-      },
-      "locked": {
-        "lastModified": 1717093333,
-        "narHash": "sha256-D050npC0XbDiNPB1xUOzUNLSp0JyUUl015WEA0h8yf4=",
-        "owner": "tailscale",
-        "repo": "golink",
-        "rev": "ef8d461b8546ca45079254d134af2d15ad03ea61",
-        "type": "github"
-      },
-      "original": {
-        "owner": "tailscale",
-        "repo": "golink",
-        "type": "github"
-      }
-    },
-    "gomod2nix": {
-      "inputs": {
-        "flake-utils": [
-          "searchix",
-          "flake-utils"
-        ],
-        "nixpkgs": [
-          "searchix",
-          "nixpkgs"
-        ]
-      },
-      "locked": {
-        "lastModified": 1716202913,
-        "narHash": "sha256-zjPNXI4DWBOrPsrK8u/XTsm5Q36quONQvz0jhAKHEeg=",
-        "owner": "nix-community",
-        "repo": "gomod2nix",
-        "rev": "4702caff8e201f4c98fe3583637a930d253447c8",
-        "type": "github"
-      },
-      "original": {
-        "owner": "nix-community",
-        "repo": "gomod2nix",
-        "type": "github"
-      }
-    },
-    "home-manager": {
-      "inputs": {
-        "nixpkgs": [
-          "agenix",
-          "nixpkgs"
-        ]
-      },
-      "locked": {
-        "lastModified": 1703113217,
-        "narHash": "sha256-7ulcXOk63TIT2lVDSExj7XzFx09LpdSAPtvgtM7yQPE=",
-        "owner": "nix-community",
-        "repo": "home-manager",
-        "rev": "3bfaacf46133c037bb356193bd2f1765d9dc82c1",
-        "type": "github"
-      },
-      "original": {
-        "owner": "nix-community",
-        "repo": "home-manager",
-        "type": "github"
-      }
-    },
-    "home-manager_2": {
-      "inputs": {
-        "nixpkgs": [
-          "nixpkgs"
-        ]
-      },
-      "locked": {
-        "lastModified": 1717097707,
-        "narHash": "sha256-HC5vJ3oYsjwsCaSbkIPv80e4ebJpNvFKQTBOGlHvjLs=",
-        "owner": "nix-community",
-        "repo": "home-manager",
-        "rev": "0eb314b4f0ba337e88123e0b1e57ef58346aafd9",
-        "type": "github"
-      },
-      "original": {
-        "owner": "nix-community",
-        "repo": "home-manager",
-        "type": "github"
-      }
-    },
-    "nixpkgs": {
-      "locked": {
-        "lastModified": 1716948383,
-        "narHash": "sha256-SzDKxseEcHR5KzPXLwsemyTR/kaM9whxeiJohbL04rs=",
-        "owner": "NixOS",
-        "repo": "nixpkgs",
-        "rev": "ad57eef4ef0659193044870c731987a6df5cf56b",
-        "type": "github"
-      },
-      "original": {
-        "owner": "NixOS",
-        "ref": "nixos-unstable",
-        "repo": "nixpkgs",
-        "type": "github"
-      }
-    },
-    "nixpkgs-small": {
-      "locked": {
-        "lastModified": 1717112898,
-        "narHash": "sha256-7R2ZvOnvd9h8fDd65p0JnB7wXfUvreox3xFdYWd1BnY=",
-        "owner": "NixOS",
-        "repo": "nixpkgs",
-        "rev": "6132b0f6e344ce2fe34fc051b72fb46e34f668e0",
-        "type": "github"
-      },
-      "original": {
-        "owner": "NixOS",
-        "ref": "nixos-unstable-small",
-        "repo": "nixpkgs",
-        "type": "github"
-      }
-    },
-    "nixpkgs-stable": {
-      "locked": {
-        "lastModified": 1710695816,
-        "narHash": "sha256-3Eh7fhEID17pv9ZxrPwCLfqXnYP006RKzSs0JptsN84=",
-        "owner": "NixOS",
-        "repo": "nixpkgs",
-        "rev": "614b4613980a522ba49f0d194531beddbb7220d3",
-        "type": "github"
-      },
-      "original": {
-        "owner": "NixOS",
-        "ref": "nixos-23.11",
-        "repo": "nixpkgs",
-        "type": "github"
-      }
-    },
-    "nixpkgs_2": {
-      "locked": {
-        "lastModified": 1710765496,
-        "narHash": "sha256-p7ryWEeQfMwTB6E0wIUd5V2cFTgq+DRRBz2hYGnJZyA=",
-        "owner": "NixOS",
-        "repo": "nixpkgs",
-        "rev": "e367f7a1fb93137af22a3908f00b9a35e2d286a7",
-        "type": "github"
-      },
-      "original": {
-        "owner": "NixOS",
-        "ref": "nixpkgs-unstable",
-        "repo": "nixpkgs",
-        "type": "github"
-      }
-    },
-    "pre-commit-hooks": {
-      "inputs": {
-        "flake-compat": "flake-compat",
-        "gitignore": "gitignore",
-        "nixpkgs": "nixpkgs_2",
-        "nixpkgs-stable": "nixpkgs-stable"
-      },
-      "locked": {
-        "lastModified": 1716213921,
-        "narHash": "sha256-xrsYFST8ij4QWaV6HEokCUNIZLjjLP1bYC60K8XiBVA=",
-        "owner": "cachix",
-        "repo": "pre-commit-hooks.nix",
-        "rev": "0e8fcc54b842ad8428c9e705cb5994eaf05c26a0",
-        "type": "github"
-      },
-      "original": {
-        "owner": "cachix",
-        "repo": "pre-commit-hooks.nix",
-        "type": "github"
-      }
-    },
-    "root": {
-      "inputs": {
-        "agenix": "agenix",
-        "golink": "golink",
-        "home-manager": "home-manager_2",
-        "nixpkgs": "nixpkgs",
-        "nixpkgs-small": "nixpkgs-small",
-        "searchix": "searchix",
-        "secrets": "secrets",
-        "utils": "utils"
-      }
-    },
-    "searchix": {
-      "inputs": {
-        "flake-utils": "flake-utils_2",
-        "gomod2nix": "gomod2nix",
-        "nixpkgs": [
-          "nixpkgs-small"
-        ],
-        "pre-commit-hooks": "pre-commit-hooks",
-        "simple-css": "simple-css"
-      },
-      "locked": {
-        "lastModified": 1717118045,
-        "narHash": "sha256-0wAYEnOCnuoP+1O6Jcdd/IHjQiIlDyOf4TBXdqL5leo=",
-        "ref": "refs/heads/main",
-        "rev": "66b2556a6a7c911a69b231fddeefe0a939d8898d",
-        "revCount": 230,
-        "type": "git",
-        "url": "https://git.alanpearce.eu/searchix"
-      },
-      "original": {
-        "type": "git",
-        "url": "https://git.alanpearce.eu/searchix"
-      }
-    },
-    "secrets": {
-      "flake": false,
-      "locked": {
-        "lastModified": 1717118271,
-        "narHash": "sha256-O0/THgLg1X3v+KRTpJF4w6ypjVqIsbU+2+bueaKseR4=",
-        "ref": "refs/heads/main",
-        "rev": "8ee78678874a6921a8f1728ef6d8b0beab877c69",
-        "revCount": 65,
-        "type": "git",
-        "url": "file:///home/alan/projects/alanpearce.eu/nixfiles/private"
-      },
-      "original": {
-        "id": "secrets",
-        "type": "indirect"
-      }
-    },
-    "simple-css": {
-      "flake": false,
-      "locked": {
-        "narHash": "sha256-AAA6fucfxB8R7z66UjOps79XMxbK/gZAB+JDEpZeXGo=",
-        "type": "file",
-        "url": "https://raw.githubusercontent.com/kevquirk/simple.css/v2.3.0/simple.css"
-      },
-      "original": {
-        "type": "file",
-        "url": "https://raw.githubusercontent.com/kevquirk/simple.css/v2.3.0/simple.css"
-      }
-    },
-    "systems": {
-      "locked": {
-        "lastModified": 1681028828,
-        "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
-        "owner": "nix-systems",
-        "repo": "default",
-        "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
-        "type": "github"
-      },
-      "original": {
-        "owner": "nix-systems",
-        "repo": "default",
-        "type": "github"
-      }
-    },
-    "systems_2": {
-      "locked": {
-        "lastModified": 1681028828,
-        "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
-        "owner": "nix-systems",
-        "repo": "default",
-        "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
-        "type": "github"
-      },
-      "original": {
-        "owner": "nix-systems",
-        "repo": "default",
-        "type": "github"
-      }
-    },
-    "systems_3": {
-      "locked": {
-        "lastModified": 1681028828,
-        "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
-        "owner": "nix-systems",
-        "repo": "default",
-        "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
-        "type": "github"
-      },
-      "original": {
-        "owner": "nix-systems",
-        "repo": "default",
-        "type": "github"
-      }
-    },
-    "systems_4": {
-      "locked": {
-        "lastModified": 1681028828,
-        "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
-        "owner": "nix-systems",
-        "repo": "default",
-        "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
-        "type": "github"
-      },
-      "original": {
-        "owner": "nix-systems",
-        "repo": "default",
-        "type": "github"
-      }
-    },
-    "utils": {
-      "inputs": {
-        "systems": "systems_4"
-      },
-      "locked": {
-        "lastModified": 1710146030,
-        "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
-        "owner": "numtide",
-        "repo": "flake-utils",
-        "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
-        "type": "github"
-      },
-      "original": {
-        "owner": "numtide",
-        "repo": "flake-utils",
-        "type": "github"
-      }
-    }
-  },
-  "root": "root",
-  "version": 7
-}
diff --git a/flake.nix b/flake.nix
deleted file mode 100644
index 5fccaa19..00000000
--- a/flake.nix
+++ /dev/null
@@ -1,90 +0,0 @@
-{
-  inputs = {
-    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
-    nixpkgs-small.url = "github:NixOS/nixpkgs/nixos-unstable-small";
-    home-manager.url = "github:nix-community/home-manager";
-    home-manager.inputs.nixpkgs.follows = "nixpkgs";
-    secrets = {
-      flake = false;
-    };
-    utils.url = "github:numtide/flake-utils";
-    agenix.url = "github:ryantm/agenix";
-    agenix.inputs.nixpkgs.follows = "nixpkgs";
-    searchix = {
-      url = "git+https://git.alanpearce.eu/searchix";
-      inputs.nixpkgs.follows = "nixpkgs-small";
-    };
-    golink = {
-      url = "github:tailscale/golink";
-      inputs.nixpkgs.follows = "nixpkgs-small";
-    };
-  };
-
-  outputs =
-    inputs@
-    { self
-    , utils
-    , nixpkgs
-    , nixpkgs-small
-    , home-manager
-    , secrets
-    , agenix
-    , searchix
-    , golink
-    , ...
-    }:
-    let
-      readOverlays = path:
-        let content = builtins.readDir path; in
-        map (n: import (path + ("/" + n)))
-          (builtins.filter
-            (n:
-              (builtins.match ".*\\.nix" n != null &&
-              # ignore Emacs lock files (.#foo.nix)
-              builtins.match "\\.#.*" n == null) ||
-              builtins.pathExists (path + ("/" + n + "/default.nix")))
-            (builtins.attrNames content));
-
-      mkHomeConfiguration = { modules, system }: home-manager.lib.homeManagerConfiguration {
-        pkgs = import nixpkgs {
-          inherit system;
-          overlays = readOverlays (toString ./overlays);
-        };
-
-        inherit modules;
-        extraSpecialArgs = {
-          inherit inputs system;
-        };
-      };
-    in
-    {
-      nixosConfigurations.linde = nixpkgs-small.lib.nixosSystem {
-        system = utils.lib.system.aarch64-linux;
-        specialArgs = { inherit inputs; };
-        modules = [
-          agenix.nixosModules.default
-          searchix.nixosModules.web
-          golink.nixosModules.default
-          ./system/linde.nix
-          home-manager.nixosModules.home-manager
-          {
-            home-manager = {
-              extraSpecialArgs = {
-                pkgs = import nixpkgs {
-                  overlays = readOverlays (toString ./overlays);
-                };
-              };
-              users.alan = import ./user/server.nix;
-            };
-          }
-        ];
-      };
-      homeConfigurations."alan@linde" = mkHomeConfiguration {
-        system = utils.lib.system.aarch64-linux;
-        modules = [
-          ./user/server.nix
-          (secrets + "/default.nix")
-        ];
-      };
-    };
-}
diff --git a/npins/sources.json b/npins/sources.json
index 8cc7f833..d7b43684 100644
--- a/npins/sources.json
+++ b/npins/sources.json
@@ -20,9 +20,9 @@
         "repo": "nix-darwin"
       },
       "branch": "master",
-      "revision": "58b905ea87674592aa84c37873e6c07bc3807aba",
-      "url": "https://github.com/lnl7/nix-darwin/archive/58b905ea87674592aa84c37873e6c07bc3807aba.tar.gz",
-      "hash": "17iv39qqwqyfyg06pihrblixhaxb349rxadz47xa65zwhrv71ic8"
+      "revision": "50581970f37f06a4719001735828519925ef8310",
+      "url": "https://github.com/lnl7/nix-darwin/archive/50581970f37f06a4719001735828519925ef8310.tar.gz",
+      "hash": "1c2zihl124j7xz5fyhkjvcpabyrvs1qgix1fzr0fc002mnkcrf13"
     },
     "emacs-overlay": {
       "type": "Git",
@@ -32,9 +32,9 @@
         "repo": "emacs-overlay"
       },
       "branch": "master",
-      "revision": "a3bb4fefef1ed47a18480ab14d65d409d1f9b9c0",
-      "url": "https://github.com/nix-community/emacs-overlay/archive/a3bb4fefef1ed47a18480ab14d65d409d1f9b9c0.tar.gz",
-      "hash": "0qdvxkp6m2l3kplcf8gx158l7cdyx6c4rwni324zq4w4sfscjgzf"
+      "revision": "dc376600483aae0272de58ea9b2d06c9f4e132eb",
+      "url": "https://github.com/nix-community/emacs-overlay/archive/dc376600483aae0272de58ea9b2d06c9f4e132eb.tar.gz",
+      "hash": "15b1w9vg1g7zih56lh198yi8si6m7b4yxxfsn4dxffdzal415vbl"
     },
     "home-manager": {
       "type": "Git",
@@ -44,9 +44,9 @@
         "repo": "home-manager"
       },
       "branch": "master",
-      "revision": "0a7ffb28e5df5844d0e8039c9833d7075cdee792",
-      "url": "https://github.com/nix-community/home-manager/archive/0a7ffb28e5df5844d0e8039c9833d7075cdee792.tar.gz",
-      "hash": "1qd5sdpgpadd0972gmngjl0gf96h4cz0xvmv0186pgj6xgzc7amh"
+      "revision": "cd886711998fe5d9ff7979fdd4b4cbd17b1f1511",
+      "url": "https://github.com/nix-community/home-manager/archive/cd886711998fe5d9ff7979fdd4b4cbd17b1f1511.tar.gz",
+      "hash": "1kvww9d28nlz2gawbrasvgpk172vzxlxdbhh1b8c41m1x7rrvqk8"
     },
     "nix-index-database": {
       "type": "Git",
@@ -68,15 +68,15 @@
         "repo": "nixos-hardware"
       },
       "branch": "master",
-      "revision": "cde8f7e11f036160b0fd6a9e07dc4c8e4061cf06",
-      "url": "https://github.com/NixOS/nixos-hardware/archive/cde8f7e11f036160b0fd6a9e07dc4c8e4061cf06.tar.gz",
-      "hash": "0506wvajw8kg1k17hqi37jnd01xq8kz8nzryssmg4iqgwhig51nn"
+      "revision": "e8232c132a95ddc62df9d404120ad4ff53862910",
+      "url": "https://github.com/NixOS/nixos-hardware/archive/e8232c132a95ddc62df9d404120ad4ff53862910.tar.gz",
+      "hash": "0w6d2nk498i0hqiimfxhxj7i9zhija9sybnhbyknwl7pkc4b7lkp"
     },
     "nixpkgs": {
       "type": "Channel",
       "name": "nixos-unstable",
-      "url": "https://releases.nixos.org/nixos/unstable/nixos-24.11pre639108.e9ee548d90ff/nixexprs.tar.xz",
-      "hash": "1k9cdvanlvx2pmglx600mg0ly6fxwbgac95yrchm4jyhyamv3ifv"
+      "url": "https://releases.nixos.org/nixos/unstable/nixos-24.11pre642660.a71e967ef369/nixexprs.tar.xz",
+      "hash": "0km1smh73aqa9syc3pd6f8l8rz6jb87x8a4qx7d6x1b8932z3is2"
     },
     "nur": {
       "type": "Git",
@@ -86,9 +86,9 @@
         "repo": "NUR"
       },
       "branch": "master",
-      "revision": "a901945bee92ec63f1ed7f01913f8216bc8e94d3",
-      "url": "https://github.com/nix-community/NUR/archive/a901945bee92ec63f1ed7f01913f8216bc8e94d3.tar.gz",
-      "hash": "0k8shccbx1459pbyjjff3y3162k3zvba6p5cgvwfjylkxr8crdix"
+      "revision": "88407857c90e39f2654a0ef347c2c920c25f453c",
+      "url": "https://github.com/nix-community/NUR/archive/88407857c90e39f2654a0ef347c2c920c25f453c.tar.gz",
+      "hash": "1gn8lbgrcqx4i13p2jjqqp3n2pkrmxn8rliz53x0vdmlg4vvzrjk"
     }
   },
   "version": 3
diff --git a/packages b/packages
-Subproject d7485c5f7ace65db560d8023906d079928e1182
+Subproject e44b42f082aee425459182711649283986ef5e4
diff --git a/private b/private
-Subproject 442aa5d4590153b95817b1f102510e87639d60a
+Subproject b9a288b3c757997afe2399ca10a877bffd8eba6
diff --git a/shell.nix b/shell.nix
index f41153fc..b7d05d66 100644
--- a/shell.nix
+++ b/shell.nix
@@ -15,6 +15,6 @@ pkgs.mkShell
   ];
 
   shellHook = ''
-    export NIX_PATH="${builtins.concatStringsSep ":"nixPath}";
+    export NIX_PATH="${builtins.concatStringsSep ":" nixPath}";
   '';
 }
diff --git a/system/linde.nix b/system/linde.nix
index f255bc30..2ae0b714 100644
--- a/system/linde.nix
+++ b/system/linde.nix
@@ -16,10 +16,16 @@ let
   net-mask6 = "64";
   net-gw6 = "fe80::1";
   ts-domain = "hydra-pinecone.ts.net";
+  golink = (builtins.getFlake (toString <golink>)).nixosModules.default;
 in
 {
   imports =
     [
+      <personal/modules/nixos/laminar.nix>
+      <home-manager/nixos>
+      <agenix/modules/age.nix>
+      <searchix/nix/modules>
+      golink
       # Include the results of the hardware scan.
       ./linde-hardware.nix
 
@@ -67,7 +73,6 @@ in
   environment.systemPackages = with pkgs; [
     htop
     lsof
-    gitMinimal
     powerdns
     sqlite-interactive
     knot-dns
@@ -304,7 +309,7 @@ in
   users.users.root.shell = "${pkgs.fish}/bin/fish";
   users.users.alan = {
     shell = "${pkgs.fish}/bin/fish";
-    extraGroups = [ "wheel" "caddy" "docker" ];
+    extraGroups = [ "wheel" "caddy" "docker" "laminar" ];
     isNormalUser = true;
     home = "/home/alan";
     createHome = true;
@@ -313,6 +318,9 @@ in
       "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII8VIII+598QOBxi/52O1Kb19RdUdX0aZmS1/dNoyqc5 alan@hetzner.strongbox"
     ];
   };
+  home-manager = {
+    users.alan = import ../user/server.nix;
+  };
 
   users.users.nixremote = {
     shell = "/bin/sh";
@@ -340,7 +348,7 @@ in
     let
       inherit (lib.lists) flatten;
       inherit (lib.strings) concatStringsSep;
-      he = rec {
+      he = {
         notify = "216.218.130.2";
         axfr = [
           "216.218.133.2"
@@ -676,7 +684,10 @@ in
           extraConfig = ''
             encode zstd gzip
             ${security-headers {}}
-            reverse_proxy localhost${config.services.ntfy-sh.settings.listen-http}
+            reverse_proxy localhost${config.services.ntfy-sh.settings.listen-http} {
+              health_uri /v1/health
+              health_body `"healthy":true`
+            }
           '';
         };
         "searchix.alanpearce.eu" = {
@@ -709,6 +720,15 @@ in
               reverse_proxy ${ns.bindAddress}:${toString ns.port}
             '';
           };
+        "ci.alanpearce.eu" =
+          let
+            srv = config.services.laminar;
+          in
+          {
+            extraConfig = ''
+              reverse_proxy ${srv.settings.bindHTTP}
+            '';
+          };
       };
   };
   systemd.services.caddy.serviceConfig = {
@@ -958,4 +978,46 @@ in
       };
     };
   };
+
+  programs.git = {
+    enable = true;
+    package = pkgs.gitMinimal;
+    config = {
+      advice = {
+        detachedHead = false;
+        mergeConflict = false;
+      };
+    };
+  };
+
+  systemd.services.laminar.environment = {
+    NIX_PATH = "nixpkgs=${<nixpkgs>}";
+  };
+  services.laminar = {
+    enable = true;
+    path = with pkgs; [
+      bash
+      stdenv
+      git
+      cached-nix-shell
+      nix
+      config.programs.ssh.package
+      flock
+      just
+    ];
+    settings = {
+      bindHTTP = "[::1]:8002";
+      keepRundirs = 1;
+    };
+  };
+  users.users.laminar = {
+    homeMode = "770";
+  };
+
+  virtualisation.containers = {
+    enable = true;
+    policy = {
+      default = [{ type = "insecureAcceptAnything"; }];
+    };
+  };
 }
diff --git a/system/mba.nix b/system/mba.nix
index abed520b..cc8c81da 100644
--- a/system/mba.nix
+++ b/system/mba.nix
@@ -1,10 +1,16 @@
 { ... }: {
   imports = [
     ./settings/darwin.nix
-    ./settings/programs/base.nix
+    ./settings/dev.nix
     ./settings/programs/shell.nix
+    <personal/modules/darwin/caddy>
   ];
 
+  services.caddy = {
+    user = "root";
+    group = "wheel";
+  };
+
   networking = {
     hostName = "mba";
   };
@@ -37,27 +43,4 @@
       supportedFeatures = [ ];
     }
   ];
-
-  nix.linux-builder = {
-    maxJobs = 4;
-    config = { pkgs, ... }: {
-      virtualisation = {
-        darwin-builder = {
-          diskSize = 60 * 1024;
-          memorySize = 8 * 1024;
-        };
-        cores = 4;
-      };
-      # don't go crazy with this setup, it rebuilds the VM
-      imports = [
-        ./settings/configuration/user.nix
-        ./settings/programs/shell.nix
-      ];
-      environment.systemPackages = with pkgs; [
-        kitty.terminfo
-        hello
-      ];
-    };
-    systems = [ "aarch64-linux" ];
-  };
 }
diff --git a/system/nanopi.nix b/system/nanopi.nix
index 6ee61e69..3c49ec8f 100755
--- a/system/nanopi.nix
+++ b/system/nanopi.nix
@@ -504,11 +504,9 @@ in
         "/ts.net/tailscale"
       ];
       localise-queries = true;
-      cname = [
-        "ha,home-assistant"
-      ];
       interface-name = [
         "nanopi.${domain},bridge0"
+        "ca.${domain},bridge0"
         "wan.${domain},wan0"
         "wlan.${domain},wlan0"
       ];
@@ -538,7 +536,8 @@ in
       dhcp-rapid-commit = true;
       dhcp-range = [
         "10.0.1.0,10.0.1.250,12h"
-        "::,constructor:bridge0,ra-stateless,ra-names,48h"
+        "fd12:d04f:65d:42::,slaac,ra-names,48h"
+        "::,constructor:bridge0,ra-stateless,48h"
       ];
       dhcp-host = [
         "00:a0:de:b3:0c:01,10.0.0.50,wxa-50"
@@ -609,6 +608,46 @@ in
     };
   };
 
+  services.caddy = {
+    enable = true;
+    globalConfig = ''
+      auto_https disable_redirects
+      pki {
+        ca home {
+          name "Home CA"
+        }
+      }
+    '';
+    virtualHosts = {
+      "nanopi.${domain}" = {
+        serverAliases = [ "nanopi.${ts_domain}" ];
+        extraConfig = ''
+          tls {
+            issuer internal {
+              ca home
+            }
+          }
+          root /var/lib/caddy/ca
+          file_server browse
+        '';
+      };
+      "ca.${domain}" = {
+        extraConfig = ''
+          tls {
+            issuer internal {
+              ca home
+            }
+          }
+          acme_server {
+            allow {
+              domains *.test *.${domain}
+            }
+          }
+        '';
+      };
+    };
+  };
+
   system.stateVersion = "23.05";
 
   programs.fish = {
diff --git a/system/prefect.nix b/system/prefect.nix
index 0fc80eb9..980e35ff 100644
--- a/system/prefect.nix
+++ b/system/prefect.nix
@@ -23,6 +23,7 @@
     ./settings/programs/kde.nix
     ./settings/programs/shell.nix
     ./settings/programs/docker.nix
+    ./settings/dev.nix
     ./settings/gaming.nix
     <nixos-hardware/common/cpu/amd>
     <nixos-hardware/common/cpu/amd/pstate.nix>
@@ -31,6 +32,26 @@
     <nixos-hardware/common/gpu/nvidia>
   ];
 
+  virtualisation.vmVariant = {
+    disabledModules = [
+      ./settings/hardware/nvidia-gpu.nix
+      ./settings/hardware/bare-metal.nix
+      ./settings/gaming.nix
+      ./settings/user-interface.nix
+      ./settings/programs/kde.nix
+      <nixos-hardware/common/cpu/amd>
+      <nixos-hardware/common/cpu/amd/pstate.nix>
+      <nixos-hardware/common/pc/ssd>
+      <nixos-hardware/common/pc>
+      <nixos-hardware/common/gpu/nvidia>
+    ];
+    services.qemuGuest.enable = true;
+    virtualisation = {
+      memorySize = 4096;
+      cores = 4;
+    };
+  };
+
   nixpkgs.hostPlatform = "x86_64-linux";
 
   services.xserver.screenSection = ''
@@ -148,10 +169,35 @@
     dnssec = "true";
   };
 
-  services.tailscale.enable = true;
+  services.tailscale = {
+    enable = true;
+    extraUpFlags = [
+      "--accept-dns=true"
+      "--accept-routes=false"
+    ];
+  };
 
   system.stateVersion = "23.05";
 
+  security.pki.certificates = [
+    ''
+      -----BEGIN CERTIFICATE-----
+      MIIBozCCAUqgAwIBAgIRAJ1slNK3lsucmYYUbtGRUvswCgYIKoZIzj0EAwIwMDEu
+      MCwGA1UEAxMlQ2FkZHkgTG9jYWwgQXV0aG9yaXR5IC0gMjAyNCBFQ0MgUm9vdDAe
+      Fw0yNDA2MjYxNTM3MTJaFw0zNDA1MDUxNTM3MTJaMDAxLjAsBgNVBAMTJUNhZGR5
+      IExvY2FsIEF1dGhvcml0eSAtIDIwMjQgRUNDIFJvb3QwWTATBgcqhkjOPQIBBggq
+      hkjOPQMBBwNCAAR1fc1TOhp9oNy/p40BfUd+E13b1/URwwocuZ5w0SKHTE/t8Hp+
+      7Zd9ZTYvQ7WxFfaVxmBCcFMUJsTm7bbYTEvlo0UwQzAOBgNVHQ8BAf8EBAMCAQYw
+      EgYDVR0TAQH/BAgwBgEB/wIBATAdBgNVHQ4EFgQUcnlbpAM2ZCRsiCzdFiM5EjCm
+      aoEwCgYIKoZIzj0EAwIDRwAwRAIgcKf3vRiF87G0r2+vgBbyfWo4D2TDQWkSrfek
+      Q0f1Q5UCIEmyeqrifbp5JnZqtm3IlGVIEQcUeVygqnV/xW3xCAgT
+      -----END CERTIFICATE-----
+    ''
+  ];
+  networking.hosts = {
+    "127.0.0.80" = [ "alanpearce.test" "alanpearce.localhost" ];
+  };
+
   boot.binfmt.emulatedSystems = [ "aarch64-linux" ];
   nix.settings.trusted-users = [ "root" "nixremote" ];
   services.displayManager.hiddenUsers = [ "nixremote" ];
diff --git a/system/settings/dev.nix b/system/settings/dev.nix
new file mode 100644
index 00000000..7d2e6193
--- /dev/null
+++ b/system/settings/dev.nix
@@ -0,0 +1,62 @@
+{ ... }: {
+  services.caddy = {
+    enable = true;
+    globalConfig = ''
+      auto_https disable_redirects
+    '';
+    virtualHosts =
+      let
+        local_tls = ''
+          tls {
+            issuer internal {
+              ca local
+            }
+          }
+        '';
+      in
+      {
+        "localhost" = {
+          logFormat = "output discard";
+          extraConfig = ''
+            ${local_tls}
+            acme_server {
+              allow {
+                domains *.test *.localhost
+              }
+            }
+          '';
+        };
+        # need to test forwarding behaviour
+        "https://alanpearce.localhost" = {
+          logFormat = "output discard";
+          serverAliases = [
+            "http://alanpearce.localhost"
+
+            # remember to update /etc/hosts
+            "https://alanpearce.test"
+            "http://alanpearce.test"
+          ];
+          extraConfig = ''
+            ${local_tls}
+            reverse_proxy http://alanpearce.test:8080 {
+              transport http {
+                dial_timeout 1s
+                compression off
+              }
+            }
+          '';
+        };
+        "searchix.localhost" = {
+          logFormat = "output discard";
+          extraConfig = ''
+            reverse_proxy http://localhost:7331 {
+              transport http {
+                dial_timeout 1s
+                compression off
+              }
+            }
+          '';
+        };
+      };
+  };
+}
diff --git a/system/settings/gaming.nix b/system/settings/gaming.nix
index 17f25065..d11d5a3c 100644
--- a/system/settings/gaming.nix
+++ b/system/settings/gaming.nix
@@ -19,9 +19,9 @@
   };
   fonts.fontconfig.cache32Bit = true;
   hardware.steam-hardware.enable = true;
-  hardware.opengl = {
+  hardware.graphics = {
     enable = true;
-    driSupport32Bit = true;
+    enable32Bit = true;
   };
   hardware.pulseaudio.support32Bit = true;
   services.pipewire.alsa.support32Bit = true;
diff --git a/system/settings/services/git-server.nix b/system/settings/services/git-server.nix
index 0ef40ccc..e8fe6360 100644
--- a/system/settings/services/git-server.nix
+++ b/system/settings/services/git-server.nix
@@ -4,8 +4,7 @@
 , ...
 }:
 let
-  inherit (builtins) mapAttrs attrValues;
-  inherit (lib) pipe flatten mergeAttrsList mapAttrsToList;
+  inherit (lib) pipe flatten concatMapAttrs mapAttrsToList;
   inherit (import ../../../lib/caddy.nix { inherit lib; }) security-headers;
   repos = "${config.services.gitolite.dataDir}/repositories";
 
@@ -35,7 +34,7 @@ let
   createMirrorService =
     name: { hostname, username }:
     {
-      services."mirror-to-${name}@" = {
+      "mirror-to-${name}@" = {
         path = with pkgs; [ gitMinimal openssh ];
         serviceConfig = {
           Type = "oneshot";
@@ -48,7 +47,11 @@ let
           ConditionPathExists = "${repos}/%i.git/git-daemon-export-ok";
         };
       };
-      paths."mirror-to-${name}@" = {
+    };
+
+  createMirrorPath = name: { hostname, username }:
+    {
+      "mirror-to-${name}@" = {
         pathConfig = {
           PathChanged = "${repos}/%i.git/refs/heads";
           StartLimitIntervalSec = "1h";
@@ -57,6 +60,7 @@ let
       };
     };
 
+
   mkMirrorWants = repo: map (target: "mirror-to-${target}@${repo}.path");
 in
 {
@@ -79,6 +83,7 @@ in
       push( @{$RC{ENABLE}}, 'D' );
       push( @{$RC{ENABLE}}, 'Shell alan' );
       push( @{$RC{ENABLE}}, 'cgit' );
+      push( @{$RC{ENABLE}}, 'repo-specific-hooks' );
     '';
   };
   services.legit = {
@@ -261,18 +266,14 @@ in
     ];
   };
 
-  systemd = (pipe
-    mirrors [
-    (mapAttrsToList createMirrorService)
-    mergeAttrsList
-  ]) // {
-    targets.git-mirroring = {
-      wantedBy = [ "multi-user.target" ];
-      wants = pipe
-        repoMirrors [
-        (mapAttrsToList mkMirrorWants)
-        flatten
-      ];
-    };
+  systemd.services = concatMapAttrs createMirrorService mirrors;
+  systemd.paths = concatMapAttrs createMirrorPath mirrors;
+  systemd.targets.git-mirroring = {
+    wantedBy = [ "multi-user.target" ];
+    wants = pipe
+      repoMirrors [
+      (mapAttrsToList mkMirrorWants)
+      flatten
+    ];
   };
 }
diff --git a/user/config.nix b/user/config.nix
index c12a0bb1..5a420d7b 100644
--- a/user/config.nix
+++ b/user/config.nix
@@ -1,5 +1,16 @@
-{ pkgs }: {
-  allowUnfree = true;
-  allowUnfreePredicate = pkg: true;
+{ pkgs }:
+let
+  inherit (pkgs) lib;
+in
+{
+  allowUnfreePredicate = pkg: builtins.elem (lib.getName pkg) [
+    "beeper"
+    "discord"
+    "input-fonts"
+    "tabnine"
+  ];
   input-fonts.acceptLicense = true;
+  permittedInsecurePackages = [
+    "electron-28.3.3" # for logseq 0.10.9
+  ];
 }
diff --git a/user/emacs/init.el b/user/emacs/init.el
index 6b30ac70..b666e033 100644
--- a/user/emacs/init.el
+++ b/user/emacs/init.el
@@ -90,6 +90,10 @@
                                                    original-stimmung-themes-string))
                     (load-theme current-theme :noconfirm)))))))
 
+(global-set-key (kbd "<pinch>") 'ignore)
+(global-set-key (kbd "<C-wheel-up>") 'ignore)
+(global-set-key (kbd "<C-wheel-down>") 'ignore)
+
 (setq font-lock-maximum-decoration '((t . 1))
       jit-lock-stealth-time 1.25
       jit-lock-stealth-nice 0.5
@@ -675,6 +679,12 @@ _C-k_: prev  _u_pper              _=_: upper/lower       _s_mart resolve
             (add-to-list 'tramp-default-proxies-alist
                          `(,(regexp-quote (system-name)) nil nil))))
 
+(use-package ssh-deploy
+  :config (progn
+            (ssh-deploy-line-mode +1)
+            (ssh-deploy-add-find-file-hook)
+            (ssh-deploy-add-after-save-hook)))
+
 ;;; Directories
 
 (setq dired-dwim-target t
@@ -791,6 +801,7 @@ _C-k_: prev  _u_pper              _=_: upper/lower       _s_mart resolve
 
 (setq-default go-ts-mode-indent-offset 2)
 (use-package templ-ts-mode
+  :gfhook #'eglot-format-before-save-mode
   :defer t
   :config (progn
             (setq-default go-ts-mode-indent-offset 2)))
@@ -817,7 +828,7 @@ _C-k_: prev  _u_pper              _=_: upper/lower       _s_mart resolve
 (add-hook 'compilation-filter-hook #'colourise-compilation-buffer)
 
 ;;;; shell
-(general-add-hook 'sh-mode-hook
+(general-add-hook '(sh-mode-hook bash-ts-mode-hook fish-mode-hook)
                   (lambda ()
                     (general-add-hook 'after-save-hook
                                       #'executable-make-buffer-file-executable-if-script-p :append :local)))
@@ -1093,6 +1104,13 @@ _C-k_: prev  _u_pper              _=_: upper/lower       _s_mart resolve
   :commands (consult-lsp-symbols
              consult-lsp-diagnostics))
 
+(define-minor-mode eglot-format-before-save-mode
+  "Whether to ask the LSP to format the buffer before saving"
+  :init-val nil
+  (if eglot-format-before-save-mode
+      (add-hook 'before-save-hook #'eglot-format-buffer nil 'local)
+    (remove-hook 'before-save-hook #'eglot-format-buffer 'local)))
+
 (use-package eglot
   :defer 3
   :general (:states 'normal :keymaps 'eglot-mode-map
@@ -1107,6 +1125,7 @@ _C-k_: prev  _u_pper              _=_: upper/lower       _s_mart resolve
             nim-mode-hook
             html-mode-hook
             nix-mode-hook
+            templ-ts-mode-hook
             toml-ts-mode-hook
             haskell-mode-hook)
           #'eglot-ensure)
@@ -1197,16 +1216,12 @@ _C-k_: prev  _u_pper              _=_: upper/lower       _s_mart resolve
       (call-interactively #'consult-lsp-symbols)
     (call-interactively #'consult-eglot-symbols)))
 
-;; Inside a javascript project, it's common to install tools locally to
-;; the project.  This will allows emacs to find their executables.
-
-(use-package add-node-modules-path
-  :config (setq add-node-modules-max-depth 6)
-  :ghook ('(feature-mode-hook
-            js-base-mode-hook
-            json-ts-mode-hook
-            typescript-ts-mode-hook)
-          #'add-node-modules-path))
+(defun my/ls-code-actions ()
+  (interactive)
+  (call-interactively
+   (if lsp-mode
+       #'lsp-execute-code-action
+     #'eglot-code-actions)))
 
 ;;;; Reformat on save
 
@@ -1261,6 +1276,7 @@ _C-k_: prev  _u_pper              _=_: upper/lower       _s_mart resolve
   "s" #'treemacs-select-window
   "u" #'universal-argument
   ";" #'execute-extended-command
+  "a" #'my/ls-code-actions
   "bb" #'consult-buffer
   "bx" #'kill-this-buffer
   "br" #'revert-buffer
@@ -1287,7 +1303,8 @@ _C-k_: prev  _u_pper              _=_: upper/lower       _s_mart resolve
   "iu" #'insert-char
   "xe" #'eval-last-sexp
   "xx" #'eval-defun
-  "xi" #'consult-imenu)
+  "xi" #'consult-imenu
+  "z" '(:keymap ssh-deploy-prefix-map :package ssh-deploy))
 
 (let ((mail-config (expand-file-name "mail.el" user-emacs-directory)))
   (if (file-readable-p mail-config)
diff --git a/user/mba.nix b/user/mba.nix
index 06488688..ca7b0706 100644
--- a/user/mba.nix
+++ b/user/mba.nix
@@ -4,7 +4,6 @@
     ./settings/development/base.nix
     ./settings/development/javascript.nix
     ./settings/development/golang.nix
-    ./settings/development/lisp.nix
     ./settings/development/web.nix
     ./settings/darwin.nix
     ./settings/emacs.nix
diff --git a/user/nanopi.nix b/user/nanopi.nix
index 44561eda..f2dfceac 100644
--- a/user/nanopi.nix
+++ b/user/nanopi.nix
@@ -7,7 +7,6 @@
     ./settings/git.nix
     ./settings/nix.nix
     ./settings/nixos.nix
-    ./settings/music-management.nix
     ./settings/ssh.nix
   ];
   home = {
diff --git a/user/prefect.nix b/user/prefect.nix
index ed8b77cf..6cf31cbc 100644
--- a/user/prefect.nix
+++ b/user/prefect.nix
@@ -7,7 +7,6 @@
     ./settings/dunst.nix
     ./settings/emacs.nix
     ./settings/development/base.nix
-    ./settings/development/lisp.nix
     ./settings/development/golang.nix
     ./settings/development/javascript.nix
     ./settings/development/web.nix
diff --git a/user/settings/development/base.nix b/user/settings/development/base.nix
index 669b4786..5bf54172 100644
--- a/user/settings/development/base.nix
+++ b/user/settings/development/base.nix
@@ -27,7 +27,6 @@
       miller
       watchexec
       entr
-      httping
 
       diffoscopeMinimal
 
@@ -39,7 +38,7 @@
       colima
       docker-client
     ] else [
-      zeal
+      httping
     ]);
 
   home.sessionVariables = {
@@ -89,6 +88,7 @@
     config = {
       global = {
         disable_stdin = true;
+        load_dotenv = true;
         strict_env = true;
         hide_env_diff = true;
       };
diff --git a/user/settings/development/javascript.nix b/user/settings/development/javascript.nix
index 4d196cb4..fa418cc1 100644
--- a/user/settings/development/javascript.nix
+++ b/user/settings/development/javascript.nix
@@ -23,10 +23,6 @@
     };
   };
 
-  programs.emacs.extraPackages = epkgs: (with epkgs; [
-    add-node-modules-path
-  ]);
-
   home.shellAliases = {
     bn = "bun";
     bni = "bun install";
diff --git a/user/settings/development/web.nix b/user/settings/development/web.nix
index e5c5ebb7..77b3e01d 100644
--- a/user/settings/development/web.nix
+++ b/user/settings/development/web.nix
@@ -34,6 +34,67 @@
       de-de
     ];
   };
+  programs.firefox = {
+    enable = pkgs.stdenv.isLinux;
+    package = pkgs.firefox-devedition;
+    profiles.dev-edition-default = {
+      search.default = "DuckDuckGo";
+      extensions = with pkgs.nur.repos.rycee.firefox-addons; [
+        a11ycss
+        disable-javascript
+        laboratory-by-mozilla
+        side-view
+        ublock-origin
+      ];
+      settings = {
+        "browser.aboutConfig.showWarning" = false;
+        "browser.theme.content-theme" = 1;
+        "browser.theme.toolbar-theme" = 1;
+        "browser.tabs.firefox-view" = false;
+        "extensions.activeThemeID" = "firefox-compact-light@mozilla.org";
+      };
+    };
+    policies = {
+      AutoFillCreditCardEnabled = false;
+      CaptivePortal = false;
+      Cookies = {
+        Behavior = "reject-foreign";
+      };
+      SanitizeOnShutdown = {
+        Cache = true;
+        Cookies = true;
+        FormData = true;
+      };
+      DisableFirefoxAccounts = true;
+      DisableFirefoxScreenShots = true;
+      DisableFirefoxStudies = true;
+      DisableMasterPasswordCreation = true;
+      DisablePasswordReveal = true;
+      DisablePocket = true;
+      DisableTelemetry = true;
+      DNSOverHTTPS.Enabled = false;
+      DontCheckDefaultBrowser = true;
+      EnableTrackingProtection = true;
+      GoToIntranetSiteForSingleWordEntryInAddressBar = true;
+      Homepage.URL = "http://localhost:7331";
+      NewTabPage = false;
+      NoDefaultBookmarks = true;
+      OfferToSaveLogins = false;
+      OverrideFirstRunPage = "";
+      OverridePostUpdatePage = "";
+      PasswordManagerEnabled = false;
+      PrintingEnabled = false;
+      SearchBar = "separate";
+      ShowHomeButton = true;
+      UserMessaging = {
+        ExtensionRecommendations = false;
+        FeatureRecommendations = false;
+        UrlbarInterventions = false;
+        SkipOnboarding = true;
+        MoreFromMozilla = false;
+      };
+    };
+  };
   programs.emacs.extraPackages = epkgs: (with epkgs; [
     caddyfile-mode
     emmet-mode
diff --git a/user/settings/emacs.nix b/user/settings/emacs.nix
index 7f681bd1..cc9deab6 100644
--- a/user/settings/emacs.nix
+++ b/user/settings/emacs.nix
@@ -144,6 +144,7 @@ in
         quickrun
         rainbow-mode
         rainbow-delimiters
+        ssh-deploy
         stimmung-themes
         systemd
         tempel
diff --git a/user/settings/git.nix b/user/settings/git.nix
index 4726120c..769b3728 100644
--- a/user/settings/git.nix
+++ b/user/settings/git.nix
@@ -19,6 +19,8 @@
       };
       advice = {
         addEmptyPathspec = false;
+        detachedHead = false;
+        mergeConflict = false;
       };
       ghq = {
         root = "${config.home.homeDirectory}/projects";
diff --git a/user/settings/nix.nix b/user/settings/nix.nix
index b3109c08..66c00daf 100644
--- a/user/settings/nix.nix
+++ b/user/settings/nix.nix
@@ -18,6 +18,7 @@ in
   };
 
   home.packages = with pkgs; [
+    cached-nix-shell
     nil
     npins
     nix-prefetch-scripts
@@ -29,7 +30,6 @@ in
     nixpkgs-lint
     nixpkgs-review
     nix-output-monitor
-    cachix
   ];
   xdg.configFile."nix-init/config.toml".source = toml.generate "config.toml" {
     maintainers = [ "alanpearce" ];
diff --git a/user/settings/nixos.nix b/user/settings/nixos.nix
index 05b87333..85ea7f72 100644
--- a/user/settings/nixos.nix
+++ b/user/settings/nixos.nix
@@ -6,8 +6,8 @@
 
   home.shellAliases = {
     srb = "nixos-rebuild";
-    rbs = "nixos-rebuild switch";
-    rbb = "nixos-rebuild boot";
+    rbs = "nixos-rebuild switch --fast";
+    rbb = "nixos-rebuild boot --fast";
     rbr = "nixos-rebuild switch --rollback";
   };
 }
diff --git a/user/settings/shell.nix b/user/settings/shell.nix
index 170f543f..fe2b4690 100644
--- a/user/settings/shell.nix
+++ b/user/settings/shell.nix
@@ -148,6 +148,7 @@ in
     };
   };
   home.packages = with pkgs; [
+    babashka
     fzf
     up
   ];
diff --git a/user/settings/user-interface.nix b/user/settings/user-interface.nix
index 13264e11..29de4439 100644
--- a/user/settings/user-interface.nix
+++ b/user/settings/user-interface.nix
@@ -44,11 +44,11 @@ in
       })
     ]
     ++ lib.optionals (!stdenv.isDarwin) (with pkgs; [
-      logseq
+      logseq # 0.10.9 is insecure, see ../config.nix
       (discord.override { withOpenASAR = true; })
 
+      zeal
       falkon
-      mu
       beeper
       kdePackages.neochat
       kdePackages.kleopatra