summary refs log tree commit diff stats
path: root/user
diff options
context:
space:
mode:
Diffstat (limited to 'user')
-rw-r--r--user/.gitignore2
-rw-r--r--user/config.nix17
-rw-r--r--user/emacs/early-init.el7
-rw-r--r--user/emacs/init.el150
-rw-r--r--user/gnupg/dirmngr.conf3
-rw-r--r--user/gnupg/gpa.conf2
-rw-r--r--user/gnupg/gpg-agent.conf3
-rw-r--r--user/gnupg/gpg.conf83
-rw-r--r--user/gnupg/trezor/dirmngr.conf1
-rw-r--r--user/mba.nix5
-rw-r--r--user/nanopi.nix1
-rw-r--r--user/nvim/init.lua1
-rw-r--r--user/prefect.nix10
-rw-r--r--user/server.nix1
-rw-r--r--user/settings/base.nix18
-rw-r--r--user/settings/development/base.nix16
-rw-r--r--user/settings/development/golang.nix9
-rw-r--r--user/settings/development/javascript.nix4
-rw-r--r--user/settings/development/web.nix81
-rw-r--r--user/settings/emacs.nix52
-rw-r--r--user/settings/fish/functions/dired.fish2
-rw-r--r--user/settings/fish/functions/magit.fish2
-rw-r--r--user/settings/fish/functions/newest.fish10
-rw-r--r--user/settings/fish/functions/oldest.fish10
-rw-r--r--user/settings/git.nix5
-rw-r--r--user/settings/gnupg.nix16
-rw-r--r--user/settings/i3.nix3
-rw-r--r--user/settings/neovim.nix18
-rw-r--r--user/settings/nix.nix12
-rw-r--r--user/settings/nixos.nix4
-rw-r--r--user/settings/shell.nix11
-rw-r--r--user/settings/ssh.nix4
-rw-r--r--user/settings/tabnine.nix13
-rw-r--r--user/settings/trezor.nix10
-rw-r--r--user/settings/user-interface.nix11
35 files changed, 378 insertions, 219 deletions
diff --git a/user/.gitignore b/user/.gitignore
deleted file mode 100644
index d7bc17e5..00000000
--- a/user/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-home.nix
-result
\ No newline at end of file
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/early-init.el b/user/emacs/early-init.el
index 29dadb92..d24c661d 100644
--- a/user/emacs/early-init.el
+++ b/user/emacs/early-init.el
@@ -4,9 +4,16 @@
       frame-inhibit-implied-resize t
       byte-compile-warnings '(not free-vars unresolved noruntime lexical make-local cl-functions))
 
+(require 'xdg)
+(startup-redirect-eln-cache
+ (expand-file-name "emacs/native-compile"
+                   (xdg-cache-home)))
+
 ;; Disable all the bars, unless on macOS, in which case, keep the menu bar.
 (unless (eq window-system 'ns)
   (menu-bar-mode -1))
 (scroll-bar-mode -1)
 (tool-bar-mode -1)
 (set-fringe-mode '(4 . 4))
+
+(setenv "LSP_USE_PLISTS" "true") ; must match with lsp-mode override
diff --git a/user/emacs/init.el b/user/emacs/init.el
index dddd0ec0..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
@@ -133,7 +137,11 @@
 (setq-default display-line-numbers 'relative
               display-line-numbers-widen t
               display-line-numbers-width 4)
-(setq frame-resize-pixelwise t)
+(setq frame-resize-pixelwise t
+      window-resize-pixelwise t
+      display-buffer-alist `(("\\*\\(?:shell\\|compilation\\)\\*" display-buffer-in-side-window
+                              (side . bottom) (slot . 0) (preserve-size . (nil . t))
+                              (no-other-window . t) (no-delete-other-windows . t))))
 
 (defun noct-relative ()
   "Show relative line numbers."
@@ -478,6 +486,12 @@ _C-k_: prev  _u_pper              _=_: upper/lower       _s_mart resolve
   :defer 2
   :config (evil-commentary-mode +1))
 
+(use-package evil-lion
+  :after evil
+  :defer 10
+  :config (progn
+            (evil-lion-mode +1)))
+
 (use-package evil-matchit
   :after evil
   :defer 2
@@ -568,7 +582,7 @@ _C-k_: prev  _u_pper              _=_: upper/lower       _s_mart resolve
             (setq kind-icon-default-face 'corfu-default)
             (add-to-list 'corfu-margin-formatters #'kind-icon-margin-formatter)))
 
-(use-package tabnine
+(use-package tabnine-core
   :config (progn
             (setq tabnine-binaries-folder "~/.local/tabnine")
             (with-demoted-errors "TabNine error: %s"
@@ -635,11 +649,10 @@ _C-k_: prev  _u_pper              _=_: upper/lower       _s_mart resolve
 ;;;; Auto-reloading
 
 (use-package autorevert
-  :defer 1
   :config (progn
             (setq auto-revert-verbose nil
                   auto-revert-use-notify t)
-            (global-auto-revert-mode t)))
+            (global-auto-revert-mode 1)))
 
 (setq delete-by-moving-to-trash t)
 
@@ -666,11 +679,18 @@ _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
       dired-recursive-copies 'top
       dired-listing-switches "-alh --group-directories-first"
+      dired-kill-when-opening-new-dired-buffer t
       dired-recursive-deletes (if delete-by-moving-to-trash
                                   'always
                                 'top))
@@ -707,7 +727,9 @@ _C-k_: prev  _u_pper              _=_: upper/lower       _s_mart resolve
 
 (use-package eshell-toggle
   :commands (eshell-toggle)
-  :general ("C-`" #'eshell-toggle))
+  :general ("C-`" #'eshell-toggle)
+  :config (progn
+            (setq eshell-toggle-find-project-root-package 'project)))
 
 (declare-function eshell-push-command "esh-buf-stack" (CMD))
 (defun my-bind-esh-push ()
@@ -777,6 +799,13 @@ _C-k_: prev  _u_pper              _=_: upper/lower       _s_mart resolve
 (with-eval-after-load 'project
   (add-to-list 'project-vc-extra-root-markers "go.mod"))
 
+(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)))
+
 ;;;; nim
 (use-package nim-mode
   :defer t
@@ -786,6 +815,7 @@ _C-k_: prev  _u_pper              _=_: upper/lower       _s_mart resolve
 
 ;;;; js
 (setq js-enabled-frameworks '(javascript))
+(add-to-list 'auto-mode-alist '("\\.[cm]js\\'" . js-ts-mode))
 
 ;;;; typescript
 
@@ -798,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)))
@@ -806,8 +836,6 @@ _C-k_: prev  _u_pper              _=_: upper/lower       _s_mart resolve
 (add-to-list 'auto-mode-alist '("\\.env\\'" . conf-unix-mode))
 (add-to-list 'auto-mode-alist '("\\.zsh\\'" . shell-script-mode))
 (add-to-list 'auto-mode-alist '("zshenv\\'" . shell-script-mode))
-(add-to-list 'auto-mode-alist '("zshrc\\'"  . shell-script-mode))
-(setq sh-shell-file "/usr/bin/env zsh")
 
 (add-hook 'shell-mode-hook 'ansi-color-for-comint-mode-on)
 
@@ -882,14 +910,16 @@ _C-k_: prev  _u_pper              _=_: upper/lower       _s_mart resolve
 
 (use-package web-mode
   :mode (("\\.html?.erb\\'" . web-mode)
+         ("\\.gotmpl\\'" . web-mode)
          ("\\.tmpl\\'" . web-mode))
   :config (setq web-mode-enable-auto-pairing nil
                 web-mode-style-padding 2
                 web-mode-script-padding 2
-                web-mode-engines-alist '(("go" . "\\.tmpl\\'"))))
+                web-mode-engines-alist '(("go" . "\\.tmpl\\'")
+                                         ("go" . "\\.gotmpl\\'"))))
 
 (use-package emmet-mode
-  :ghook '(web-mode-hook sgml-mode-hook))
+  :ghook '(web-mode-hook sgml-mode-hook templ-ts-mode-hook))
 
 ;;; IDE features
 
@@ -941,6 +971,32 @@ _C-k_: prev  _u_pper              _=_: upper/lower       _s_mart resolve
               (evil-ex-define-cmd "pb" #'project-switch-to-buffer)
               (evil-ex-define-cmd "psw[itch]" #'project-switch-project))))
 
+(use-package treemacs
+  :general (:keymaps 'treemacs-mode-map
+                     [mouse-1] #'treemacs-single-click-expand-action)
+  :config (progn
+            (treemacs-project-follow-mode t)
+            (setq treemacs-is-never-other-window t
+                  treemacs-select-when-already-in-treemacs 'move-back
+                  treemacs-eldoc-display nil
+                  treemacs-indentation '(8 px)
+                  treemacs-show-hidden-files nil
+                  treemacs-recenter-after-project-jump 'on-distance
+                  treemacs-missing-project-action 'remove)))
+
+(use-package treemacs-evil
+  :after treemacs)
+
+(use-package treemacs-magit
+  :after treemacs)
+
+(use-package treemacs-nerd-icons
+  :after treemacs
+  :init (progn
+          (setq treemacs-nerd-icons-tab " "))
+  :config (progn
+            (treemacs-load-theme "simple")))
+
 (use-package consult-ghq
   :defer 5
   :general (:keymaps 'project-prefix-map
@@ -961,12 +1017,15 @@ _C-k_: prev  _u_pper              _=_: upper/lower       _s_mart resolve
   :general ([remap project-vc-dir] #'magit-project-status)
   (:keymaps 'project-prefix-map "m" #'magit-project-status)
   :init (progn
-          (with-eval-after-load 'project
-            (add-to-list 'project-switch-commands '(magit-project-status "Magit") t)))
+          (defvar magit-auto-revert-mode nil)
+          (setq magit-auto-revert-mode nil)
+          (require 'project)
+          (add-to-list 'project-switch-commands '(magit-project-status "Magit") t))
   :config (progn
             (setq magit-section-visibility-indicator nil
                   magit-diff-refine-hunk t
-                  magit-auto-revert-immediately t
+                  magit-auto-revert-mode nil
+                  magit-auto-revert-immediately nil ; unnecessary when global-auto-revert-mode is enabled
                   magit-display-buffer-function #'magit-display-buffer-fullcolumn-most-v1)
             (remove-hook 'magit-status-sections-hook 'magit-insert-tags-header)
             (remove-hook 'magit-section-highlight-hook 'magit-section-highlight)
@@ -974,6 +1033,11 @@ _C-k_: prev  _u_pper              _=_: upper/lower       _s_mart resolve
             (remove-hook 'magit-section-highlight-hook 'magit-diff-highlight)
             (require 'magit-extras)))
 
+(use-package magit-todos
+  :after magit
+  :config (progn
+            (magit-todos-mode +1)))
+
 (use-package git-gutter-fringe
   :defer 5
   :config (progn
@@ -1001,7 +1065,9 @@ _C-k_: prev  _u_pper              _=_: upper/lower       _s_mart resolve
   :defer 2
   :config (progn
             (editorconfig-mode +1)
-            (setq editorconfig-lisp-use-default-indent t)))
+            (setq editorconfig-lisp-use-default-indent t)
+            (setf (alist-get 'templ-ts-mode editorconfig-indentation-alist)
+                  'go-ts-mode-indent-offset)))
 
 (setq-default ispell-dictionary "en_GB-ise-w_accents")
 (setq ispell-extra-args '("--sug-mode=ultra" "--camel-case"))
@@ -1034,11 +1100,22 @@ _C-k_: prev  _u_pper              _=_: upper/lower       _s_mart resolve
 
 (defvaralias 'nix-ts-mode-hook 'nix-mode-hook)
 
+(use-package consult-lsp
+  :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
                     "gr" #'xref-find-references
-                    "C-t" #'xref-pop-marker-stack)
+                    "C-t" #'xref-go-back)
   :ghook ('(typescript-mode-hook
             dockerfile-mode-hook
             yaml-mode-hook
@@ -1048,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)
@@ -1055,14 +1133,14 @@ _C-k_: prev  _u_pper              _=_: upper/lower       _s_mart resolve
             (when (assoc 'nix-mode eglot-server-programs)
               (setf (car (assoc 'nix-mode eglot-server-programs)) '(nix-mode nix-ts-mode)))
             (nconc eglot-server-programs '((toml-ts-mode "taplo" "lsp" "stdio")))
-            (advice-add 'eglot--message :before-while (lambda (formatstring &rest rest)
+            (advice-add 'eglot--message :before-until (lambda (formatstring &rest rest)
                                                         (s-starts-with-p "Connected!" formatstring)))
             (defun my/setup-eglot-eldoc ()
               (push 'flymake-eldoc-function eldoc-documentation-functions))
             (add-hook 'eglot-managed-mode-hook 'my/setup-eglot-eldoc)
             (setq-default eglot-workspace-configuration
                           '( :yaml (:keyOrdering nil)
-                             :nix (:autoArchive t)
+                             :nil (:nix (:flake (:autoArchive t)))
                              :gopls ( :staticcheck t
                                       :usePlaceholders t)))
             (defun my/eglot-capf ()
@@ -1090,12 +1168,13 @@ _C-k_: prev  _u_pper              _=_: upper/lower       _s_mart resolve
   ('lsp-completion-mode-hook #'my/lsp-mode-setup-completion)
   :general (:states 'normal :keymaps 'lsp-mode-map
                     "gr" #'xref-find-references
-                    "C-t" #'xref-pop-marker-stack)
+                    "C-t" #'xref-go-back)
   :config (progn
             (setq lsp-auto-guess-root t
                   lsp-auto-execute-action nil
                   lsp-headerline-breadcrumb-enable nil
                   lsp-enable-suggest-server-download nil
+                  lsp-modeline-diagnostics-enable nil
                   lsp-completion-provider :none ; value `:capf' is actually for company :(
                   lsp-diagnostics-provider t     ; this means prefer flymake over flycheck, why‽
                   )
@@ -1131,16 +1210,18 @@ _C-k_: prev  _u_pper              _=_: upper/lower       _s_mart resolve
       (call-interactively #'lsp-rename)
     (call-interactively #'eglot-rename)))
 
-;; Inside a javascript project, it's common to install tools locally to
-;; the project.  This will allows emacs to find their executables.
+(defun my/ls-consult-symbol ()
+  (interactive)
+  (if lsp-mode
+      (call-interactively #'consult-lsp-symbols)
+    (call-interactively #'consult-eglot-symbols)))
 
-(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
 
@@ -1166,15 +1247,13 @@ _C-k_: prev  _u_pper              _=_: upper/lower       _s_mart resolve
             (setq apheleia-formatters
                   (append apheleia-formatters '((nixpkgs-fmt "nixpkgs-fmt")
                                                 (golines "golines")
+                                                (taplo "taplo" "format" "-")
                                                 (prettier-gotmpl
                                                  "prettier" "--stdin-filepath" filepath
                                                  "--parser=go-template" (apheleia-formatters-indent "--use-tabs" "--tab-width")))))
-            (setf (alist-get 'go-ts-mode apheleia-mode-alist)
-                  '(golines)
-                  (alist-get 'web-mode apheleia-mode-alist)
-                  '(prettier-gotmpl))
             (setq apheleia-mode-alist (append apheleia-mode-alist '((nix-ts-mode . nixpkgs-fmt)
-                                                                    (nix-mode . nixpkgs-fmt))))
+                                                                    (nix-mode . nixpkgs-fmt)
+                                                                    (toml-ts-mode . taplo))))
             (add-hook 'apheleia-mode-hook #'turn-off-format-all-mode))
   :init (progn
           (apheleia-global-mode +1)))
@@ -1188,14 +1267,16 @@ _C-k_: prev  _u_pper              _=_: upper/lower       _s_mart resolve
   "w" '(:keymap evil-window-map :package evil)
   "x" '(:keymap ctl-x-map)
   "c" (general-simulate-key "C-c")
-  "j" #'consult-eglot-symbols
+  "j" #'my/ls-consult-symbol
   "r" #'my/ls-rename
   "q" #'evil-delete-buffer
   "p" '(:keymap project-prefix-map :package project)
   "v" #'split-window-right
   "o" #'other-window
+  "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
@@ -1222,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/gnupg/dirmngr.conf b/user/gnupg/dirmngr.conf
deleted file mode 100644
index f69421d7..00000000
--- a/user/gnupg/dirmngr.conf
+++ /dev/null
@@ -1,3 +0,0 @@
-keyserver hkps://keys.openpgp.org
-# keyserver hkp://zkaan2xfbuxia2wpf7ofnkbz6r5zdbbvxbunvp5g2iebopbfc4iqmbad.onion
-# use-tor
diff --git a/user/gnupg/gpa.conf b/user/gnupg/gpa.conf
deleted file mode 100644
index 2e33e80b..00000000
--- a/user/gnupg/gpa.conf
+++ /dev/null
@@ -1,2 +0,0 @@
-default-key 5FA779613E2AB0EEFC6DD3056A56F2A314E23293
-detailed-view
diff --git a/user/gnupg/gpg-agent.conf b/user/gnupg/gpg-agent.conf
deleted file mode 100644
index 52eb1dca..00000000
--- a/user/gnupg/gpg-agent.conf
+++ /dev/null
@@ -1,3 +0,0 @@
-enable-ssh-support
-default-cache-ttl 600
-max-cache-ttl 7200
diff --git a/user/gnupg/gpg.conf b/user/gnupg/gpg.conf
deleted file mode 100644
index 61df93cf..00000000
--- a/user/gnupg/gpg.conf
+++ /dev/null
@@ -1,83 +0,0 @@
-#
-# This is an implementation of the Riseup OpenPGP Best Practices
-# https://help.riseup.net/en/security/message-security/openpgp/best-practices
-#
-
-#-----------------------------
-# default key
-#-----------------------------
-
-# The default key to sign with. If this option is not used, the default key is
-# the first key found in the secret keyring
-
-# default-key 
-
-#-----------------------------
-# behavior
-#-----------------------------
-
-# Disable inclusion of the version string in ASCII armored output
-no-emit-version
-
-# Disable comment string in clear text signatures and ASCII armored messages
-no-comments
-
-# Display long key IDs
-keyid-format 0xlong
-
-# List all keys (or the specified ones) along with their fingerprints
-with-fingerprint
-
-# Display the calculated validity of user IDs during key listings
-list-options show-uid-validity
-verify-options show-uid-validity
-
-# Try to use the GnuPG-Agent. With this option, GnuPG first tries to connect to
-# the agent before it asks for a passphrase.
-use-agent
-
-#-----------------------------
-# keyserver
-#-----------------------------
-
-# This is the server that --recv-keys, --send-keys, and --search-keys will
-# communicate with to receive keys from, send keys to, and search for keys on
-keyserver hkps://keys.openpgp.org
-
-# Provide a certificate store to override the system default
-# Get this from https://sks-keyservers.net/sks-keyservers.netCA.pem
-# keyserver-options ca-cert-file=.gnupg/sks-keyservers.netCA.pem
-
-# Set the proxy to use for HTTP and HKP keyservers - default to the standard
-# local Tor socks proxy
-# It is encouraged to use Tor for improved anonymity. Preferrably use either a
-# dedicated SOCKSPort for GnuPG and/or enable IsolateDestPort and
-# IsolateDestAddr
-# keyserver-options http-proxy=socks5-hostname://127.0.0.1:9050
-
-# When using --refresh-keys, if the key in question has a preferred keyserver
-# URL, then disable use of that preferred keyserver to refresh the key from
-keyserver-options no-honor-keyserver-url
-# When searching for a key with --search-keys, include keys that are marked on
-# the keyserver as revoked
-keyserver-options include-revoked
-
-
-#-----------------------------
-# algorithm and ciphers
-#-----------------------------
-
-# list of personal digest preferences. When multiple digests are supported by
-# all recipients, choose the strongest one
-personal-cipher-preferences AES256 AES192 AES CAST5
-
-# list of personal digest preferences. When multiple ciphers are supported by
-# all recipients, choose the strongest one
-personal-digest-preferences SHA512 SHA384 SHA256 SHA224
-
-# message digest algorithm used when signing a key
-cert-digest-algo SHA512
-
-# This preference list is used for new keys and becomes the default for
-# "setpref" in the edit menu
-default-preference-list SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5 ZLIB BZIP2 ZIP Uncompressed
\ No newline at end of file
diff --git a/user/gnupg/trezor/dirmngr.conf b/user/gnupg/trezor/dirmngr.conf
deleted file mode 100644
index 17612d46..00000000
--- a/user/gnupg/trezor/dirmngr.conf
+++ /dev/null
@@ -1 +0,0 @@
-keyserver hkps://keys.openpgp.org
\ No newline at end of file
diff --git a/user/mba.nix b/user/mba.nix
index a205fea4..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
@@ -15,10 +14,12 @@
     ./settings/ssh.nix
     ./settings/tabnine.nix
     ./settings/user-interface.nix
+    <private>
+    <private/ssh.nix>
   ];
 
   home.username = "alan";
-  home.homeDirectory = "/home/alan";
+  home.homeDirectory = "/Users/alan";
   home.stateVersion = "22.11";
 
   launchd.agents.colima = {
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/nvim/init.lua b/user/nvim/init.lua
index f7bb020a..f9162167 100644
--- a/user/nvim/init.lua
+++ b/user/nvim/init.lua
@@ -2,6 +2,7 @@ vim.opt.autoindent = true
 
 vim.opt.background = "light"
 vim.opt.number = true
+vim.opt.clipboard = "unnamed"
 
 vim.g.mapleader = ","
 
diff --git a/user/prefect.nix b/user/prefect.nix
index b5c4789e..6cf31cbc 100644
--- a/user/prefect.nix
+++ b/user/prefect.nix
@@ -7,24 +7,21 @@
     ./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
     ./settings/fish.nix
     ./settings/git.nix
     ./settings/gnupg.nix
-    ./settings/i3.nix
     ./settings/music.nix
     ./settings/nixos.nix
-    ./settings/rofi.nix
     ./settings/passwords.nix
     ./settings/ssh.nix
-    ./settings/sxhkd.nix
     ./settings/tabnine.nix
-    ./settings/trezor.nix
     ./settings/user-interface.nix
     ./settings/xresources.nix
+    <private>
+    <private/ssh.nix>
   ];
 
   home.username = "alan";
@@ -33,8 +30,7 @@
     transgui
   ];
 
-  xsession.windowManager.i3.config.startup = [
-  ];
+  xsession.enable = true;
 
   home.stateVersion = "22.11";
 }
diff --git a/user/server.nix b/user/server.nix
index 235e6908..9b3db3fc 100644
--- a/user/server.nix
+++ b/user/server.nix
@@ -9,6 +9,7 @@
     ./settings/nix.nix
     ./settings/nixos.nix
     ./settings/development/base.nix
+    <private>
   ];
   home = {
     username = "alan";
diff --git a/user/settings/base.nix b/user/settings/base.nix
index 6725b6db..52cb14ac 100644
--- a/user/settings/base.nix
+++ b/user/settings/base.nix
@@ -1,4 +1,4 @@
-{ config
+args@{ config
 , lib
 , pkgs
 , ...
@@ -6,7 +6,10 @@
   imports = [
     ./neovim.nix
     ./shell.nix
+    (import <nix-index-database/home-manager-module.nix>
+      (args // { databases = import <nix-index-database/packages.nix>; }))
   ];
+
   # Let Home Manager install and manage itself.
   programs.home-manager.enable = true;
   manual = {
@@ -22,11 +25,8 @@
     in
     {
       EMAIL = "alan@alanpearce.eu";
-      MANPAGER = "bat -l man -p";
       ABDUCO_SOCKET_DIR = "${state}/abduco";
-      GNUPGHOME = "${data}/gnupg";
       SOLARGRAPH_CACHE = "${cache}/solargraph";
-      ASPELL_CONF = "per-conf ${conf}/aspell/aspell.conf; personal ${conf}/aspell/en.pws; repl ${conf}/aspell/en.prepl; dict-dir ${config.home.profileDirectory}/lib/aspell";
       ELECTRUMDIR = "${data}/electrum";
       DOCKER_CONFIG = "${conf}/docker";
       npm_config_userconfig = "${conf}/npm/config";
@@ -72,7 +72,7 @@
     ];
     config = {
       theme = "ansi";
-      style = "header-filename,header-filesize,grid,rule";
+      style = "header-filename,header-filesize,rule";
     };
   };
   programs.nix-index-database.comma.enable = true;
@@ -99,9 +99,11 @@
       abduco
       dvtm
       walk
-      (aspellWithDicts (d: [ d.en d.en-computers d.en-science d.de ]))
-    ]
-    ++ (
+      nuspell
+    ] ++ (with pkgs.hunspellDicts; [
+      en-gb-large
+      de-de
+    ]) ++ (
       if !stdenv.isDarwin
       then [
         file
diff --git a/user/settings/development/base.nix b/user/settings/development/base.nix
index b1c636ad..5bf54172 100644
--- a/user/settings/development/base.nix
+++ b/user/settings/development/base.nix
@@ -1,5 +1,4 @@
 { config
-, lib
 , pkgs
 , ...
 }:
@@ -20,6 +19,7 @@
 
       mosh
 
+      curlHTTP3
       xh
       htmlq
       jq
@@ -27,7 +27,6 @@
       miller
       watchexec
       entr
-      httping
 
       diffoscopeMinimal
 
@@ -39,11 +38,12 @@
       colima
       docker-client
     ] else [
-      zeal
+      httping
     ]);
 
   home.sessionVariables = {
     FLY_NO_UPDATE_CHECK = "1";
+    MOSH_TITLE_NOPREFIX = "1";
     LIMA_INSTANCE = "nixos";
   };
 
@@ -57,7 +57,10 @@
         insert_final_newline = true;
         indent_style = "space";
         indent_size = 2;
-        tab_width = 4;
+        tab_width = 2;
+      };
+      "*.fish" = {
+        indent_size = 4;
       };
       justfile = {
         indent_style = "tab";
@@ -75,6 +78,7 @@
     ea = "direnv allow";
     ex = "direnv exec";
     es = "direnv status";
+    curl3 = "${pkgs.curlHTTP3}/bin/curl --http3";
   };
   programs.direnv = {
     enable = true;
@@ -84,6 +88,7 @@
     config = {
       global = {
         disable_stdin = true;
+        load_dotenv = true;
         strict_env = true;
         hide_env_diff = true;
       };
@@ -104,4 +109,7 @@
       }
     '';
   };
+  services.lorri = {
+    enable = pkgs.stdenv.isLinux;
+  };
 }
diff --git a/user/settings/development/golang.nix b/user/settings/development/golang.nix
index 6373a1c4..39baf910 100644
--- a/user/settings/development/golang.nix
+++ b/user/settings/development/golang.nix
@@ -6,12 +6,19 @@
     gogetdoc
     gotools
     golines
+    impl
+    gomodifytags
     golangci-lint
     golangci-lint-langserver
-    nodePackages.prettier-plugin-go-template
+    personal.prettier-plugin-go-template
+  ];
+  home.sessionPath = [
+    "$HOME/go/bin"
   ];
   programs.emacs.extraPackages = epkgs: (with epkgs; [
     go-eldoc
+    go-tag
+    templ-ts-mode
   ]);
   programs.neovim.plugins = with pkgs.vimPlugins; [
     coc-go
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 4d26416c..77b3e01d 100644
--- a/user/settings/development/web.nix
+++ b/user/settings/development/web.nix
@@ -1,5 +1,6 @@
 { config
 , pkgs
+, lib
 , ...
 }: {
   home.packages = with pkgs.nodePackages; [
@@ -10,12 +11,90 @@
   ] ++ (with pkgs; [
     flyctl
     prettierd
-    htmlformat
+    personal.htmlformat
+    nodePackages.vercel
   ]);
   home.shellAliases = {
     # 0.2.25 current completion command only affects `flyctl`, although `fly` is a link to `flyctl`
     fly = "flyctl";
   };
+  programs.chromium = lib.mkIf pkgs.stdenv.isLinux {
+    enable = true;
+    package = pkgs.ungoogled-chromium;
+    extensions = [
+      # # uBlock origin
+      { id = "cjpalhdlnbpafiamejdnhcphjbkeiagm"; }
+      {
+        id = "ocaahdebbfolfmndjeplogmgcagdmblk";
+        updateUrl = "https://raw.githubusercontent.com/NeverDecaf/chromium-web-store/master/updates.xml";
+      }
+    ];
+    dictionaries = with pkgs.hunspellDictsChromium; [
+      en-gb
+      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 a65f8d8c..cc9deab6 100644
--- a/user/settings/emacs.nix
+++ b/user/settings/emacs.nix
@@ -6,13 +6,6 @@
 let
   inherit (pkgs) stdenv;
 
-  nativeCompileDirectory = "${config.xdg.cacheHome}/emacs/native-compile/";
-
-  darwinPath = pkgs.runCommandLocal "path_helper " { } ''
-    eval $(/usr/libexec/path_helper)
-    echo -n $PATH > $out
-  '';
-
   editorScript = pkgs.writeScriptBin "edit" ''
     #!${pkgs.runtimeShell}
     if [ -z "$1" ]; then
@@ -34,6 +27,11 @@ in
     xfuncname = "^(((;;;+ )|\\(|([ \t]+\\(((cl-|el-patch-)?def(un|var|macro|method|custom)|gb/))).*)$";
   };
 
+  services.emacs = lib.mkIf stdenv.isLinux {
+    enable = true;
+    package = config.programs.emacs.finalPackage;
+    client.enable = true;
+  };
   programs.emacs = {
     enable = true;
     package = lib.mkDefault (pkgs.emacs29.override { withGTK3 = true; });
@@ -65,6 +63,7 @@ in
         cdg = "cd (project-root)";
       };
     };
+
     extraPackages = epkgs: (with epkgs;
       [
         ace-link
@@ -80,6 +79,7 @@ in
         consult-dir
         consult-ghq
         consult-eglot
+        consult-lsp
         crux
         dired-git-info
         docker-compose-mode
@@ -100,6 +100,7 @@ in
         evil-commentary
         evil-embrace
         evil-exchange
+        evil-lion
         evil-matchit
         evil-mu4e
         evil-numbers
@@ -130,6 +131,7 @@ in
         lsp-mode
         lispyville
         magit
+        magit-todos
         markdown-mode
         marginalia
         nerd-icons
@@ -142,11 +144,16 @@ in
         quickrun
         rainbow-mode
         rainbow-delimiters
+        ssh-deploy
         stimmung-themes
         systemd
         tempel
         tempel-collection
         eglot-tempel
+        treemacs
+        treemacs-evil
+        treemacs-magit
+        treemacs-nerd-icons
         treesit-grammars.with-all-grammars
         treesit-auto
         vc-msg
@@ -166,23 +173,36 @@ in
               --replace-fail '"prettier"' '"prettierd"'
           '';
         });
+      just-mode = self.melpaPackages.just-mode.overrideAttrs (old: {
+        src = pkgs.fetchFromGitHub {
+          owner = "alanpearce";
+          repo = "just-mode.el";
+          rev = "08eb25e0641b4b6d79aa39182c70b9d40c56fc02";
+          sha256 = "13ccphbd95bn79pqbw6ycnfy1z8yd32swrhd1ljl7gwbhi7q6s0p";
+          # date = "2024-05-01T22:22:02+02:00";
+        };
+      });
+      treemacs-nerd-icons = self.melpaPackages.treemacs-nerd-icons.overrideAttrs (old: {
+        src = pkgs.fetchFromGitHub {
+          owner = "aaronmiller";
+          repo = "treemacs-nerd-icons";
+          sha256 = "171pdi5y9zym26iqi02c5p7zw9i7xxhv4csnjb7qlkkczha17jgp";
+          rev = "90b4f0868eea1ea923dee97d2c5457c21a61f37a";
+          # date = "2023-11-02T13:42:55-04:00";
+        };
+      });
       lsp-mode = self.melpaPackages.lsp-mode.overrideAttrs {
-        LSP_USE_PLISTS = "true"; # sync with below
+        LSP_USE_PLISTS = "true"; # must be set in early-init
       };
     };
     extraConfig = ''
-      (setenv "LSP_USE_PLISTS" "true") ; sync with above
       (with-eval-after-load 'editorconfig
-        (setq editorconfig-exec-path "${pkgs.editorconfig-core-c}/bin/editorconfig"))
-      (when (featurep 'native-compile)
-        (setq native-compile-target-directory "${nativeCompileDirectory}")
-        (add-to-list 'native-comp-eln-load-path "${nativeCompileDirectory}" :append))
+        (defvar editorconfig-exec-path "${pkgs.editorconfig-core-c}/bin/editorconfig"))
     '' + lib.optionalString stdenv.isDarwin ''
       (with-eval-after-load 'files
-        (setq insert-directory-program "${pkgs.coreutils-prefixed}/bin/gls"))
+        (defvar insert-directory-program "${pkgs.coreutils-prefixed}/bin/gls"))
       (with-eval-after-load 'dired
-        (setq dired-use-ls-dired t))
-      (setq exec-path (parse-colon-path (setenv "PATH" "${pkgs.lib.readFile darwinPath}")))
+        (defvar dired-use-ls-dired t))
     '';
   };
   home.packages = with pkgs; [
diff --git a/user/settings/fish/functions/dired.fish b/user/settings/fish/functions/dired.fish
index 97174b35..a59ffac2 100644
--- a/user/settings/fish/functions/dired.fish
+++ b/user/settings/fish/functions/dired.fish
@@ -4,5 +4,5 @@ function dired
     else
         set --function repo $pwd
     end
-    emacsclient -e "(magit-status \"$argv[1]\")"
+    emacsclient --suppress-output --eval "(dired \"$argv[1]\")"
 end
diff --git a/user/settings/fish/functions/magit.fish b/user/settings/fish/functions/magit.fish
index 048fd42f..96c90096 100644
--- a/user/settings/fish/functions/magit.fish
+++ b/user/settings/fish/functions/magit.fish
@@ -4,5 +4,5 @@ function magit
     else
         set --function repo $pwd
     end
-    emacsclient -e "(magit-status \"$argv[1]\")"
+    emacsclient --suppress-output --eval "(magit-status \"$argv[1]\")"
 end
diff --git a/user/settings/fish/functions/newest.fish b/user/settings/fish/functions/newest.fish
index 73e26dcc..3f2fa66f 100644
--- a/user/settings/fish/functions/newest.fish
+++ b/user/settings/fish/functions/newest.fish
@@ -4,9 +4,11 @@ function newest
         return 1
     end
     for arg in $argv
-        fd --hidden --print0 --max-depth 1 . $arg |
-            bfs -files0-from - \( -name .git -prune \) -o \( -printf '%TY%Tm%Td%TR %TF %h/%f\n' \) |
-            sort --reverse --key 1n,1 | head --lines 1 |
-            cut -d ' ' -f 2,3
+        if test -d $arg
+            fd --hidden --print0 --max-depth 1 . $arg |
+                bfs -files0-from - \( -name .git -prune \) -o \( -printf '%TY%Tm%Td%TH%TM %TF %h/%f\n' \) |
+                sort --key 1nr,1 | head --lines 1 |
+                cut -d ' ' -f 2,3
+        end
     end
 end
diff --git a/user/settings/fish/functions/oldest.fish b/user/settings/fish/functions/oldest.fish
index 66aad720..140d74cc 100644
--- a/user/settings/fish/functions/oldest.fish
+++ b/user/settings/fish/functions/oldest.fish
@@ -4,9 +4,11 @@ function oldest
         return 1
     end
     for arg in $argv
-        fd --hidden --print0 --max-depth 1 . $arg |
-            bfs -files0-from - \( -name .git -prune \) -o \( -printf '%TY%Tm%Td%TR %TF %h/%f\n' \) |
-            sort --key 1n,1 | head --lines 1 |
-            cut -d ' ' -f 2,3
+        if test -d $arg
+            fd --hidden --print0 --max-depth 1 . $arg |
+                bfs -files0-from - \( -name .git -prune \) -o \( -printf '%TY%Tm%Td%TH%TM %TF %h/%f\n' \) |
+                sort --key 1n,1 | head --lines 1 |
+                cut -d ' ' -f 2,3
+        end
     end
 end
diff --git a/user/settings/git.nix b/user/settings/git.nix
index 18368864..769b3728 100644
--- a/user/settings/git.nix
+++ b/user/settings/git.nix
@@ -17,6 +17,11 @@
       init = {
         defaultBranch = "main";
       };
+      advice = {
+        addEmptyPathspec = false;
+        detachedHead = false;
+        mergeConflict = false;
+      };
       ghq = {
         root = "${config.home.homeDirectory}/projects";
         user = "alanpearce";
diff --git a/user/settings/gnupg.nix b/user/settings/gnupg.nix
index 913b5d27..d719b618 100644
--- a/user/settings/gnupg.nix
+++ b/user/settings/gnupg.nix
@@ -2,8 +2,18 @@
 , pkgs
 , ...
 }: {
-  home.file.".gnupg" = {
-    recursive = true;
-    source = ../gnupg;
+  programs.gpg = {
+    enable = true;
+    homedir = "${config.xdg.dataHome}/gnupg";
+    settings = {
+      keyserver = "hkps://keys.openpgp.org";
+    };
+  };
+  services.gpg-agent = {
+    enable = true;
+    pinentryPackage = with pkgs;
+      if stdenv.isDarwin
+      then pinentry_mac
+      else pinentry-qt;
   };
 }
diff --git a/user/settings/i3.nix b/user/settings/i3.nix
index 79a7811d..e8951062 100644
--- a/user/settings/i3.nix
+++ b/user/settings/i3.nix
@@ -7,6 +7,9 @@
     recursive = true;
     source = ../i3/i3status;
   };
+  home.sessionVariables = {
+    TERMINAL = "xterm";
+  };
   xsession.windowManager.i3 =
     let
       mod = "Mod4";
diff --git a/user/settings/neovim.nix b/user/settings/neovim.nix
index 315a309b..dcee5fde 100644
--- a/user/settings/neovim.nix
+++ b/user/settings/neovim.nix
@@ -31,16 +31,22 @@
       enable = true;
       settings = {
         "json.enable" = true;
-        "suggest.enablePreview" = true;
-        "coc.preferences.formatOnSaveFiletypes" = [ "nix" ];
-        "nil.formatting.command" = "nixpkgs-fmt";
-        semantictokens = {
-          filetypes = [ "nix" ];
-        };
         languageserver = {
           nix = {
             command = "${pkgs.nil}/bin/nil";
             filetypes = [ "nix" ];
+            rootPatterns = [ "flake.nix" ];
+            settings = {
+              coc.preferences.formatOnSaveFiletypes = [ "nix" ];
+              links.tooltip = true;
+              semanticTokens = {
+                filetypes = [ "nix" ];
+              };
+              nil = {
+                formatting.command = [ "nixpkgs-fmt" ];
+                nix.flake.autoArchive = true;
+              };
+            };
           };
           lua = {
             command = "${pkgs.lua-language-server}/bin/lua-language-server";
diff --git a/user/settings/nix.nix b/user/settings/nix.nix
index e0fb3d3e..66c00daf 100644
--- a/user/settings/nix.nix
+++ b/user/settings/nix.nix
@@ -1,25 +1,26 @@
 { config
 , pkgs
+, lib
 , ...
 }:
 let
   toml = pkgs.formats.toml { };
 in
 {
-  imports = [
-    ../../pin.nix
-  ];
   nixpkgs.config = import ../config.nix;
   nix = {
     enable = true;
-    package = pkgs.nix;
+    # needed for "standalone" home-manager, conflicts with module
+    package = lib.mkDefault pkgs.nix;
     settings = {
       use-xdg-base-directories = true;
     };
   };
 
   home.packages = with pkgs; [
+    cached-nix-shell
     nil
+    npins
     nix-prefetch-scripts
     nix-init
     nix-update
@@ -29,11 +30,10 @@ in
     nixpkgs-lint
     nixpkgs-review
     nix-output-monitor
-    cachix
   ];
   xdg.configFile."nix-init/config.toml".source = toml.generate "config.toml" {
     maintainers = [ "alanpearce" ];
-    nixpkgs = "builtins.getFlake \"nixpkgs\"";
+    nixpkgs = "<nixpkgs>";
   };
   programs.emacs.extraPackages = epkgs: (with epkgs; [
     nix-mode
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 5358f618..fe2b4690 100644
--- a/user/settings/shell.nix
+++ b/user/settings/shell.nix
@@ -30,7 +30,7 @@ in
       llr = "ll -t";
 
       c = "lk";
-      "c," = "cd $(ghq list -p nixfiles)";
+      "c," = "cd ${config.home.homeDirectory + "/projects/alanpearce.eu/nixfiles"}";
       cg = "cd $(git root)";
       cdg = "cd $(git root)";
 
@@ -125,7 +125,11 @@ in
       hol = "home-manager generations";
       hox = "home-manager expire-generations '-30 days'";
 
-      nsh = "nix shell";
+      lw = "lorri watch";
+      lw1 = "lorri watch --once";
+      lwo = "lorri watch --once";
+
+      nsh = "nix-shell";
       nb = "nix build";
       nl = "nix log"; # shadows `coreutils.nl`, but I've never used that yet
       nr = "nix run";
@@ -135,6 +139,8 @@ in
       nfp = "nix flake prefetch";
       nfu = "nix flake update";
       nfl = "nix flake lock";
+      nfsh = "nix shell";
+      ndev = "nix develop";
       nlg = "nix-env --list-generations";
       snlg = "sudo nix-env --list-generations --profile /nix/var/nix/profiles/system";
       ngc = "nix-collect-garbage --delete-older-than 30d";
@@ -142,6 +148,7 @@ in
     };
   };
   home.packages = with pkgs; [
+    babashka
     fzf
     up
   ];
diff --git a/user/settings/ssh.nix b/user/settings/ssh.nix
index f5073c8d..b7c46bba 100644
--- a/user/settings/ssh.nix
+++ b/user/settings/ssh.nix
@@ -12,6 +12,10 @@
     serverAliveInterval = 15;
     extraConfig = ''
       VerifyHostKeyDNS ask
+      CanonicalizeHostname yes
+      CanonicalizeFallbackLocal no
+      CanonicalizeMaxDots 0
+      CanonicalDomains home.arpa hydra-pinecone.ts.net
     '';
     includes = [
       "local.ssh_config"
diff --git a/user/settings/tabnine.nix b/user/settings/tabnine.nix
index 377b8217..9502c68d 100644
--- a/user/settings/tabnine.nix
+++ b/user/settings/tabnine.nix
@@ -21,18 +21,28 @@
       disable_local_when_using_battery = false;
       enable_power_saving_mode = false;
       enable_telemetry = false;
+      exclude_file_masks = true;
       force_local_hub = true;
       generation = 0;
+      guuid = null;
+      gusr.gcgdc = "0000000000000000000000000000000000000000000000000000000000000000";
+      has_git_repos = null;
+      heartbeat_interval_seconds = null;
       hide_deep_information_message = false;
       hide_promotional_message = true;
       hosted_deep_completions_enabled = "Disabled";
       ignore_all_lsp = false;
       inline_suggestions_mode = true;
+      inline_suggestions_mode_clients = null;
+      last_service_level = null;
       line_suggestions = true;
       local_enabled = "Yes";
       local_indexing = null;
       local_model_size = null;
+      manually_selected_model = null;
+      model_hash_override = null;
       num_of_suggestions = 5;
+      omit_prefix_suggestions = null;
       onboarding = {
         model_type = null;
         skipped_login = true;
@@ -40,6 +50,7 @@
       };
       rate_limit_amount = null;
       rate_limit_interval_seconds = null;
+      rlhf = null;
       semantic_status = {
         css = "Enabled";
         dockerfile = "Enabled";
@@ -57,7 +68,9 @@
       tabnine_cloud_certificate_domain = null;
       tabnine_cloud_host = null;
       tabnine_cloud_port = null;
+      tabnine_hub_port = null;
       use_specialized_model_if_available = true;
+      user_understands_that_enabling_tabnine_cloud_sends_code_to_tabnine_servers = false;
     };
     lspConfig.language = {
       typescript = {
diff --git a/user/settings/trezor.nix b/user/settings/trezor.nix
deleted file mode 100644
index 6996d9b0..00000000
--- a/user/settings/trezor.nix
+++ /dev/null
@@ -1,10 +0,0 @@
-{ config
-, pkgs
-, ...
-}: {
-  home.file.".ssh/agent.config" = {
-    text = ''
-      ecdsa-curve-name = ed25519
-    '';
-  };
-}
diff --git a/user/settings/user-interface.nix b/user/settings/user-interface.nix
index 6adf57ff..29de4439 100644
--- a/user/settings/user-interface.nix
+++ b/user/settings/user-interface.nix
@@ -9,9 +9,6 @@ in
   imports = [
     ./kitty.nix
   ];
-  home.sessionVariables = {
-    TERMINAL = "xterm";
-  };
 
   services.ssh-agent = {
     enable = stdenv.hostPlatform.isLinux;
@@ -47,11 +44,15 @@ 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
     ]);
+  services.lorri.enableNotifications = true;
+  services.emacs.startWithUserSession = "graphical";
 }