about summary refs log tree commit diff stats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--flake.lock107
-rw-r--r--flake.nix8
-rw-r--r--modules/by-name/ca/cargo/module.nix18
-rw-r--r--modules/by-name/fi/firefox/module.nix2
-rw-r--r--modules/by-name/fi/firefox/profile.nix5
-rw-r--r--modules/by-name/fi/firefox/search_engines/default.nix28
-rw-r--r--modules/by-name/lf/lf/commands/default.nix5
-rwxr-xr-xmodules/by-name/lf/lf/commands/scripts/open.sh15
-rwxr-xr-xmodules/by-name/lf/lf/commands/scripts/trash_restore.sh1
-rw-r--r--modules/by-name/lf/lf/ctpv/default.nix41
-rw-r--r--modules/by-name/lf/lf/ctpv/helpers.sh2
-rw-r--r--modules/by-name/lf/lf/ctpv/prev/any.sh13
-rw-r--r--modules/by-name/lf/lf/ctpv/prev/application/archive/atool.sh5
-rw-r--r--modules/by-name/lf/lf/ctpv/prev/application/dll/dll.sh9
-rw-r--r--modules/by-name/lf/lf/ctpv/prev/application/epub/default.nix10
-rw-r--r--modules/by-name/lf/lf/ctpv/prev/application/epub/epub.sh9
-rw-r--r--modules/by-name/lf/lf/ctpv/prev/application/pdf/default.nix1
-rw-r--r--modules/by-name/lf/lf/ctpv/prev/application/pdf/pdf.sh5
-rw-r--r--modules/by-name/lf/lf/ctpv/prev/application/pgp/pgp.sh5
-rw-r--r--modules/by-name/lf/lf/ctpv/prev/application/sqlite/sqlite.sh5
-rw-r--r--modules/by-name/lf/lf/ctpv/prev/application/x-bittorrent/torrent.sh5
-rw-r--r--modules/by-name/lf/lf/ctpv/prev/application/x-pem-file/default.nix11
-rw-r--r--modules/by-name/lf/lf/ctpv/prev/application/x-pem-file/pem.sh8
-rw-r--r--modules/by-name/lf/lf/ctpv/prev/audio/audio.sh5
-rw-r--r--modules/by-name/lf/lf/ctpv/prev/audio/default.nix1
-rw-r--r--modules/by-name/lf/lf/ctpv/prev/default.nix9
-rw-r--r--modules/by-name/lf/lf/ctpv/prev/font/default.nix1
-rw-r--r--modules/by-name/lf/lf/ctpv/prev/font/font.sh5
-rw-r--r--modules/by-name/lf/lf/ctpv/prev/image/image.sh5
-rw-r--r--modules/by-name/lf/lf/ctpv/prev/image/svg+xml/svg.sh5
-rw-r--r--modules/by-name/lf/lf/ctpv/prev/image/x-xcf/xcf.sh5
-rw-r--r--modules/by-name/lf/lf/ctpv/prev/inode/ls.sh5
-rw-r--r--modules/by-name/lf/lf/ctpv/prev/inode/symlink.sh5
-rw-r--r--modules/by-name/lf/lf/ctpv/prev/libreoffice.sh5
-rw-r--r--modules/by-name/lf/lf/ctpv/prev/text/bat.sh5
-rw-r--r--modules/by-name/lf/lf/ctpv/prev/text/diff/delta.sh5
-rw-r--r--modules/by-name/lf/lf/ctpv/prev/text/glow.sh5
-rw-r--r--modules/by-name/lf/lf/ctpv/prev/text/html/default.nix13
-rw-r--r--modules/by-name/lf/lf/ctpv/prev/text/html/elinks.sh18
-rw-r--r--modules/by-name/lf/lf/ctpv/prev/text/json/jq.sh5
-rw-r--r--modules/by-name/lf/lf/ctpv/prev/video/video.sh5
-rw-r--r--modules/by-name/lf/lf/module.nix2
-rw-r--r--modules/by-name/mp/mpd/mpc.nix5
-rw-r--r--modules/by-name/nv/nvim/plgs/harpoon/default.nix116
-rw-r--r--modules/by-name/nv/nvim/plgs/lf-nvim/default.nix10
-rw-r--r--modules/by-name/nv/nvim/plgs/telescope/extensions/bibtex/default.nix5
-rw-r--r--modules/by-name/ta/taskwarrior/module.nix21
-rw-r--r--modules/by-name/ti/timewarrior/module.nix36
-rwxr-xr-xmodules/by-name/ti/timewarrior/taskwarirror_hooks/on-modify_track-timewarrior.py94
-rwxr-xr-xmodules/by-name/ti/timewarrior/taskwarrior_hooks/on-modify.track-timewarrior.py124
-rwxr-xr-xmodules/by-name/ti/timewarrior/taskwarrior_hooks/on-modify.track-total-active-time.py (renamed from modules/by-name/ti/timewarrior/taskwarirror_hooks/on-modify_track-total-active-time.py)43
-rw-r--r--modules/by-name/ts/tskm/module.nix9
-rw-r--r--modules/by-name/wa/water-reminder/module.nix57
-rw-r--r--modules/by-name/xd/xdg/module.nix123
-rwxr-xr-xmodules/by-name/xd/xdg/scripts/lf-wrapper.sh (renamed from modules/by-name/xd/xdg/lf-wrapper.sh)0
-rwxr-xr-xmodules/by-name/xd/xdg/scripts/url-handler.sh (renamed from modules/home.legacy/conf/xdg/url_handler.sh)7
-rw-r--r--modules/by-name/zs/zsh/module.nix5
-rw-r--r--modules/common/default.nix5
-rw-r--r--modules/home.legacy/conf/default.nix2
-rw-r--r--modules/home.legacy/conf/mail/accounts/soispha.nix4
-rw-r--r--modules/home.legacy/conf/xdg/default.nix59
-rw-r--r--modules/home.legacy/conf/xdg/xdg_vars.nix29
-rw-r--r--modules/home.legacy/conf/ytcc/default.nix11
-rw-r--r--modules/home.legacy/conf/ytcc/ytcc.conf37
-rw-r--r--modules/home.legacy/pkgs/default.nix5
-rwxr-xr-xpkgs/by-name/au/aumo/aumo.sh47
-rw-r--r--pkgs/by-name/au/aumo/package.nix18
-rwxr-xr-xpkgs/by-name/ba/battery/battery.sh3
-rw-r--r--pkgs/by-name/ba/battery/package.nix17
-rw-r--r--pkgs/by-name/be/beetsExtraPlugins/xtractor.nix4
-rwxr-xr-xpkgs/by-name/br/brightness/brightness.sh26
-rw-r--r--pkgs/by-name/br/brightness/package.nix20
-rwxr-xr-xpkgs/by-name/co/con2pdf/con2pdf.sh17
-rw-r--r--pkgs/by-name/co/con2pdf/package.nix17
-rwxr-xr-xpkgs/by-name/fu/fupdate-flake/fupdate-flake.sh182
-rw-r--r--pkgs/by-name/fu/fupdate-flake/package.nix28
-rwxr-xr-xpkgs/by-name/fu/fupdate-sys/fupdate-sys.sh158
-rw-r--r--pkgs/by-name/fu/fupdate-sys/package.nix (renamed from pkgs/by-name/up/update-sys/package.nix)14
-rw-r--r--pkgs/by-name/fu/fupdate/.envrc3
-rw-r--r--pkgs/by-name/fu/fupdate/.gitignore2
-rw-r--r--pkgs/by-name/fu/fupdate/Cargo.lock301
-rw-r--r--pkgs/by-name/fu/fupdate/Cargo.toml71
-rw-r--r--pkgs/by-name/fu/fupdate/flake.lock27
-rw-r--r--pkgs/by-name/fu/fupdate/flake.nix25
-rw-r--r--pkgs/by-name/fu/fupdate/fupdate.1.md70
-rwxr-xr-xpkgs/by-name/fu/fupdate/fupdate.sh197
-rw-r--r--pkgs/by-name/fu/fupdate/package.nix55
-rw-r--r--pkgs/by-name/fu/fupdate/src/cli.rs46
-rw-r--r--pkgs/by-name/fu/fupdate/src/main.rs40
-rwxr-xr-xpkgs/by-name/fu/fupdate/update.sh3
-rw-r--r--pkgs/by-name/ge/generate_moz_extension/Cargo.lock49
-rw-r--r--pkgs/by-name/ge/generate_moz_extension/Cargo.toml2
-rw-r--r--pkgs/by-name/ge/generate_moz_extension/flake.lock18
-rwxr-xr-xpkgs/by-name/gi/git-cm/git-cm.sh5
-rw-r--r--pkgs/by-name/gi/git-cm/package.nix14
-rwxr-xr-xpkgs/by-name/gi/git-edit-index/git-edit-index.sh48
-rw-r--r--pkgs/by-name/gi/git-edit-index/package.nix15
-rwxr-xr-xpkgs/by-name/hi/hibernate/hibernate.sh3
-rw-r--r--pkgs/by-name/hi/hibernate/package.nix15
-rw-r--r--pkgs/by-name/lf/lf-make-map/Cargo.lock66
-rw-r--r--pkgs/by-name/lf/lf-make-map/Cargo.toml2
-rw-r--r--pkgs/by-name/lf/lf-make-map/flake.lock24
-rwxr-xr-xpkgs/by-name/ll/ll/ll.sh8
-rw-r--r--pkgs/by-name/ll/ll/package.nix12
-rwxr-xr-xpkgs/by-name/lm/lm/lm.sh10
-rw-r--r--pkgs/by-name/lm/lm/package.nix12
-rw-r--r--pkgs/by-name/lo/lock/package.nix4
-rwxr-xr-xpkgs/by-name/mp/mpp-beetrm/mpp-beetrm.sh3
-rw-r--r--pkgs/by-name/mp/mpp-beetrm/package.nix12
-rwxr-xr-xpkgs/by-name/mp/mpp-lyrics/mpp-lyrics.sh12
-rw-r--r--pkgs/by-name/mp/mpp-lyrics/package.nix17
-rwxr-xr-xpkgs/by-name/mp/mpp-searchadd/mpp-searchadd.sh10
-rw-r--r--pkgs/by-name/mp/mpp-searchadd/package.nix12
-rwxr-xr-xpkgs/by-name/mp/mpp/mpp.sh3
-rw-r--r--pkgs/by-name/mp/mpp/package.nix26
-rw-r--r--pkgs/by-name/ri/river-mk-keymap/Cargo.lock8
-rw-r--r--pkgs/by-name/ri/river-mk-keymap/Cargo.toml2
-rw-r--r--pkgs/by-name/ri/river-mk-keymap/flake.lock6
-rw-r--r--pkgs/by-name/sc/screenshot_temporary/package.nix12
-rwxr-xr-xpkgs/by-name/sc/screenshot_temporary/screenshot_temporary.sh3
-rw-r--r--pkgs/by-name/sn/snap-sync-forked/package.nix9
-rwxr-xr-xpkgs/by-name/sn/snap-sync-forked/snap-sync-forked.sh3
-rw-r--r--pkgs/by-name/st/stamp/package.nix18
-rwxr-xr-xpkgs/by-name/st/stamp/stamp.sh6
-rw-r--r--pkgs/by-name/ts/tskm/.envrc3
-rw-r--r--pkgs/by-name/ts/tskm/Cargo.lock339
-rw-r--r--pkgs/by-name/ts/tskm/Cargo.toml17
-rw-r--r--pkgs/by-name/ts/tskm/build.rs49
-rw-r--r--pkgs/by-name/ts/tskm/flake.lock6
-rw-r--r--pkgs/by-name/ts/tskm/flake.nix4
-rw-r--r--pkgs/by-name/ts/tskm/package.nix33
-rw-r--r--pkgs/by-name/ts/tskm/src/cli.rs166
-rw-r--r--pkgs/by-name/ts/tskm/src/interface/neorg/handle.rs51
-rw-r--r--pkgs/by-name/ts/tskm/src/interface/neorg/mod.rs9
-rw-r--r--pkgs/by-name/ts/tskm/src/interface/open/handle.rs115
-rw-r--r--pkgs/by-name/ts/tskm/src/main.rs55
-rw-r--r--pkgs/by-name/ts/tskm/src/state.rs45
-rw-r--r--pkgs/by-name/ts/tskm/src/task/mod.rs186
-rwxr-xr-xpkgs/by-name/up/update-sys/update-sys.sh85
-rw-r--r--pkgs/default.nix13
-rwxr-xr-xupdate.sh5
141 files changed, 2566 insertions, 1709 deletions
diff --git a/flake.lock b/flake.lock
index ac446ada..6b1f16fb 100644
--- a/flake.lock
+++ b/flake.lock
@@ -42,11 +42,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1739094253,
-        "narHash": "sha256-yDTgmfSuL5Ax7LRuxhdoMJrBi4X9Q3fyyI7TerTXVBA=",
+        "lastModified": 1744011341,
+        "narHash": "sha256-ZwyAdfXgfigchDLMZ/UqSjLc5YKk2xnchGHuWaNfqmQ=",
         "owner": "dwarfmaster",
         "repo": "arkenfox-nixos",
-        "rev": "27e0c3094e778bd73f93bea799f627ef317e7f22",
+        "rev": "57eefe49b80ea5e02f42199db531292de34a4350",
         "type": "github"
       },
       "original": {
@@ -83,11 +83,11 @@
     },
     "crane": {
       "locked": {
-        "lastModified": 1742394900,
-        "narHash": "sha256-vVOAp9ahvnU+fQoKd4SEXB2JG2wbENkpqcwlkIXgUC0=",
+        "lastModified": 1743908961,
+        "narHash": "sha256-e1idZdpnnHWuosI3KsBgAgrhMR05T2oqskXCmNzGPq0=",
         "owner": "ipetkov",
         "repo": "crane",
-        "rev": "70947c1908108c0c551ddfd73d4f750ff2ea67cd",
+        "rev": "80ceeec0dc94ef967c371dcdc56adb280328f591",
         "type": "github"
       },
       "original": {
@@ -123,11 +123,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1741786315,
-        "narHash": "sha256-VT65AE2syHVj6v/DGB496bqBnu1PXrrzwlw07/Zpllc=",
+        "lastModified": 1744145203,
+        "narHash": "sha256-I2oILRiJ6G+BOSjY+0dGrTPe080L3pbKpc+gCV3Nmyk=",
         "owner": "nix-community",
         "repo": "disko",
-        "rev": "0d8c6ad4a43906d14abd5c60e0ffe7b587b213de",
+        "rev": "76c0a6dba345490508f36c1aa3c7ba5b6b460989",
         "type": "github"
       },
       "original": {
@@ -159,11 +159,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1741352980,
-        "narHash": "sha256-+u2UunDA4Cl5Fci3m7S643HzKmIDAe+fiXrLqYsR2fs=",
+        "lastModified": 1743550720,
+        "narHash": "sha256-hIshGgKZCgWh6AYJpJmRgFdR3WUbkY04o82X05xqQiY=",
         "owner": "hercules-ci",
         "repo": "flake-parts",
-        "rev": "f4330d22f1c5d2ba72d3d22df5597d123fdb60a9",
+        "rev": "c621e8422220273271f52058f618c94e405bb0f5",
         "type": "github"
       },
       "original": {
@@ -291,11 +291,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1743136572,
-        "narHash": "sha256-uwaVrKgi6g1TUq56247j6QvvFtYHloCkjCrEpGBvV54=",
+        "lastModified": 1744208565,
+        "narHash": "sha256-vG3JJOar/r8ognz7wuwMtOJ8Knu1MMlOzHB1N6R2MbY=",
         "owner": "nix-community",
         "repo": "home-manager",
-        "rev": "1efd2503172016a6742c87b47b43ca2c8145607d",
+        "rev": "542efdf2dfac351498f534eb71671525b9bd45ed",
         "type": "github"
       },
       "original": {
@@ -405,11 +405,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1743221873,
-        "narHash": "sha256-i8VPNm4UBsC3Ni6VwjojVJvCpS9GZ4vPrpFRtCGJzBs=",
+        "lastModified": 1743496612,
+        "narHash": "sha256-emPWa5lmKbnyuj8c1mSJUkzJNT+iJoU9GMcXwjp2oVM=",
         "owner": "lnl7",
         "repo": "nix-darwin",
-        "rev": "53d0f0ed11487a4476741fde757d0feabef4cc4e",
+        "rev": "73d59580d01e9b9f957ba749f336a272869c42dd",
         "type": "github"
       },
       "original": {
@@ -446,11 +446,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1742701275,
-        "narHash": "sha256-AulwPVrS9859t+eJ61v24wH/nfBEIDSXYxlRo3fL/SA=",
+        "lastModified": 1743911143,
+        "narHash": "sha256-4j4JPwr0TXHH4ZyorXN5yIcmqIQr0WYacsuPA4ktONo=",
         "owner": "nix-community",
         "repo": "nix-index-database",
-        "rev": "36dc43cb50d5d20f90a28d53abb33a32b0a2aae6",
+        "rev": "a36f6a7148aec2c77d78e4466215cceb2f5f4bfb",
         "type": "github"
       },
       "original": {
@@ -472,11 +472,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1743157969,
-        "narHash": "sha256-ldlSyVKNaXL7ys7Jr7mLhlpGDE4VPVcWmV7Odupn5TY=",
+        "lastModified": 1744200902,
+        "narHash": "sha256-BqTLjxT1C1XfREDBQSxPrfKI9DBpZHBVLHzfXZs+h8M=",
         "owner": "nix-community",
         "repo": "nixvim",
-        "rev": "95573411bc9be155a93b0f15d2bad62c6b43b3cc",
+        "rev": "51203927e395535c4a427295efed4e1b2ef8349b",
         "type": "github"
       },
       "original": {
@@ -510,11 +510,11 @@
     },
     "nixpkgs": {
       "locked": {
-        "lastModified": 1743095683,
-        "narHash": "sha256-gWd4urRoLRe8GLVC/3rYRae1h+xfQzt09xOfb0PaHSk=",
+        "lastModified": 1744098102,
+        "narHash": "sha256-tzCdyIJj9AjysC3OuKA+tMD/kDEDAF9mICPDU7ix0JA=",
         "owner": "NixOS",
         "repo": "nixpkgs",
-        "rev": "5e5402ecbcb27af32284d4a62553c019a3a49ea6",
+        "rev": "c8cd81426f45942bb2906d5ed2fe21d2f19d95b7",
         "type": "github"
       },
       "original": {
@@ -524,29 +524,13 @@
         "type": "github"
       }
     },
-    "nixpkgs-lf": {
-      "locked": {
-        "lastModified": 1743256538,
-        "narHash": "sha256-fG19N9PvPtsV3UUwT7lauNJ7tE4ZB/EPKwwENrqqKCQ=",
-        "owner": "bpeetz",
-        "repo": "nixpkgs",
-        "rev": "e315c0e09beaf4daf4041d402067cbdbc84870d9",
-        "type": "github"
-      },
-      "original": {
-        "owner": "bpeetz",
-        "ref": "init-lf.nvim",
-        "repo": "nixpkgs",
-        "type": "github"
-      }
-    },
     "nixpkgs-lib": {
       "locked": {
-        "lastModified": 1742692082,
-        "narHash": "sha256-s3XOULQj7BVO7myY5V4Sob0tRZ7nRpwEOIzXg/MkD/Q=",
+        "lastModified": 1743901752,
+        "narHash": "sha256-WKv9xikcdKm0VWOnhttJ6dAxorQJDjJCfIsjrP00ip4=",
         "owner": "nix-community",
         "repo": "nixpkgs.lib",
-        "rev": "a09310bc940f245e51b1ffea68731244ca38f2bd",
+        "rev": "2bb0af21f02e8c61a5dded3832b92db47d6a0411",
         "type": "github"
       },
       "original": {
@@ -557,11 +541,11 @@
     },
     "nixpkgs-stable": {
       "locked": {
-        "lastModified": 1742937945,
-        "narHash": "sha256-lWc+79eZRyvHp/SqMhHTMzZVhpxkRvthsP1Qx6UCq0E=",
+        "lastModified": 1743975612,
+        "narHash": "sha256-o4FjFOUmjSRMK7dn0TFdAT0RRWUWD+WsspPHa+qEQT8=",
         "owner": "NixOS",
         "repo": "nixpkgs",
-        "rev": "d02d88f8de5b882ccdde0465d8fa2db3aa1169f7",
+        "rev": "a880f49904d68b5e53338d1e8c7bf80f59903928",
         "type": "github"
       },
       "original": {
@@ -582,11 +566,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1743201766,
-        "narHash": "sha256-bb/dqoIjtIWtJRzASOe8g4m8W2jUIWtuoGPXdNjM/Tk=",
+        "lastModified": 1743683223,
+        "narHash": "sha256-LdXtHFvhEC3S64dphap1pkkzwjErbW65eH1VRerCUT0=",
         "owner": "NuschtOS",
         "repo": "search",
-        "rev": "2651dbfad93d6ef66c440cbbf23238938b187bde",
+        "rev": "56a49ffef2908dad1e9a8adef1f18802bc760962",
         "type": "github"
       },
       "original": {
@@ -612,11 +596,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1742397518,
-        "narHash": "sha256-nzgO/ZCSBzWjbMkYDxG+yl9Z2eGbCgQu06Oku3ir5D4=",
+        "lastModified": 1743690424,
+        "narHash": "sha256-cX98bUuKuihOaRp8dNV1Mq7u6/CQZWTPth2IJPATBXc=",
         "owner": "nix-community",
         "repo": "poetry2nix",
-        "rev": "b9a98080beff0903a5e5fe431f42cde1e3e50d6b",
+        "rev": "ce2369db77f45688172384bbeb962bc6c2ea6f94",
         "type": "github"
       },
       "original": {
@@ -737,7 +721,6 @@
         "nixVim": "nixVim",
         "nixos-generators": "nixos-generators",
         "nixpkgs": "nixpkgs",
-        "nixpkgs-lf": "nixpkgs-lf",
         "nixpkgs-lib": "nixpkgs-lib",
         "nixpkgs-stable": "nixpkgs-stable",
         "nuschtosSearch": "nuschtosSearch",
@@ -760,11 +743,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1743215516,
-        "narHash": "sha256-52qbrkG65U1hyrQWltgHTgH4nm0SJL+9TWv2UDCEPNI=",
+        "lastModified": 1744166053,
+        "narHash": "sha256-mpI7OzFwp+fUeDtZYQbVZ2YmtxTN2UNrrOwbYD27xKU=",
         "owner": "oxalica",
         "repo": "rust-overlay",
-        "rev": "524463199fdee49338006b049bc376b965a2cfed",
+        "rev": "896158be1835589db6f42f45ef0a49b8b492cc66",
         "type": "github"
       },
       "original": {
@@ -888,11 +871,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1743081648,
-        "narHash": "sha256-WRAylyYptt6OX5eCEBWyTwOEqEtD6zt33rlUkr6u3cE=",
+        "lastModified": 1743748085,
+        "narHash": "sha256-uhjnlaVTWo5iD3LXics1rp9gaKgDRQj6660+gbUU3cE=",
         "owner": "numtide",
         "repo": "treefmt-nix",
-        "rev": "29a3d7b768c70addce17af0869f6e2bd8f5be4b7",
+        "rev": "815e4121d6a5d504c0f96e5be2dd7f871e4fd99d",
         "type": "github"
       },
       "original": {
diff --git a/flake.nix b/flake.nix
index 8d8ce03a..220095aa 100644
--- a/flake.nix
+++ b/flake.nix
@@ -10,8 +10,6 @@
     nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
 
     # open nixpkgs prs
-    # FIXME: Close these PRs <2024-09-07>
-    nixpkgs-lf.url = "github:bpeetz/nixpkgs/init-lf.nvim";
 
     library = {
       url = "git+https://git.foss-syndicate.org/vhack.eu/nix-library?ref=prime";
@@ -257,7 +255,6 @@
     self,
     nixpkgs,
     nixpkgs-stable,
-    nixpkgs-lf,
     library,
     # modules
     home-manager,
@@ -289,14 +286,11 @@
     pkgsStable = nixpkgs-stable.legacyPackages.${system};
     pkgs = nixpkgs.legacyPackages.${system};
     myPkgs = import ./pkgs {
-      inherit sysLib pkgs nixLib;
+      inherit pkgs nixLib;
     };
 
     nixpkgs_as_input = nixpkgs;
     nixpkgs_open_prs = {
-      inherit
-        nixpkgs-lf
-        ;
     };
 
     outputs = import ./flake {
diff --git a/modules/by-name/ca/cargo/module.nix b/modules/by-name/ca/cargo/module.nix
new file mode 100644
index 00000000..f7153509
--- /dev/null
+++ b/modules/by-name/ca/cargo/module.nix
@@ -0,0 +1,18 @@
+{
+  config,
+  lib,
+  ...
+}: let
+  cfg = config.soispha.programs.cargo;
+in {
+  options.soispha.programs.cargo = {
+    enable = lib.mkEnableOption "cargo";
+  };
+  config = lib.mkIf cfg.enable {
+    home-manager.users.soispha = {
+      home.sessionVariables = {
+        CARGO_HOME = "${config.home-manager.users.soispha.xdg.dataHome}/cargo";
+      };
+    };
+  };
+}
diff --git a/modules/by-name/fi/firefox/module.nix b/modules/by-name/fi/firefox/module.nix
index feeb8198..17bfa049 100644
--- a/modules/by-name/fi/firefox/module.nix
+++ b/modules/by-name/fi/firefox/module.nix
@@ -120,7 +120,7 @@ in {
       enable = true;
       preferencesStatus = "locked";
 
-      languagePacks = ["de" "sv-SE" "en-CA"];
+      languagePacks = ["en-CA" "de" "sv-SE"];
 
       nativeMessagingHosts.packages = [
         pkgs.tridactyl-native
diff --git a/modules/by-name/fi/firefox/profile.nix b/modules/by-name/fi/firefox/profile.nix
index 7cdf4d90..195c2075 100644
--- a/modules/by-name/fi/firefox/profile.nix
+++ b/modules/by-name/fi/firefox/profile.nix
@@ -1,4 +1,7 @@
-{config, pkgs}: preConfig: ({
+{
+  config,
+  pkgs,
+}: preConfig: ({
     userChrome = ./userChrome.css;
 
     bookmarks = {
diff --git a/modules/by-name/fi/firefox/search_engines/default.nix b/modules/by-name/fi/firefox/search_engines/default.nix
index d05a5af8..51a447e1 100644
--- a/modules/by-name/fi/firefox/search_engines/default.nix
+++ b/modules/by-name/fi/firefox/search_engines/default.nix
@@ -1,6 +1,6 @@
 {pkgs, ...}: {
   # DEFAULT
-  brave-search= {
+  brave-search = {
     name = "Brave Search";
     urls = [{template = "https://search.brave.com/search?q={searchTerms}";}];
     icon = ./logos/brave.svg;
@@ -8,53 +8,53 @@
   };
 
   # NIX
-  nix-packages= {
+  nix-packages = {
     name = "Nix packages";
     urls = [{template = "https://search.nixos.org/packages?type=packages&query={searchTerms}";}];
     icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg";
     definedAliases = ["@np"];
   };
 
-  nix-functions= {
+  nix-functions = {
     name = "Nix functions";
     urls = [{template = "https://noogle.dev/q?term={searchTerms}";}];
     icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg";
     definedAliases = ["@ng"];
   };
 
-  nixos-options= {
+  nixos-options = {
     name = "NixOS options";
     urls = [{template = "https://search.nixos.org/options?type=options&query={searchTerms}";}];
     icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg";
     definedAliases = ["@no"];
   };
-  homemanager-options= {
+  homemanager-options = {
     name = "Home-Manager options";
     urls = [{template = "https://home-manager-options.extranix.com/?query={searchTerms}&release=master";}];
     icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg";
     definedAliases = ["@nh"];
   };
 
-  nixpkgs-issues= {
+  nixpkgs-issues = {
     name = "Nixpkgs issues";
     urls = [{template = "https://github.com/NixOS/nixpkgs/issues?q=is%3Aissue+is%3Aopen+{searchTerms}";}];
     icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg";
     definedAliases = ["@ni"];
   };
-  nixpkgs-pull-requests= {
+  nixpkgs-pull-requests = {
     name = "Nixpkgs pull requests";
     urls = [{template = "https://github.com/NixOS/nixpkgs/pulls?q=is%3Apr+is%3Aopen+{searchTerms}";}];
     icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg";
     definedAliases = ["@nr"];
   };
 
-  nixpkgs-pull-requests-tracker= {
+  nixpkgs-pull-requests-tracker = {
     name = "Nixpkgs pull requests tracker";
     urls = [{template = "https://nixpk.gs/pr-tracker.html?pr={searchTerms}";}];
     icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg";
     definedAliases = ["@nt"];
   };
-  nixos-wiki= {
+  nixos-wiki = {
     name = "NixOS Wiki";
     urls = [{template = "https://wiki.nixos.org/w/index.php?search={searchTerms}";}];
     icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg";
@@ -62,13 +62,13 @@
   };
 
   # RUST
-  rust-std= {
+  rust-std = {
     name = "Rust std";
     urls = [{template = "https://doc.rust-lang.org/std/?search={searchTerms}";}];
     icon = ./logos/rust_std.svg;
     definedAliases = ["@rs"];
   };
-  rust-tokio= {
+  rust-tokio = {
     name = "Rust tokio";
     urls = [{template = "https://docs.rs/tokio/latest/tokio/index.html?search={searchTerms}";}];
     icon = ./logos/rust_tokio.png;
@@ -76,19 +76,19 @@
   };
 
   # OTHER
-  google-scholar= {
+  google-scholar = {
     name = "Google Scholar";
     urls = [{template = "https://scholar.google.com/scholar?hl=en&q={searchTerms}";}];
     icon = ./logos/google_scholar.ico;
     definedAliases = ["@gs"];
   };
-  wikipedia= {
+  wikipedia = {
     name = "Wikipedia";
     urls = [{template = "https://en.wikipedia.org/wiki/{searchTerms}";}];
     icon = ./logos/wikipedia.svg;
     definedAliases = ["@wp"];
   };
-  arch-wiki= {
+  arch-wiki = {
     name = "Arch Wiki";
     urls = [{template = "https://wiki.archlinux.org/index.php?search={searchTerms}";}];
     icon = ./logos/arch_linux.svg;
diff --git a/modules/by-name/lf/lf/commands/default.nix b/modules/by-name/lf/lf/commands/default.nix
index 0c42607b..90b333c6 100644
--- a/modules/by-name/lf/lf/commands/default.nix
+++ b/modules/by-name/lf/lf/commands/default.nix
@@ -124,11 +124,6 @@ in {
     dependencies = [pkgs.gnused];
   };
 
-  open = async {
-    name = "open";
-    dependencies = [pkgs.handlr-regex];
-  };
-
   trash = pipe {
     name = "trash";
     dependencies = [pkgs.trash-cli];
diff --git a/modules/by-name/lf/lf/commands/scripts/open.sh b/modules/by-name/lf/lf/commands/scripts/open.sh
deleted file mode 100755
index b494074f..00000000
--- a/modules/by-name/lf/lf/commands/scripts/open.sh
+++ /dev/null
@@ -1,15 +0,0 @@
-# shellcheck shell=sh
-
-# shellcheck disable=SC2269
-f="$f"
-# shellcheck disable=SC2269
-fx="$fx"
-# shellcheck disable=SC2269
-fs="$fs"
-# shellcheck disable=SC2269
-id="$id"
-
-# TODO: For some reason, `xdg-utils` tries to open firefox with it's default profile for
-# _everything_. Using `handlr-regex` sort-of solves this. <2025-04-04>
-handlr open "$f"
-# vim: ft=sh
diff --git a/modules/by-name/lf/lf/commands/scripts/trash_restore.sh b/modules/by-name/lf/lf/commands/scripts/trash_restore.sh
index 5a7624db..cc2d4890 100755
--- a/modules/by-name/lf/lf/commands/scripts/trash_restore.sh
+++ b/modules/by-name/lf/lf/commands/scripts/trash_restore.sh
@@ -13,6 +13,5 @@ while IFS="$(printf '\n')" read -r file; do
     set -- "$@" "$(pwd)/$file"
 done <"$(conceal list | fzf --multi --ansi | awk '{$1="";$2=""; print $0}' | sed 's/^\s*//' | tmp)"
 
-
 [ "$#" -ne 0 ] && trash restore --match=exact "$@"
 # vim: ft=sh
diff --git a/modules/by-name/lf/lf/ctpv/default.nix b/modules/by-name/lf/lf/ctpv/default.nix
index 3748eca4..98438fba 100644
--- a/modules/by-name/lf/lf/ctpv/default.nix
+++ b/modules/by-name/lf/lf/ctpv/default.nix
@@ -1,5 +1,4 @@
 {
-  sysLib,
   lib,
   config,
   pkgs,
@@ -8,15 +7,15 @@
   functionCall = {
     name,
     dependencies,
-    replacementStrings,
     scriptPath,
-    ...
+    environment,
   }:
-    sysLib.writeShellScript {
+    pkgs.writeShellApplication {
       inherit name;
-      src = scriptPath;
-      keepPath = false;
-      inherit replacementStrings dependencies;
+      text = builtins.readFile ./helpers.sh + builtins.readFile scriptPath;
+      inheritPath = false;
+      runtimeInputs = dependencies;
+      runtimeEnv = environment;
     }
     + "/bin/${name}";
 
@@ -24,8 +23,8 @@
     matches,
     priority,
     dependencies,
-    replacementStrings,
     previewer,
+    environment,
   }: let
     mkMimePath = val: let
       split = lib.strings.splitString "/" val;
@@ -49,7 +48,7 @@
       inherit
         name
         dependencies
-        replacementStrings
+        environment
         ;
       scriptPath = previewer;
     };
@@ -93,6 +92,12 @@
         };
       };
 
+      environment = lib.mkOption {
+        type = lib.types.attrsOf lib.types.str;
+        default = {};
+        description = "Environment variables to set for the script";
+      };
+
       previewer = lib.mkOption {
         type = lib.types.pathInStore;
         description = "The path to the preview script or binary";
@@ -104,13 +109,6 @@
         default = 0;
         description = "The priority to use this previewer.";
       };
-      replacementStrings = lib.mkOption {
-        type = lib.types.attrsOf (lib.types.either lib.types.str lib.types.pathInStore);
-        default = {
-          HELPERS = ./helpers.sh;
-        };
-        description = "Arbitrary strings to replace in the shell script.";
-      };
       dependencies = lib.mkOption {
         type = lib.types.listOf lib.types.package;
         default = [];
@@ -153,17 +151,6 @@ in {
 
     package = lib.mkPackageOption pkgs "ctpv-64-types" {};
 
-    # TODO: This is necessary, as the `./prev` dir is imported separately and as such
-    # cannot access the `./helpers.sh` file in it's parent directory.
-    # This separate import should ideally be removed. <2024-12-15>
-    helpers = lib.mkOption {
-      default = ./helpers.sh;
-      type = lib.types.pathInStore;
-
-      internal = true;
-      readOnly = true;
-    };
-
     previewers = lib.mkOption {
       description = ''
         The previewers to add to the config file.
diff --git a/modules/by-name/lf/lf/ctpv/helpers.sh b/modules/by-name/lf/lf/ctpv/helpers.sh
index 6dc7fee6..30e4483a 100644
--- a/modules/by-name/lf/lf/ctpv/helpers.sh
+++ b/modules/by-name/lf/lf/ctpv/helpers.sh
@@ -59,7 +59,7 @@ preview_xxd() {
     # This has been derived mathematically.
     octet_columns=$(((2 * w - 22) / 7))
 
-    if [ -n "$CTPV_LESS_PREVIEWER" ]; then
+    if [ "${CTPV_LESS_PREVIEWER:-unset}" != "-unset" ]; then
         __base_xxd_preview "$1"
     else
         __base_xxd_preview "$1" -len "$((h * octet_columns))"
diff --git a/modules/by-name/lf/lf/ctpv/prev/any.sh b/modules/by-name/lf/lf/ctpv/prev/any.sh
index 38dfd538..7ce72dcd 100644
--- a/modules/by-name/lf/lf/ctpv/prev/any.sh
+++ b/modules/by-name/lf/lf/ctpv/prev/any.sh
@@ -1,16 +1,13 @@
 #! /usr/bin/env dash
 
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
-
 # shellcheck disable=SC2269
 f="$f"
 # shellcheck disable=SC2269
 w="$w"
 # shellcheck disable=SC2269
-e="$e"
+e="${e:-[missing extension]}"
 # shellcheck disable=SC2269
-m="$m"
+m="${m:-[missing mime type]}"
 # shellcheck disable=SC2269
 h="$h"
 
@@ -19,8 +16,6 @@ extension="$e"
 # shellcheck disable=SC2269
 mime="$m"
 
-. %HELPERS
-
 is_not_printable() {
     grep --text --quiet '[^[:print:]]' "$1"
 }
@@ -33,8 +28,8 @@ case "$mime" in
 *)
     echo "(ctpv did not recognize this file, with extension: '$extension' and mime: '$mime')"
 
-    directory_storage="%STORAGE_DIRECTORY/$mime"
-    mkdir --parents "$(dirname "%STORAGE_DIRECTORY/$mime")"
+    directory_storage="$STORAGE_DIRECTORY/$mime"
+    mkdir --parents "$(dirname "$STORAGE_DIRECTORY/$mime")"
 
     printf "%s -- %s\n" "$f" "$extension" >>"$directory_storage"
     ;;
diff --git a/modules/by-name/lf/lf/ctpv/prev/application/archive/atool.sh b/modules/by-name/lf/lf/ctpv/prev/application/archive/atool.sh
index 5f4baac7..3aebfbb3 100644
--- a/modules/by-name/lf/lf/ctpv/prev/application/archive/atool.sh
+++ b/modules/by-name/lf/lf/ctpv/prev/application/archive/atool.sh
@@ -1,11 +1,6 @@
 #! /usr/bin/env dash
 
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
-
 # shellcheck disable=SC2269
 f="$f"
 
-. %HELPERS
-
 atool --list -- "$f"
diff --git a/modules/by-name/lf/lf/ctpv/prev/application/dll/dll.sh b/modules/by-name/lf/lf/ctpv/prev/application/dll/dll.sh
index 678506eb..5237ecec 100644
--- a/modules/by-name/lf/lf/ctpv/prev/application/dll/dll.sh
+++ b/modules/by-name/lf/lf/ctpv/prev/application/dll/dll.sh
@@ -1,19 +1,14 @@
 #! /usr/bin/env dash
 
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
-
 # shellcheck disable=SC2269
 f="$f"
 # shellcheck disable=SC2269
 w="$w"
 # shellcheck disable=SC2269
-e="$e"
+e="${e:-[missing extension]}"
 # shellcheck disable=SC2269
-m="$m"
+m="${m:-[missing mime type]}"
 # shellcheck disable=SC2269
 h="$h"
 
-. %HELPERS
-
 preview_xxd "$f"
diff --git a/modules/by-name/lf/lf/ctpv/prev/application/epub/default.nix b/modules/by-name/lf/lf/ctpv/prev/application/epub/default.nix
index 40510a78..b4df845a 100644
--- a/modules/by-name/lf/lf/ctpv/prev/application/epub/default.nix
+++ b/modules/by-name/lf/lf/ctpv/prev/application/epub/default.nix
@@ -5,11 +5,11 @@
       matches.mime = ["application/epub+zip"];
       matches.extension = ["epub"];
       priority = 1;
-      dependencies = with pkgs; [
-        bk
-        epub-thumbnailer
-        chafa
-        gnused
+      dependencies = [
+        pkgs.bk
+        pkgs.epub-thumbnailer
+        pkgs.chafa
+        pkgs.gnused
       ];
     };
   };
diff --git a/modules/by-name/lf/lf/ctpv/prev/application/epub/epub.sh b/modules/by-name/lf/lf/ctpv/prev/application/epub/epub.sh
index 703e7dad..3bec0dd1 100644
--- a/modules/by-name/lf/lf/ctpv/prev/application/epub/epub.sh
+++ b/modules/by-name/lf/lf/ctpv/prev/application/epub/epub.sh
@@ -1,23 +1,18 @@
 #! /usr/bin/env dash
 
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
-
 # shellcheck disable=SC2269
 f="$f"
 # shellcheck disable=SC2269
 w="$w"
 # shellcheck disable=SC2269
-e="$e"
+e="${e:-[missing extension]}"
 # shellcheck disable=SC2269
-m="$m"
+m="${m:-[missing mime type]}"
 # shellcheck disable=SC2269
 h="$h"
 # shellcheck disable=SC2269
 cache_f="$cache_f"
 
-. %HELPERS
-
 epub() {
     epub-thumbnailer "$f" "$cache_f" 20000
 }
diff --git a/modules/by-name/lf/lf/ctpv/prev/application/pdf/default.nix b/modules/by-name/lf/lf/ctpv/prev/application/pdf/default.nix
index d3061ea8..24112737 100644
--- a/modules/by-name/lf/lf/ctpv/prev/application/pdf/default.nix
+++ b/modules/by-name/lf/lf/ctpv/prev/application/pdf/default.nix
@@ -8,6 +8,7 @@
         pkgs.poppler_utils # for `pdftoppm`
         pkgs.chafa
         pkgs.gnused
+        pkgs.coreutils
       ];
     };
   };
diff --git a/modules/by-name/lf/lf/ctpv/prev/application/pdf/pdf.sh b/modules/by-name/lf/lf/ctpv/prev/application/pdf/pdf.sh
index 2f807b1a..4d99f4b0 100644
--- a/modules/by-name/lf/lf/ctpv/prev/application/pdf/pdf.sh
+++ b/modules/by-name/lf/lf/ctpv/prev/application/pdf/pdf.sh
@@ -1,15 +1,10 @@
 #! /usr/bin/env dash
 
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
-
 # shellcheck disable=SC2269
 f="$f"
 # shellcheck disable=SC2269
 cache_f="$cache_f"
 
-. %HELPERS
-
 pdf() {
     pdftoppm -f 1 -l 1 \
         -scale-to-x 1920 \
diff --git a/modules/by-name/lf/lf/ctpv/prev/application/pgp/pgp.sh b/modules/by-name/lf/lf/ctpv/prev/application/pgp/pgp.sh
index a4eefd96..4747a8c4 100644
--- a/modules/by-name/lf/lf/ctpv/prev/application/pgp/pgp.sh
+++ b/modules/by-name/lf/lf/ctpv/prev/application/pgp/pgp.sh
@@ -1,13 +1,8 @@
 #! /usr/bin/env dash
 
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
-
 # shellcheck disable=SC2269
 f="$f"
 # shellcheck disable=SC2269
 w="$w"
 
-. %HELPERS
-
 hide_script_env sq inspect --certifications -- "$f"
diff --git a/modules/by-name/lf/lf/ctpv/prev/application/sqlite/sqlite.sh b/modules/by-name/lf/lf/ctpv/prev/application/sqlite/sqlite.sh
index 07e77a93..62c1abec 100644
--- a/modules/by-name/lf/lf/ctpv/prev/application/sqlite/sqlite.sh
+++ b/modules/by-name/lf/lf/ctpv/prev/application/sqlite/sqlite.sh
@@ -1,15 +1,10 @@
 #! /usr/bin/env dash
 
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
-
 # shellcheck disable=SC2269
 f="$f"
 # shellcheck disable=SC2269
 w="$w"
 
-. %HELPERS
-
 echo "SQLite database. Schema:"
 echo
 
diff --git a/modules/by-name/lf/lf/ctpv/prev/application/x-bittorrent/torrent.sh b/modules/by-name/lf/lf/ctpv/prev/application/x-bittorrent/torrent.sh
index 16cfcbcd..f1da355a 100644
--- a/modules/by-name/lf/lf/ctpv/prev/application/x-bittorrent/torrent.sh
+++ b/modules/by-name/lf/lf/ctpv/prev/application/x-bittorrent/torrent.sh
@@ -1,13 +1,8 @@
 #! /usr/bin/env dash
 
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
-
 # shellcheck disable=SC2269
 f="$f"
 # shellcheck disable=SC2269
 cache_f="$cache_f"
 
-. %HELPERS
-
 transmission-show -- "$f"
diff --git a/modules/by-name/lf/lf/ctpv/prev/application/x-pem-file/default.nix b/modules/by-name/lf/lf/ctpv/prev/application/x-pem-file/default.nix
new file mode 100644
index 00000000..a6a32808
--- /dev/null
+++ b/modules/by-name/lf/lf/ctpv/prev/application/x-pem-file/default.nix
@@ -0,0 +1,11 @@
+{pkgs, ...}: {
+  soispha.programs.lf.ctpv.previewers = {
+    pem = {
+      previewer = ./pem.sh;
+      matches.mime = ["application/x-pem-file"];
+      dependencies = [
+        pkgs.openssl
+      ];
+    };
+  };
+}
diff --git a/modules/by-name/lf/lf/ctpv/prev/application/x-pem-file/pem.sh b/modules/by-name/lf/lf/ctpv/prev/application/x-pem-file/pem.sh
new file mode 100644
index 00000000..76ee3002
--- /dev/null
+++ b/modules/by-name/lf/lf/ctpv/prev/application/x-pem-file/pem.sh
@@ -0,0 +1,8 @@
+#! /usr/bin/env dash
+
+# shellcheck disable=SC2269
+f="$f"
+# shellcheck disable=SC2269
+cache_f="$cache_f"
+
+openssl x509 -in "$f" -text -noout
diff --git a/modules/by-name/lf/lf/ctpv/prev/audio/audio.sh b/modules/by-name/lf/lf/ctpv/prev/audio/audio.sh
index c5abc646..2e9e147c 100644
--- a/modules/by-name/lf/lf/ctpv/prev/audio/audio.sh
+++ b/modules/by-name/lf/lf/ctpv/prev/audio/audio.sh
@@ -1,15 +1,10 @@
 #! /usr/bin/env dash
 
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
-
 # shellcheck disable=SC2269
 f="$f"
 # shellcheck disable=SC2269
 cache_f="$cache_f"
 
-. %HELPERS
-
 audio() {
     ffmpegthumbnailer -i "$f" -s 0 -q 5 -t 10 -o "$cache_f" 2>/dev/null
 }
diff --git a/modules/by-name/lf/lf/ctpv/prev/audio/default.nix b/modules/by-name/lf/lf/ctpv/prev/audio/default.nix
index 0c60e9d5..20df04b3 100644
--- a/modules/by-name/lf/lf/ctpv/prev/audio/default.nix
+++ b/modules/by-name/lf/lf/ctpv/prev/audio/default.nix
@@ -9,6 +9,7 @@
 
         pkgs.chafa
         pkgs.gnused
+        pkgs.coreutils
       ];
     };
   };
diff --git a/modules/by-name/lf/lf/ctpv/prev/default.nix b/modules/by-name/lf/lf/ctpv/prev/default.nix
index b59430f8..3e54e88a 100644
--- a/modules/by-name/lf/lf/ctpv/prev/default.nix
+++ b/modules/by-name/lf/lf/ctpv/prev/default.nix
@@ -10,18 +10,15 @@ in {
       previewer = ./any.sh;
       priority = -1;
       matches.mime = ["*/*"];
-      replacementStrings = {
-        # FIXME: This declaration replaces the default (although it should be merged with
-        # the default value.) There must be a way, so that repeating the default values is
-        # not needed. <2024-12-15>
-        HELPERS = cfg.ctpv.helpers;
-
+      environment = {
         STORAGE_DIRECTORY = "${cfg.ctpv.xdgDataHome}/ctpv/missing_previews";
       };
 
       dependencies = [
         pkgs.tinyxxd # For xxd
         pkgs.bat
+        pkgs.gnugrep
+        pkgs.coreutils
       ];
     };
   };
diff --git a/modules/by-name/lf/lf/ctpv/prev/font/default.nix b/modules/by-name/lf/lf/ctpv/prev/font/default.nix
index 306e7892..48bcb7ad 100644
--- a/modules/by-name/lf/lf/ctpv/prev/font/default.nix
+++ b/modules/by-name/lf/lf/ctpv/prev/font/default.nix
@@ -13,6 +13,7 @@
         pkgs.fontforge # for `fontimage`
         pkgs.chafa
         pkgs.gnused
+        pkgs.coreutils
       ];
     };
   };
diff --git a/modules/by-name/lf/lf/ctpv/prev/font/font.sh b/modules/by-name/lf/lf/ctpv/prev/font/font.sh
index 4065557e..9e5ef3c1 100644
--- a/modules/by-name/lf/lf/ctpv/prev/font/font.sh
+++ b/modules/by-name/lf/lf/ctpv/prev/font/font.sh
@@ -1,15 +1,10 @@
 #! /usr/bin/env dash
 
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
-
 # shellcheck disable=SC2269
 f="$f"
 # shellcheck disable=SC2269
 cache_f="$cache_f"
 
-. %HELPERS
-
 font() {
     fontimage -o "$cache_f.png" "$f" 2>/dev/null &&
         mv -- "$cache_f.png" "$cache_f"
diff --git a/modules/by-name/lf/lf/ctpv/prev/image/image.sh b/modules/by-name/lf/lf/ctpv/prev/image/image.sh
index b5b97668..42c99c23 100644
--- a/modules/by-name/lf/lf/ctpv/prev/image/image.sh
+++ b/modules/by-name/lf/lf/ctpv/prev/image/image.sh
@@ -1,11 +1,6 @@
 #! /usr/bin/env dash
 
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
-
 # shellcheck disable=SC2269
 f="$f"
 
-. %HELPERS
-
 send_image "$f"
diff --git a/modules/by-name/lf/lf/ctpv/prev/image/svg+xml/svg.sh b/modules/by-name/lf/lf/ctpv/prev/image/svg+xml/svg.sh
index 04a06f56..ce588ada 100644
--- a/modules/by-name/lf/lf/ctpv/prev/image/svg+xml/svg.sh
+++ b/modules/by-name/lf/lf/ctpv/prev/image/svg+xml/svg.sh
@@ -1,15 +1,10 @@
 #! /usr/bin/env dash
 
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
-
 # shellcheck disable=SC2269
 f="$f"
 # shellcheck disable=SC2269
 cache_f="$cache_f"
 
-. %HELPERS
-
 svg() {
     magick "$f" "jpg:$cache_f"
 }
diff --git a/modules/by-name/lf/lf/ctpv/prev/image/x-xcf/xcf.sh b/modules/by-name/lf/lf/ctpv/prev/image/x-xcf/xcf.sh
index 1603e337..abb83a89 100644
--- a/modules/by-name/lf/lf/ctpv/prev/image/x-xcf/xcf.sh
+++ b/modules/by-name/lf/lf/ctpv/prev/image/x-xcf/xcf.sh
@@ -1,15 +1,10 @@
 #! /usr/bin/env dash
 
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
-
 # shellcheck disable=SC2269
 f="$f"
 # shellcheck disable=SC2269
 cache_f="$cache_f"
 
-. %HELPERS
-
 xcf() {
     # TODO: Add this (currently it fails, as gimp lacks the `python-fu` evaluator) <2024-11-25>
     true
diff --git a/modules/by-name/lf/lf/ctpv/prev/inode/ls.sh b/modules/by-name/lf/lf/ctpv/prev/inode/ls.sh
index f73bd1c2..f5b95d13 100644
--- a/modules/by-name/lf/lf/ctpv/prev/inode/ls.sh
+++ b/modules/by-name/lf/lf/ctpv/prev/inode/ls.sh
@@ -1,8 +1,5 @@
 #! /usr/bin/env dash
 
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
-
 # shellcheck disable=SC2269
 f="$f"
 # shellcheck disable=SC2269
@@ -10,6 +7,4 @@ cache_d="$cache_d"
 # shellcheck disable=SC2269
 cache_f="$cache_f"
 
-. %HELPERS
-
 ls --color --group-directories-first -- "$f"
diff --git a/modules/by-name/lf/lf/ctpv/prev/inode/symlink.sh b/modules/by-name/lf/lf/ctpv/prev/inode/symlink.sh
index b30957d0..fb0dea8f 100644
--- a/modules/by-name/lf/lf/ctpv/prev/inode/symlink.sh
+++ b/modules/by-name/lf/lf/ctpv/prev/inode/symlink.sh
@@ -1,13 +1,8 @@
 #! /usr/bin/env dash
 
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
-
 # shellcheck disable=SC2269
 f="$f"
 
-. %HELPERS
-
 #
 # do nothing because in src/ctpv.c some kind of a "preview"
 # is already printed
diff --git a/modules/by-name/lf/lf/ctpv/prev/libreoffice.sh b/modules/by-name/lf/lf/ctpv/prev/libreoffice.sh
index ec57da0b..9407aade 100644
--- a/modules/by-name/lf/lf/ctpv/prev/libreoffice.sh
+++ b/modules/by-name/lf/lf/ctpv/prev/libreoffice.sh
@@ -1,8 +1,5 @@
 #! /usr/bin/env dash
 
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
-
 # shellcheck disable=SC2269
 f="$f"
 # shellcheck disable=SC2269
@@ -10,8 +7,6 @@ cache_d="$cache_d"
 # shellcheck disable=SC2269
 cache_f="$cache_f"
 
-. %HELPERS
-
 doc() {
     # File produced by libreoffice
     jpg="$(printf '%s\n' "$f" | sed 's|^.*/||; s|\..*$||')"
diff --git a/modules/by-name/lf/lf/ctpv/prev/text/bat.sh b/modules/by-name/lf/lf/ctpv/prev/text/bat.sh
index be952aea..a466c9c7 100644
--- a/modules/by-name/lf/lf/ctpv/prev/text/bat.sh
+++ b/modules/by-name/lf/lf/ctpv/prev/text/bat.sh
@@ -1,13 +1,8 @@
 #! /usr/bin/env dash
 
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
-
 # shellcheck disable=SC2269
 f="$f"
 # shellcheck disable=SC2269
 w="$w"
 
-. %HELPERS
-
 preview_bat "$f"
diff --git a/modules/by-name/lf/lf/ctpv/prev/text/diff/delta.sh b/modules/by-name/lf/lf/ctpv/prev/text/diff/delta.sh
index 6a4e9a4e..3f8b5631 100644
--- a/modules/by-name/lf/lf/ctpv/prev/text/diff/delta.sh
+++ b/modules/by-name/lf/lf/ctpv/prev/text/diff/delta.sh
@@ -1,11 +1,6 @@
 #! /usr/bin/env dash
 
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
-
 # shellcheck disable=SC2269
 f="$f"
 
-. %HELPERS
-
 delta <"$f"
diff --git a/modules/by-name/lf/lf/ctpv/prev/text/glow.sh b/modules/by-name/lf/lf/ctpv/prev/text/glow.sh
index 301fe675..30f2af78 100644
--- a/modules/by-name/lf/lf/ctpv/prev/text/glow.sh
+++ b/modules/by-name/lf/lf/ctpv/prev/text/glow.sh
@@ -1,15 +1,10 @@
 #! /usr/bin/env dash
 
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
-
 # shellcheck disable=SC2269
 f="$f"
 # shellcheck disable=SC2269
 w="$w"
 
-. %HELPERS
-
 # Specify the style, to force `glow` to output colors.
 # tracking issue: https://github.com/charmbracelet/glow/issues/654
 # We can't use `hide_script_env` because of some bespoke reason. (It just forces glow to
diff --git a/modules/by-name/lf/lf/ctpv/prev/text/html/default.nix b/modules/by-name/lf/lf/ctpv/prev/text/html/default.nix
deleted file mode 100644
index 2a7a9a9f..00000000
--- a/modules/by-name/lf/lf/ctpv/prev/text/html/default.nix
+++ /dev/null
@@ -1,13 +0,0 @@
-{pkgs, ...}: {
-  # TODO: I might want to use lynx/w3m instead <2024-11-24>
-  soispha.programs.lf.ctpv.previewers = {
-    elinks = {
-      previewer = ./elinks.sh;
-      priority = 1;
-      matches.mime = ["text/html"];
-      dependencies = [
-        pkgs.elinks
-      ];
-    };
-  };
-}
diff --git a/modules/by-name/lf/lf/ctpv/prev/text/html/elinks.sh b/modules/by-name/lf/lf/ctpv/prev/text/html/elinks.sh
deleted file mode 100644
index ca0de22e..00000000
--- a/modules/by-name/lf/lf/ctpv/prev/text/html/elinks.sh
+++ /dev/null
@@ -1,18 +0,0 @@
-#! /usr/bin/env dash
-
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
-
-# shellcheck disable=SC2269
-f="$f"
-# shellcheck disable=SC2269
-w="$w"
-
-. %HELPERS
-
-elinks \
-    -dump 1 -dump-width "$w" \
-    -no-references -no-numbering <"$f"
-
-# lynx -dump -nonumbers -nolist -width="$w" -- "$f"
-# w3m -dump "$f"
diff --git a/modules/by-name/lf/lf/ctpv/prev/text/json/jq.sh b/modules/by-name/lf/lf/ctpv/prev/text/json/jq.sh
index bf807d1d..c7090ccb 100644
--- a/modules/by-name/lf/lf/ctpv/prev/text/json/jq.sh
+++ b/modules/by-name/lf/lf/ctpv/prev/text/json/jq.sh
@@ -1,11 +1,6 @@
 #! /usr/bin/env dash
 
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
-
 # shellcheck disable=SC2269
 f="$f"
 
-. %HELPERS
-
 jq --color-output . <"$f"
diff --git a/modules/by-name/lf/lf/ctpv/prev/video/video.sh b/modules/by-name/lf/lf/ctpv/prev/video/video.sh
index e42e3612..d1972187 100644
--- a/modules/by-name/lf/lf/ctpv/prev/video/video.sh
+++ b/modules/by-name/lf/lf/ctpv/prev/video/video.sh
@@ -1,15 +1,10 @@
 #! /usr/bin/env dash
 
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
-
 # shellcheck disable=SC2269
 f="$f"
 # shellcheck disable=SC2269
 cache_f="$cache_f"
 
-. %HELPERS
-
 video() {
     ffmpegthumbnailer -i "$f" -o "$cache_f" -s 0 -t 50% 2>/dev/null
 }
diff --git a/modules/by-name/lf/lf/module.nix b/modules/by-name/lf/lf/module.nix
index 6dc8e919..ae1534d0 100644
--- a/modules/by-name/lf/lf/module.nix
+++ b/modules/by-name/lf/lf/module.nix
@@ -75,7 +75,7 @@ in {
           icons = true;
           ifs = "\\n"; # internal field separator for shell commands
           #info = "size"; # show the size of a directory
-          shell = "sh";
+          shell = "${lib.getExe pkgs.dash}";
           shellopts = "-eu"; # e: exit on error; u: error for unset variables
         };
         extraConfig = ''
diff --git a/modules/by-name/mp/mpd/mpc.nix b/modules/by-name/mp/mpd/mpc.nix
index 031465fe..b1398b77 100644
--- a/modules/by-name/mp/mpd/mpc.nix
+++ b/modules/by-name/mp/mpd/mpc.nix
@@ -5,7 +5,6 @@
   ...
 }: let
   cfg = config.soispha.services.mpd.mpc;
-  parentCfg = config.soispha.services.mpd;
 in {
   options.soispha.services.mpd.mpc = {
     enable = lib.mkEnableOption "mpc with extensions";
@@ -29,9 +28,7 @@ in {
         beets = cfg.beetsPkg;
       })
       # Displays the lyrics of the currently playing song
-      (pkgs.mpp-lyrics.override {
-        mpd_music_dir = parentCfg.directories.music;
-      })
+      pkgs.mpp-lyrics
     ];
   };
 }
diff --git a/modules/by-name/nv/nvim/plgs/harpoon/default.nix b/modules/by-name/nv/nvim/plgs/harpoon/default.nix
index 05a40d9f..3760ce15 100644
--- a/modules/by-name/nv/nvim/plgs/harpoon/default.nix
+++ b/modules/by-name/nv/nvim/plgs/harpoon/default.nix
@@ -1,100 +1,44 @@
 {
-  pkgs,
-  config,
   lib,
+  config,
   ...
 }: let
-  numbers = ["0" "1" "2" "3" "4" "5" "6" "7" "8" "9"];
-  mkNumberedCommand = {
-    command_template,
-    prefix,
-    number,
-    desc_template,
-  }: {
-    key = "${prefix}${number}";
-    action.__raw = ''
-      function()
-        ${command_template number}
-      end
-    '';
-    options.desc = "${desc_template number}";
-  };
-  mkGotoTerminalCommand = number: let
-    desc_template = number: "Goto terminal number ${number}";
-    command_template = number: ''require("harpoon.term").gotoTerminal(${number})'';
-    prefix = "gt";
-  in
-    mkNumberedCommand {inherit desc_template command_template prefix number;};
-  mkGotoFileCommand = number: let
-    desc_template = number: "Goto Buffer number ${number}";
-    command_template = number: ''require("harpoon.ui").nav_file(${number})'';
-    prefix = "gf";
-  in
-    mkNumberedCommand {inherit desc_template command_template prefix number;};
-
-  gotoTerminalMappings = builtins.map mkGotoTerminalCommand numbers;
-  gotoFileMappings = builtins.map mkGotoFileCommand numbers;
   cfg = config.soispha.programs.nvim;
 in {
   home-manager.users.soispha.programs.nixvim = lib.mkIf cfg.enable {
-    plugins.harpoon = {
-      enable = true;
-      package = pkgs.vimPlugins.harpoon;
-      enableTelescope = true;
-      # menu.width = "vim.api.nvim_win_get_width(0) - 4"; # TODO: integrate that
-      keymaps = {
-        tmuxGotoTerminal = null; # TODO:
-      };
-    };
+    plugins.harpoon.enable = true;
+
     keymaps =
-      [
-        {
-          key = "-";
-          action.__raw = ''
+      lib.mapAttrsToList
+      (key: action: {
+        mode = "n";
+        inherit key;
+        action.__raw = builtins.elemAt action 0;
+        options.silent = true;
+        options.desc = builtins.elemAt action 1;
+      })
+      {
+        # add current file
+        "<leader><leader>" = [
+          # lua
+          ''
             function()
-              require("harpoon.ui").nav_next()
-             end
-          '';
-          options.desc = "go to the next marked file";
-        }
-        {
-          key = "_";
-          action.__raw = ''
-            function()
-              require("harpoon.ui").nav_prev()
-             end
-          '';
-          options.desc = "go to the previous marked file";
-        }
-        {
-          key = "<leader><leader>";
-          action.__raw = ''
-            function()
-              require("harpoon.mark").add_file()
-            end
-          '';
-          options.desc = "add a mark to the open file in harpoon.";
-        }
-        {
-          key = "gqc";
-          action.__raw = ''
-            function()
-              require("harpoon.cmd-ui").toggle_quick_menu()
+              require("harpoon"):list():add()
             end
-          '';
-          options.desc = "toggle the harpoon command quick menu to see all commands.";
-        }
-        {
-          key = "<leader>q";
-          action.__raw = ''
+          ''
+          "Add a mark to the open file in harpoon."
+        ];
+
+        # open menu
+        "<leader>q" = [
+          # lua
+          ''
             function()
-              require("harpoon.ui").toggle_quick_menu()
+                require("harpoon").ui:toggle_quick_menu(require("harpoon"):list())
             end
-          '';
-          options.desc = "toggle the harpoon normal quick menu to see all marks.";
-        }
-      ]
-      ++ gotoFileMappings
-      ++ gotoTerminalMappings;
+          ''
+          "Toggle the harpoon normal quick menu to see all marks."
+        ];
+      };
   };
 }
diff --git a/modules/by-name/nv/nvim/plgs/lf-nvim/default.nix b/modules/by-name/nv/nvim/plgs/lf-nvim/default.nix
index 1e7c91e3..6c363ee1 100644
--- a/modules/by-name/nv/nvim/plgs/lf-nvim/default.nix
+++ b/modules/by-name/nv/nvim/plgs/lf-nvim/default.nix
@@ -2,22 +2,18 @@
   pkgs,
   lib,
   config,
-  nixpkgs_open_prs,
-  system,
   ...
 }: let
   cfg = config.soispha.programs.nvim;
 in {
+  # TODO: package lf-nvim though a module
+  # TODO: change the nvim path, when I change the path with lf
   home-manager.users.soispha.programs.nixvim = lib.mkIf cfg.enable {
-    # TODO: package lf-nvim though a module
-    # FIXME: change the nvim path, when I change the path with lf
     extraConfigLuaPost = ''
       ${lib.strings.fileContents ./lua/lf-nvim.lua}
     '';
     extraPlugins = [
-      nixpkgs_open_prs.nixpkgs-lf.legacyPackages."${system}".vimPlugins.lf-nvim
-
-      pkgs.vimPlugins.toggleterm-nvim # required by lf-nvim
+      pkgs.vimPlugins.lf-nvim
     ];
   };
 }
diff --git a/modules/by-name/nv/nvim/plgs/telescope/extensions/bibtex/default.nix b/modules/by-name/nv/nvim/plgs/telescope/extensions/bibtex/default.nix
index 4cab0258..8eee9a27 100644
--- a/modules/by-name/nv/nvim/plgs/telescope/extensions/bibtex/default.nix
+++ b/modules/by-name/nv/nvim/plgs/telescope/extensions/bibtex/default.nix
@@ -1,7 +1,4 @@
-{
-  config,
-  ...
-}: let
+{config, ...}: let
   cfg = config.soispha.programs.nvim;
 in {
   # TODO: Re-enable this, once the plugin is merged into nixpkgs <2025-03-29>
diff --git a/modules/by-name/ta/taskwarrior/module.nix b/modules/by-name/ta/taskwarrior/module.nix
index 3d53706c..2c1f91c2 100644
--- a/modules/by-name/ta/taskwarrior/module.nix
+++ b/modules/by-name/ta/taskwarrior/module.nix
@@ -23,19 +23,24 @@
 
     executable = pkgs.writeShellApplication {
       name = "add-hook-${builtins.baseNameOf path}";
-      runtimeInputs = [pkgs.taskwarrior pkgs.coreutils] ++ deps;
+      runtimeInputs = [pkgs.taskwarrior3 pkgs.coreutils pkgs.gnugrep] ++ deps;
       inheritPath = false;
       text =
         # bash
         ''
           die() {
-            echo "$@"
+            echo "$@">&2
             exit 1
           }
 
           enable_hook_dbg() {
-              debug_hooks="$(task _get rc.debug.hooks)"
-              [ "$debug_hooks" ] && [ "$debug_hooks" -ge 1 ] && set -x
+              # TODO: We should probably be smarter with the debug detection <2025-04-04>
+              if echo "$2" | grep --quiet 'rc.debug.hooks='; then
+                set -x
+                mkdir --parents "$HOME/.cache/task"
+                exec >>"$HOME/.cache/task/hook.log.$1"
+                exec 2>>"$HOME/.cache/task/hook.log.$1"
+              fi
           }
 
           addedCall() {
@@ -51,7 +56,7 @@
           # We don't change the task, thus immediately return the JSON
           echo "$new_task"
 
-          enable_hook_dbg
+          enable_hook_dbg "$@"
           addedCall "$new_task" "$old_task"
 
           exit 0
@@ -91,17 +96,19 @@ in {
 
   config = {
     lib.taskwarrior = {
-      mkHook = mkHook;
+      inherit mkHook;
     };
 
     home-manager.users.soispha = lib.mkIf cfg.enable {
       services.taskwarrior-sync = {
         enable = true;
+        package = pkgs.taskwarrior3;
       };
 
       programs.taskwarrior = {
         enable = true;
         colorTheme = ./nord.theme;
+        package = pkgs.taskwarrior3;
         extraConfig = cfg.includeFiles;
 
         config = {
@@ -111,6 +118,8 @@ in {
             tags = true;
           };
 
+          news.version = "3.4.1";
+
           regex = true;
           weekstart = "Monday";
 
diff --git a/modules/by-name/ti/timewarrior/module.nix b/modules/by-name/ti/timewarrior/module.nix
index d6b4dc32..f33d02be 100644
--- a/modules/by-name/ti/timewarrior/module.nix
+++ b/modules/by-name/ti/timewarrior/module.nix
@@ -7,49 +7,41 @@
   cfg = config.soispha.programs.timewarrior;
 
   track_timewarrior = pkgs.stdenv.mkDerivation {
-    name = "track_timewarrior.taskwarrior-hook";
+    name = "track-timewarrior";
     nativeBuildInputs = [
       pkgs.makeWrapper
     ];
     buildInputs = [
       pkgs.timewarrior
-      pkgs.taskwarrior
-      # TODO: Use a `taskw` package, that actually supports newer python variants <2024-07-13>
-      (pkgs.python311.withPackages (pythonPackages:
-        with pythonPackages; [
-          taskw
-        ]))
+      pkgs.taskwarrior3
+      pkgs.python3
     ];
     dontUnpack = true;
     installPhase = ''
-      install -Dm755 ${./taskwarirror_hooks/on-modify_track-timewarrior.py} $out/bin/bin
-      wrapProgram $out/bin/bin \
-      --prefix PATH : ${lib.makeBinPath [pkgs.taskwarrior pkgs.timewarrior]}
+      install -Dm755 ${./taskwarrior_hooks/on-modify.track-timewarrior.py} $out/bin/track-timewarrior
+      wrapProgram $out/bin/track-timewarrior \
+      --set PATH ${lib.makeBinPath [pkgs.taskwarrior3 pkgs.timewarrior]}
     '';
 
-    meta.mainProgram = "bin";
+    meta.mainProgram = "track-timewarrior";
   };
   track_total_active_time = pkgs.stdenv.mkDerivation {
-    name = "track_total_active_time.taskwarrior-hook";
+    name = "track-total-active-time";
     nativeBuildInputs = [
       pkgs.makeWrapper
     ];
     buildInputs = [
-      pkgs.taskwarrior
-      # TODO: Use a `taskw` package, that actually supports newer python variants <2024-07-13>
-      (pkgs.python311.withPackages (pythonPackages:
-        with pythonPackages; [
-          taskw
-        ]))
+      pkgs.taskwarrior3
+      pkgs.python3
     ];
     dontUnpack = true;
     installPhase = ''
-      install -Dm755 ${./taskwarirror_hooks/on-modify_track-total-active-time.py} $out/bin/bin
-      wrapProgram $out/bin/bin \
-      --prefix PATH : ${lib.makeBinPath [pkgs.taskwarrior]}
+      install -Dm755 ${./taskwarrior_hooks/on-modify.track-total-active-time.py} $out/bin/track-total-active-time
+      wrapProgram $out/bin/track-total-active-time \
+      --set PATH ${lib.makeBinPath [pkgs.taskwarrior3]}
     '';
 
-    meta.mainProgram = "bin";
+    meta.mainProgram = "track-total-active-time";
   };
 in {
   options.soispha.programs.timewarrior = {
diff --git a/modules/by-name/ti/timewarrior/taskwarirror_hooks/on-modify_track-timewarrior.py b/modules/by-name/ti/timewarrior/taskwarirror_hooks/on-modify_track-timewarrior.py
deleted file mode 100755
index b482af6a..00000000
--- a/modules/by-name/ti/timewarrior/taskwarirror_hooks/on-modify_track-timewarrior.py
+++ /dev/null
@@ -1,94 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-# Copyright (C) 2016-present Arctic Ice Studio <development@arcticicestudio.com>
-# Copyright (C) 2016-present Sven Greb <development@svengreb.de>
-
-# Project:    igloo
-# Repository: https://github.com/arcticicestudio/igloo
-# License:    MIT
-# References:
-#   https://taskwarrior.org/docs
-#   https://taskwarrior.org/docs/timewarrior
-#   timew(1)
-#   task(1)
-
-"""A Taskwarrior hook to track the time of a active task with Taskwarrior.
-
-This hook will extract all of the following for use as Timewarrior tags:
-
-* UUID
-* Project
-* Tags
-* Description
-* UDAs
-
-Note:
-    This hook requires Python 3 and is only compatible with Taskwarrior version greater or equal to 2.4!
-
-This hook is a fork from the `official on-modify.timewarrior hook`_.
-
-.. _`official on-modify.timewarrior hook`:
-   https://github.com/GothenburgBitFactory/timewarrior/blob/dev/ext/on-modify.timewarrior
-"""
-
-import subprocess
-import sys
-from json import loads, dumps
-from os import system
-from sys import stdin
-from taskw import TaskWarrior
-
-# Make no changes to the task, simply observe.
-old = loads(stdin.readline())
-new = loads(stdin.readline())
-print(dumps(new))
-
-
-w = TaskWarrior(config_filename=sys.argv[4].replace("rc:", ""))
-config = w.load_config(config_filename=sys.argv[4].replace("rc:", ""))
-if "max_active_tasks" in config:
-    MAX_ACTIVE = int(config["max_active_tasks"])
-else:
-    MAX_ACTIVE = 1
-
-
-# Extract attributes for use as tags.
-tags = [new["description"]]
-
-if "project" in new:
-    project = new["project"]
-    tags.append(project)
-    if "." in project:
-        tags.extend([tag for tag in project.split(".")])
-
-if "tags" in new:
-    tags.extend(new["tags"])
-
-combined = " ".join(["'%s'" % tag for tag in tags]).encode("utf-8").strip()
-
-# Task has been started.
-if "start" in new and "start" not in old:
-    # Prevent this task from starting if "task +ACTIVE count" is greater than "MAX_ACTIVE".
-    p = subprocess.Popen(
-        ["task", "+ACTIVE", "status:pending", "count", "rc.verbose:off"],
-        stdout=subprocess.PIPE,
-    )
-    out, err = p.communicate()
-    count = int(out.rstrip())
-    if count >= MAX_ACTIVE:
-        print(
-            "Only %d task(s) can be active at a time. "
-            "See 'max_active_tasks' in .taskrc." % MAX_ACTIVE
-        )
-        sys.exit(1)
-
-    system("timew start " + combined.decode() + " :yes")
-
-# Task has been stopped.
-elif "start" not in new and "start" in old:
-    system("timew stop " + combined.decode() + " :yes")
-
-# Any task that is active, with a non-pending status should not be tracked.
-elif "start" in new and new["status"] != "pending":
-    system("timew stop " + combined.decode() + " :yes")
diff --git a/modules/by-name/ti/timewarrior/taskwarrior_hooks/on-modify.track-timewarrior.py b/modules/by-name/ti/timewarrior/taskwarrior_hooks/on-modify.track-timewarrior.py
new file mode 100755
index 00000000..0bef8bc2
--- /dev/null
+++ b/modules/by-name/ti/timewarrior/taskwarrior_hooks/on-modify.track-timewarrior.py
@@ -0,0 +1,124 @@
+#!/usr/bin/env python3
+
+###############################################################################
+#
+# Copyright 2016 - 2021, 2023, Gothenburg Bit Factory
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+# https://www.opensource.org/licenses/mit-license.php
+#
+###############################################################################
+
+import json
+import subprocess
+import sys
+
+# Hook should extract all the following for use as Timewarrior tags:
+#   UUID
+#   Project
+#   Tags
+#   Description
+#   UDAs
+
+try:
+    input_stream = sys.stdin.buffer
+except AttributeError:
+    input_stream = sys.stdin
+
+
+MAX_ACTIVE = 1
+
+
+def extract_tags_from(json_obj) -> [str]:
+    # Extract attributes for use as tags.
+    tags = [json_obj["description"]]
+
+    if "project" in json_obj:
+        tags.append(json_obj["project"])
+
+    if "tags" in json_obj:
+        if type(json_obj["tags"]) is str:
+            # Usage of tasklib (e.g. in taskpirate) converts the tag list into a string
+            # If this is the case, convert it back into a list first
+            # See https://github.com/tbabej/taskpirate/issues/11
+            tags.extend(json_obj["tags"].split(","))
+        else:
+            tags.extend(json_obj["tags"])
+
+    return tags
+
+
+def extract_annotation_from(json_obj):
+    if "annotations" not in json_obj:
+        return "''"
+
+    return json_obj["annotations"][0]["description"]
+
+
+def main(old, new):
+    start_or_stop = ""
+
+    # Started task.
+    if "start" in new and "start" not in old:
+        # Prevent this task from starting if "task +ACTIVE count" is greater than "MAX_ACTIVE".
+        p = subprocess.Popen(
+            ["task", "+ACTIVE", "status:pending", "count", "rc.verbose:off"],
+            stdout=subprocess.PIPE,
+        )
+        out, err = p.communicate()
+        count = int(out.rstrip())
+        if count >= MAX_ACTIVE:
+            print(
+                f"Only {MAX_ACTIVE} task(s) can be active at a time.",
+            )
+            sys.exit(1)
+        else:
+            start_or_stop = "start"
+
+    # Stopped task.
+    elif ("start" not in new or "end" in new) and "start" in old:
+        start_or_stop = "stop"
+
+    if start_or_stop:
+        tags = extract_tags_from(new)
+
+        subprocess.call(["timew", start_or_stop] + tags + [":yes"])
+
+    # Modifications to task other than start/stop
+    elif "start" in new and "start" in old:
+        old_tags = extract_tags_from(old)
+        new_tags = extract_tags_from(new)
+
+        if old_tags != new_tags:
+            subprocess.call(["timew", "untag", "@1"] + old_tags + [":yes"])
+            subprocess.call(["timew", "tag", "@1"] + new_tags + [":yes"])
+
+        old_annotation = extract_annotation_from(old)
+        new_annotation = extract_annotation_from(new)
+
+        if old_annotation != new_annotation:
+            subprocess.call(["timew", "annotate", "@1", new_annotation])
+
+
+if __name__ == "__main__":
+    old = json.loads(input_stream.readline().decode("utf-8", errors="replace"))
+    new = json.loads(input_stream.readline().decode("utf-8", errors="replace"))
+    print(json.dumps(new))
+    main(old, new)
diff --git a/modules/by-name/ti/timewarrior/taskwarirror_hooks/on-modify_track-total-active-time.py b/modules/by-name/ti/timewarrior/taskwarrior_hooks/on-modify.track-total-active-time.py
index d5b380d0..0b6be082 100755
--- a/modules/by-name/ti/timewarrior/taskwarirror_hooks/on-modify_track-total-active-time.py
+++ b/modules/by-name/ti/timewarrior/taskwarrior_hooks/on-modify.track-total-active-time.py
@@ -20,37 +20,24 @@ By default, this plugin allows to have one task active at a time. This can be ch
 ``1``.
 
 Note:
-    This hook requires Python 3 and the `taskw`_ package to be installed which provides the python bindings for Taskwarrior!
-    Also note that this hook is only compatible with Taskwarrior version greater or equal to 2.4!
+    Note that this hook is only compatible with Taskwarrior version greater or equal to 2.4!
 
 This hook is a fork from `kostajh/taskwarrior-time-tracking-hook`_
 
-.. _taskw:
-   https://pypi.python.org/pypi/taskw
 .. _kostajh/taskwarrior-time-tracking-hook:
    https://github.com/kostajh/taskwarrior-time-tracking-hook
 """
 
 import datetime
 import json
-import re
 import sys
 import subprocess
-from taskw import TaskWarrior
 from typing import TypeVar
 
 TIME_FORMAT = "%Y%m%dT%H%M%SZ"
 UDA_KEY = "total_active_time"
 
-w = TaskWarrior(config_filename=sys.argv[4].replace("rc:", ""))
-config = w.load_config(config_filename=sys.argv[4].replace("rc:", ""))
-if "max_active_tasks" in config:
-    MAX_ACTIVE = int(config["max_active_tasks"])
-else:
-    MAX_ACTIVE = 1
-
-"""Compiled regular expression for the duration as ISO-8601 formatted string."""
-ISO8601DURATION = re.compile("P((\d*)Y)?((\d*)M)?((\d*)D)?T((\d*)H)?((\d*)M)?((\d*)S)?")
+MAX_ACTIVE = 1
 
 """The duration type either as integer (in seconds), as ISO-8601 formatted string ("PT1H10M31S") or the seconds suffixed with "seconds"."""
 DurationType = TypeVar("DurationType", str, int)
@@ -63,31 +50,7 @@ def duration_str_to_time_delta(duration_str: DurationType) -> datetime.timedelta
     :return: The duration as timedelta object
     """
     if duration_str.startswith("P"):
-        match = ISO8601DURATION.match(duration_str)
-        if match:
-            year = match.group(2)
-            month = match.group(4)
-            day = match.group(6)
-            hour = match.group(8)
-            minute = match.group(10)
-            second = match.group(12)
-            value = 0
-            if second:
-                value += int(second)
-            if minute:
-                value += int(minute) * 60
-            if hour:
-                value += int(hour) * 3600
-            if day:
-                value += int(day) * 3600 * 24
-            if month:
-                # Assume a month is 30 days for now.
-                value += int(month) * 3600 * 24 * 30
-            if year:
-                # Assume a year is 365 days for now.
-                value += int(year) * 3600 * 24 * 365
-        else:
-            value = int(duration_str)
+        value = datetime.fromisoformat(duration_str)
     elif duration_str.endswith("seconds"):
         value = int(duration_str.rstrip("seconds"))
     else:
diff --git a/modules/by-name/ts/tskm/module.nix b/modules/by-name/ts/tskm/module.nix
index 75af4509..51be48fe 100644
--- a/modules/by-name/ts/tskm/module.nix
+++ b/modules/by-name/ts/tskm/module.nix
@@ -2,7 +2,6 @@
   lib,
   config,
   pkgs,
-  baseLib,
   ...
 }: let
   cfg = config.soispha.programs.tskm;
@@ -15,13 +14,11 @@
   in
     [name] ++ subprojects;
 
-  firefoxProfiles = builtins.listToAttrs (builtins.map (name:
+  firefoxProfiles = builtins.listToAttrs (lib.imap0 (index: name:
     lib.attrsets.nameValuePair name {
       inherit name;
-      # We use the hash-based function here, so that we can avoid an id change if a new
-      # profile is added (i.e., simply using it index.)
-      # TODO: However, I do not know what this id is for and if it would be bad if it changed? <2025-04-02>
-      id = baseLib.idFromString name;
+      # Add one here, so that we can have the default profile at id 0.
+      id = index + 1;
     })
   allProjectNames);
 
diff --git a/modules/by-name/wa/water-reminder/module.nix b/modules/by-name/wa/water-reminder/module.nix
new file mode 100644
index 00000000..39e63771
--- /dev/null
+++ b/modules/by-name/wa/water-reminder/module.nix
@@ -0,0 +1,57 @@
+{
+  config,
+  lib,
+  pkgs,
+  ...
+}: let
+  cfg = config.soispha.services.water-reminder;
+in {
+  options.soispha.services.water-reminder = {
+    enable = lib.mkEnableOption "periodic reminder for water intake";
+
+    frequency = lib.mkOption {
+      type = lib.types.str;
+      default = "*-*-* *:00/30:00"; # Every 30 minutes
+      description = ''
+        How often to remind. This value is passed to the systemd
+        timer configuration as the `OnCalendar` option. See
+        {manpage}`systemd.time(7)` for more information about the format.
+      '';
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    home-manager.users.soispha = {
+      systemd.user.services.water-reminder = {
+        Unit = {Description = "Water reminder";};
+        Service = {
+          CPUSchedulingPolicy = "idle";
+          IOSchedulingClass = "idle";
+          ExecStart = lib.getExe (
+            pkgs.writeShellApplication {
+              name = "water-reminder";
+
+              inheritPath = false;
+              runtimeInputs = [pkgs.libnotify];
+
+              text =
+                # bash
+                ''
+                  notify-send 'Seek fluid intake' 'Water intake required' --wait --expire-time=0 --urgency=critical
+                '';
+            }
+          );
+        };
+      };
+
+      systemd.user.timers.water-reminder = {
+        Unit = {Description = "periodic reminder for water intake";};
+        Timer = {
+          Unit = "water-reminder.service";
+          OnCalendar = cfg.frequency;
+        };
+        Install = {WantedBy = ["timers.target"];};
+      };
+    };
+  };
+}
diff --git a/modules/by-name/xd/xdg/module.nix b/modules/by-name/xd/xdg/module.nix
index 1202cd96..a7c77cd7 100644
--- a/modules/by-name/xd/xdg/module.nix
+++ b/modules/by-name/xd/xdg/module.nix
@@ -1,60 +1,119 @@
 {
   pkgs,
   lib,
+  config,
   ...
 }: let
-  cmd = pkgs.writeShellApplication {
-    name = "lf_wrapper";
+  lf-wrapper = pkgs.writeShellApplication {
+    name = "lf-wrapper";
 
     runtimeInputs = [pkgs.lf pkgs.alacritty];
     inheritPath = true;
 
-    text = builtins.readFile ./lf-wrapper.sh;
+    text = builtins.readFile ./scripts/lf-wrapper.sh;
+  };
+
+  url-handler = pkgs.writeShellApplication {
+    name = "url-handler";
+
+    runtimeInputs = [pkgs.rofi pkgs.libnotify pkgs.zathura pkgs.tskm];
+    inheritPath = false;
+
+    text = builtins.readFile ./scripts/url-handler.sh;
   };
 
   tfcConfigFile = (pkgs.formats.ini {}).generate "xdg-desktop-portal-termfilechooser.ini" {
     filechooser = {
       default_dir = "/tmp";
-      cmd = "${lib.getExe cmd}";
+      cmd = "${lib.getExe lf-wrapper}";
     };
   };
+
+  cfg = config.soispha.xdg;
 in {
-  services.dbus.enable = true;
-  xdg = {
-    portal = {
-      enable = true;
-      wlr = {
+  options.soispha.xdg = {
+    enable = lib.mkEnableOption "xdg";
+  };
+
+  config = lib.mkIf cfg.enable {
+    home-manager.users.soispha = {
+      xdg = {
+        configFile."xdg-desktop-portal-termfilechooser/config".source = tfcConfigFile;
+
+        desktopEntries = {
+          url-handler = {
+            name = "url-handler";
+            genericName = "Web Browser";
+            exec = "${lib.getExe url-handler} %u";
+            terminal = false;
+            categories = [
+              "Application"
+              "Network"
+              "WebBrowser"
+            ];
+            mimeType = [
+              "text/html"
+              "text/xml"
+              "x-scheme-handler/http"
+              "x-scheme-handler/https"
+              "x-scheme-handler/about"
+              "x-scheme-handler/unknown"
+            ];
+          };
+        };
+      };
+    };
+
+    services.dbus.enable = true;
+
+    xdg = {
+      mime = {
         enable = true;
+        defaultApplications = {
+          "application/pdf" = ["url-handler.desktop"];
+          "application/x-pdf" = ["url-handler.desktop"];
+
+          "text/html" = ["url-handler.desktop"];
+          "text/xml" = ["url-handler.desktop"];
+          "x-scheme-handler/http" = ["url-handler.desktop"];
+          "x-scheme-handler/https" = ["url-handler.desktop"];
+          "x-scheme-handler/about" = ["url-handler.desktop"];
+          "x-scheme-handler/unknown" = ["url-handler.desktop"];
+        };
       };
-      config = {
-        common = {
-          # NOTE: The next entry is supposedly needed for gtk based apps <2023-08-31>
-          default = ["wlr" "gtk"];
-          "org.freedesktop.impl.portal.FileChooser" = ["termfilechooser"];
+
+      portal = {
+        enable = true;
+        wlr = {
+          enable = true;
         };
+        config = {
+          common = {
+            # NOTE: The next entry is supposedly needed for gtk based apps <2023-08-31>
+            default = ["wlr" "gtk"];
+            "org.freedesktop.impl.portal.FileChooser" = ["termfilechooser"];
+          };
 
-        # TODO: Also activate, when on another wlr-based compositor <2023-11-25>
-        river = {
-          default = ["wlr" "gtk"];
-          "org.freedesktop.impl.portal.FileChooser" = ["termfilechooser"];
+          # TODO: Also activate, when on another wlr-based compositor <2023-11-25>
+          river = {
+            default = ["wlr" "gtk"];
+            "org.freedesktop.impl.portal.FileChooser" = ["termfilechooser"];
+          };
         };
+
+        extraPortals = [
+          pkgs.xdg-desktop-portal-gtk
+          pkgs.xdg-desktop-portal-wlr
+          pkgs.xdg-desktop-portal-termfilechooser
+        ];
       };
+    };
 
-      extraPortals = [
-        pkgs.xdg-desktop-portal-gtk
-        pkgs.xdg-desktop-portal-wlr
-        pkgs.xdg-desktop-portal-termfilechooser
+    systemd.user.services.xdg-desktop-portal-termfilechooser = {
+      serviceConfig.ExecStart = [
+        ""
+        "${pkgs.xdg-desktop-portal-termfilechooser}/libexec/xdg-desktop-portal-termfilechooser --loglevel=TRACE"
       ];
     };
   };
-
-  environment.etc."xdg/xdg-desktop-portal-termfilechooser/config".source = tfcConfigFile;
-
-  systemd.user.services.xdg-desktop-portal-termfilechooser = {
-    serviceConfig.ExecStart = [
-      ""
-      "${pkgs.xdg-desktop-portal-termfilechooser}/libexec/xdg-desktop-portal-termfilechooser --loglevel=TRACE"
-    ];
-  };
-  # TODO: mime = {};
 }
diff --git a/modules/by-name/xd/xdg/lf-wrapper.sh b/modules/by-name/xd/xdg/scripts/lf-wrapper.sh
index f85f7bac..f85f7bac 100755
--- a/modules/by-name/xd/xdg/lf-wrapper.sh
+++ b/modules/by-name/xd/xdg/scripts/lf-wrapper.sh
diff --git a/modules/home.legacy/conf/xdg/url_handler.sh b/modules/by-name/xd/xdg/scripts/url-handler.sh
index f15df384..d1c8277d 100755
--- a/modules/home.legacy/conf/xdg/url_handler.sh
+++ b/modules/by-name/xd/xdg/scripts/url-handler.sh
@@ -2,7 +2,7 @@
 
 project="$({
     tskm projects list
-    echo nvim zathura
+    printf "%s\n" nvim zathura
 } | rofi -sep "$(printf "\n")" -dmenu)"
 
 if [ "$project" = "nvim" ]; then
@@ -10,9 +10,10 @@ if [ "$project" = "nvim" ]; then
 elif [ "$project" = "zathura" ]; then
     zathura "$1"
 elif [ "$project" ]; then
-    firefox -P "$project" "$1"
+    tskm open project "$project" "$1"
 else
-    notify-send "(URL HANDLER) No project selected" && exit 1
+    notify-send "(URL HANDLER) No project selected"
+    exit 1
 fi
 
 # vim: ft=sh
diff --git a/modules/by-name/zs/zsh/module.nix b/modules/by-name/zs/zsh/module.nix
index b50e72ac..fd99031b 100644
--- a/modules/by-name/zs/zsh/module.nix
+++ b/modules/by-name/zs/zsh/module.nix
@@ -3,6 +3,7 @@
   lib,
   shell_library,
   system,
+  pkgs,
   ...
 }: let
   cfg = config.soispha.programs.zsh;
@@ -133,8 +134,8 @@ in {
         };
 
         shellAliases = {
-          ll = ". ll";
-          lm = ". lm";
+          ll = ". ${lib.getExe pkgs.ll}";
+          lm = ". ${lib.getExe pkgs.lm}";
         };
       };
     };
diff --git a/modules/common/default.nix b/modules/common/default.nix
index 48fdf241..1c00c710 100644
--- a/modules/common/default.nix
+++ b/modules/common/default.nix
@@ -29,6 +29,7 @@
     };
     polkit.enable = true;
     power.enable = true;
+    xdg.enable = true;
 
     services = {
       adb = {
@@ -56,6 +57,7 @@
       printing.enable = true;
       scanning.enable = true;
       snapper.enable = true;
+      water-reminder.enable = true;
       steam.enable = false;
       systemDiff.enable = true;
       unison = {
@@ -104,6 +106,7 @@
         shell = pkgs.zsh;
       };
       atuin.enable = true;
+      cargo.enable = true;
       direnv.enable = true;
       git.enable = true;
       imv.enable = true;
@@ -192,7 +195,7 @@
       };
       tskm = {
         enable = true;
-        projects = builtins.fromJSON (builtins.readFile ./projects.nix);
+        projects = builtins.fromJSON (builtins.readFile ./projects.json);
       };
       yambar.enable = true;
       yt.enable = true;
diff --git a/modules/home.legacy/conf/default.nix b/modules/home.legacy/conf/default.nix
index 5a10951c..767039c6 100644
--- a/modules/home.legacy/conf/default.nix
+++ b/modules/home.legacy/conf/default.nix
@@ -27,7 +27,5 @@
     ./starship
     ./swayidle
     ./tridactyl
-    ./xdg
-    ./ytcc
   ];
 }
diff --git a/modules/home.legacy/conf/mail/accounts/soispha.nix b/modules/home.legacy/conf/mail/accounts/soispha.nix
index 6e3e6228..11634ab3 100644
--- a/modules/home.legacy/conf/mail/accounts/soispha.nix
+++ b/modules/home.legacy/conf/mail/accounts/soispha.nix
@@ -33,11 +33,11 @@
   #   };
   # };
   smtp = {
-    host = "mail.foss-syndicate.org";
+    host = "mail.vhack.eu";
     port = 465;
   };
   imap = {
-    host = "mail.foss-syndicate.org";
+    host = "mail.vhack.eu";
     port = 993;
   };
   jmap = {
diff --git a/modules/home.legacy/conf/xdg/default.nix b/modules/home.legacy/conf/xdg/default.nix
deleted file mode 100644
index 9751d806..00000000
--- a/modules/home.legacy/conf/xdg/default.nix
+++ /dev/null
@@ -1,59 +0,0 @@
-{
-  pkgs,
-  lib,
-  ...
-}: let
-  url_handler = pkgs.writeShellApplication {
-    name = "url-handler";
-    text = builtins.readFile ./url_handler.sh;
-    inheritPath = false;
-    runtimeInputs = [
-      pkgs.rofi
-      pkgs.libnotify
-      pkgs.zathura
-      pkgs.tskm
-    ];
-  };
-in {
-  imports = [
-    ./xdg_vars.nix
-  ];
-
-  xdg = {
-    mimeApps = {
-      enable = true;
-      defaultApplications = {
-        "application/pdf" = ["url_handler.desktop"];
-        "application/x-pdf" = ["url_handler.desktop"];
-
-        "text/html" = ["url_handler.desktop"];
-        "text/xml" = ["url_handler.desktop"];
-        "x-scheme-handler/http" = ["url_handler.desktop"];
-        "x-scheme-handler/https" = ["url_handler.desktop"];
-        "x-scheme-handler/about" = ["url_handler.desktop"];
-        "x-scheme-handler/unknown" = ["url_handler.desktop"];
-      };
-    };
-    desktopEntries = {
-      url-handler = {
-        name = "url-handler";
-        genericName = "Web Browser";
-        exec = "${lib.getExe url_handler} %u";
-        terminal = false;
-        categories = [
-          "Application"
-          "Network"
-          "WebBrowser"
-        ];
-        mimeType = [
-          "text/html"
-          "text/xml"
-          "x-scheme-handler/http"
-          "x-scheme-handler/https"
-          "x-scheme-handler/about"
-          "x-scheme-handler/unknown"
-        ];
-      };
-    };
-  };
-}
diff --git a/modules/home.legacy/conf/xdg/xdg_vars.nix b/modules/home.legacy/conf/xdg/xdg_vars.nix
deleted file mode 100644
index aa2f30d4..00000000
--- a/modules/home.legacy/conf/xdg/xdg_vars.nix
+++ /dev/null
@@ -1,29 +0,0 @@
-{config, ...}: let
-  inherit (config.xdg) dataHome;
-in {
-  # FIXME: Move these options in relevant modules, that are connected to their software.
-  #        <2024-10-21>
-
-  # Variables that only have to be set because special applications fail to set reasonable
-  # defaults (mostly understandable because of backwards-compatibility, but yeah)
-  home.sessionVariables = {
-    CARGO_HOME = "${dataHome}/cargo";
-    GRADLE_USER_HOME = "${dataHome}/gradle";
-
-    #_JAVA_OPTIONS = lib.concatStringsSep " " [
-    #        ''-Djava.util.prefs.userRoot="${config.xdg.configHome}/java"''
-    #        ''-Djavafx.cachedir="${config.xdg.cacheHome}/openjfx"''
-    #      ];
-    #GOPATH = "${config.xdg.dataHome}/go";
-    #GTK2_RC_FILES = "${config.xdg.configHome}/gtk-2.0/gtkrc";
-    #RUSTUP_HOME = "${config.xdg.dataHome}/rustup";
-    #NPM_CONFIG_USERCONFIG = "${config.xdg.configHome}/npm/npmrc";
-    #NUGET_PACKAGES = "${config.xdg.cacheHome}/NuGetPackages";
-    #XAUTHORITY = "${config.xdg.stateHome}/Xauthority";
-    #COMPDUMPFILE = "${config.xdg.dataHome}/zsh/.zcompdump}";
-    #IPYTHONDIR = "${config.xdg.configHome}/ipython";
-    #PARALLEL_HOME = "${config.xdg.configHome}/parallel";
-    #STACK_XDG = "1";
-    #WINEPREFIX = "${config.xdg.dataHome}/wine";
-  };
-}
diff --git a/modules/home.legacy/conf/ytcc/default.nix b/modules/home.legacy/conf/ytcc/default.nix
deleted file mode 100644
index 87300ec1..00000000
--- a/modules/home.legacy/conf/ytcc/default.nix
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-  config,
-  pkgs,
-  ...
-}: {
-  xdg.configFile."ytcc/ytcc.conf".source = pkgs.substituteAll {
-    src = ./ytcc.conf;
-    download_dir = "${config.xdg.userDirs.download}/ytcc";
-    xdg_data_home = config.xdg.dataHome;
-  };
-}
diff --git a/modules/home.legacy/conf/ytcc/ytcc.conf b/modules/home.legacy/conf/ytcc/ytcc.conf
deleted file mode 100644
index 289843ad..00000000
--- a/modules/home.legacy/conf/ytcc/ytcc.conf
+++ /dev/null
@@ -1,37 +0,0 @@
-[ytcc]
-download_dir = @download_dir@
-mpv_flags = --really-quiet --ytdl --ytdl-format=bestvideo[height<=?1080]+bestaudio/best --speed=2.7
-download_subdirs = true
-order_by = playlists:asc, publish_date:desc
-video_attrs = id, title, publish_date, duration, playlists
-playlist_attrs = name, url, tags, reverse
-db_path = @xdg_data_home@/ytcc/ytcc.db
-date_format = %Y-%m-%d
-max_update_fail = 5
-max_update_backlog = 20
-age_limit = 0
-
-[tui]
-alphabet = sdfervghnuiojkl
-default_action = play_video
-
-[theme]
-prompt_download_audio = 2
-prompt_download_video = 4
-prompt_play_audio = 2
-prompt_play_video = 4
-prompt_mark_watched = 1
-table_alternate_background = 245
-plain_label_text = 244
-
-[youtube_dl]
-format = bestvideo[height<=?1080]+bestaudio/best
-output_template = %(title)s.%(ext)s
-ratelimit = 0
-retries = 0
-subtitles = off
-thumbnail = true
-skip_live_stream = true
-merge_output_format = mkv
-max_duration = 0
-restrict_filenames = false
diff --git a/modules/home.legacy/pkgs/default.nix b/modules/home.legacy/pkgs/default.nix
index 31942f0d..fd8b811a 100644
--- a/modules/home.legacy/pkgs/default.nix
+++ b/modules/home.legacy/pkgs/default.nix
@@ -85,7 +85,8 @@ with pkgs; let
 
     SystemUpdate = [
       fupdate # Generic update tool.
-      update-sys # System update tool (meant to slot into `fupdate`).
+      fupdate-sys # System update tool (meant to slot into `fupdate`).
+      fupdate-flake # Nix flake update tool (meant to slot into `fupdate`).
     ];
 
     FileListers = [
@@ -93,8 +94,6 @@ with pkgs; let
       fd # Simple, fast and user-friendly alternative to find
       ripgrep # A search tool that combines the usability of ag with the raw speed of grep
       file # Show information about a file
-      ll # Wrapper around `lf` to automatically change the path
-      lm # Wrapper around `ll` to automatically cd to the last accessed path
     ];
 
     Programming = {
diff --git a/pkgs/by-name/au/aumo/aumo.sh b/pkgs/by-name/au/aumo/aumo.sh
index 84d39deb..991f257c 100755
--- a/pkgs/by-name/au/aumo/aumo.sh
+++ b/pkgs/by-name/au/aumo/aumo.sh
@@ -1,28 +1,63 @@
 #! /usr/bin/env dash
 
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
+NAME="aumo"
+
+error() {
+    printf "\033[1;91m==> ERROR:\033[0m \033[1;93m%s\033[0m\n" "$*" >&2
+}
+
+die() {
+    error "$1"
+    exit "${2-1}"
+}
+
+usage() {
+    echo "Usage: $NAME mount|unmount"
+}
+
+get_mounted_labels() {
+    findmnt --output label --json | jq '.filesystems | map(.label) | sort | unique | map(select(. != null))'
+}
+get_unmounted_labels() {
+    first=true
+
+    find /dev/disk/by-label -printf "%P\n" | while read -r label; do
+        if ! get_mounted_labels | jq 'join("\n")' --raw-output | grep "$label" --quiet; then
+            if [ "$first" = "true" ]; then
+                first=false
+            else
+                printf "|"
+            fi
+            printf "%s" "$label"
+        fi
+    done
+}
 
 unmounting() {
-    disk_name="$(find /dev/disk/by-label -type l -printf "%P|" | rofi -sep "|" -dmenu -p "Select disk to mount")"
+    disk_name="$(get_mounted_labels | jq 'join("|")' --join-output | rofi -sep "|" -dmenu -p "Select disk to unmount")"
 
     udisksctl unmount --block-device "/dev/disk/by-label/$disk_name"
 }
 
 mounting() {
-    disk_name="$(find /dev/disk/by-label -type l -printf "%P|" | rofi -sep "|" -dmenu -p "Select disk to mount")"
+    disk_name="$(get_unmounted_labels | rofi -sep "|" -dmenu -p "Select disk to mount")"
 
     udisksctl mount --block-device "/dev/disk/by-label/$disk_name"
 }
 
-case "$1" in
+case "${1-unset}" in
 "mount")
     mounting
     ;;
 "unmount" | "umount")
     unmounting
     ;;
+"unset")
+    usage
+    die "You need to provide one argument."
+    ;;
 *)
-    die "Usage: $NAME mount|unmount"
+    usage
+    die "Unknown command: '$1'"
     ;;
 esac
diff --git a/pkgs/by-name/au/aumo/package.nix b/pkgs/by-name/au/aumo/package.nix
index 20054bb5..5ced60dc 100644
--- a/pkgs/by-name/au/aumo/package.nix
+++ b/pkgs/by-name/au/aumo/package.nix
@@ -1,17 +1,23 @@
 {
-  sysLib,
+  writeShellApplication,
+  # Dependencies
   udisks,
   findutils,
   rofi,
+  jq,
+  gnugrep,
+  util-linux,
 }:
-sysLib.writeShellScript {
+writeShellApplication {
   name = "aumo";
-  src = ./aumo.sh;
-  generateCompletions = false;
-  keepPath = false;
-  dependencies = [
+  text = builtins.readFile ./aumo.sh;
+  inheritPath = false;
+  runtimeInputs = [
     udisks
     findutils
     rofi
+    jq
+    gnugrep
+    util-linux # for findmnt
   ];
 }
diff --git a/pkgs/by-name/ba/battery/battery.sh b/pkgs/by-name/ba/battery/battery.sh
index e650ba5d..771a892a 100755
--- a/pkgs/by-name/ba/battery/battery.sh
+++ b/pkgs/by-name/ba/battery/battery.sh
@@ -1,8 +1,5 @@
 #!/usr/bin/env dash
 
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
-
 capacity="$(cat /sys/class/power_supply/BAT0/capacity)"
 status="$(cat /sys/class/power_supply/BAT0/status)"
 
diff --git a/pkgs/by-name/ba/battery/package.nix b/pkgs/by-name/ba/battery/package.nix
index 9c0e194b..71ab1b9f 100644
--- a/pkgs/by-name/ba/battery/package.nix
+++ b/pkgs/by-name/ba/battery/package.nix
@@ -1,9 +1,12 @@
-{sysLib}:
-sysLib.writeShellScript {
+{
+  writeShellApplication,
+
+  # Dependencies
+  coreutils,
+}:
+writeShellApplication {
   name = "battery";
-  src = ./battery.sh;
-  generateCompletions = false;
-  keepPath = false;
-  dependencies = [
-  ];
+  text = builtins.readFile ./battery.sh;
+  inheritPath = false;
+  runtimeInputs = [coreutils];
 }
diff --git a/pkgs/by-name/be/beetsExtraPlugins/xtractor.nix b/pkgs/by-name/be/beetsExtraPlugins/xtractor.nix
index ecbc10ce..17981cdb 100644
--- a/pkgs/by-name/be/beetsExtraPlugins/xtractor.nix
+++ b/pkgs/by-name/be/beetsExtraPlugins/xtractor.nix
@@ -3,11 +3,10 @@
   fetchFromGitHub,
   python3Packages,
   beets,
-}:
+}: {}
 # # NOTE: This fails to build now. It didn't work anyways. See
 # https://git.sr.ht/~johnhamelink/nix/tree/master/item/home/hosts/sun/beets/beets-plugin-xtractor.nix
 # for a possibly working version. <2025-03-29>
-
 # # FIXME: Find a way to update this derivation <2024-08-11>
 # let
 #   version = "0.4.2";
@@ -56,3 +55,4 @@
 #       license = lib.licenses.mit;
 #     };
 #   }
+
diff --git a/pkgs/by-name/br/brightness/brightness.sh b/pkgs/by-name/br/brightness/brightness.sh
index 887dbb1e..3d6b2335 100755
--- a/pkgs/by-name/br/brightness/brightness.sh
+++ b/pkgs/by-name/br/brightness/brightness.sh
@@ -1,24 +1,23 @@
-#!/usr/bin/env dash
+#!/usr/bin/env sh
 
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
+die() {
+    echo "ERROR: $1"
+    exit 1
+}
 
 help() {
     cat <<EOF
 This is a system brightness manager
 
 USAGE:
-    $NAME up [VALUE] | down [VALUE]
+    $NAME set VALUE
 
 OPTIONS:
     --help   | -h
                                 Output this help and exit.
 
-    --version   | -v
-                                Output the version and exit.
-
 COMMANDS:
-    set [VALUE]
+    set VALUE
                                 Set the brightness to the specified percentage.
 
 ARGUMENTS:
@@ -27,17 +26,14 @@ ARGUMENTS:
 EOF
 }
 
-BACKLIGHT="/sys/class/backlight/%BACKLIGHT_NAME"
+BACKLIGHT="/sys/class/backlight/$BACKLIGHT_NAME"
 
 brightness() {
     perc="$1"
 
-    max="$(cat $BACKLIGHT/max_brightness)"
-
+    max="$(cat "$BACKLIGHT/max_brightness")"
     new="$(echo | awk --assign=perc="$perc" '{printf (perc / 100)}')"
-
     output="$(echo | awk --assign=new="$new" --assign=max="$max" '{printf max * new}')"
-
     echo "$output" >"$BACKLIGHT/brightness"
 }
 
@@ -47,10 +43,6 @@ for arg in "$@"; do
         help
         exit 0
         ;;
-    "--version" | "-v")
-        version
-        exit 0
-        ;;
     esac
 done
 
diff --git a/pkgs/by-name/br/brightness/package.nix b/pkgs/by-name/br/brightness/package.nix
index c2e31a0c..7d9d2194 100644
--- a/pkgs/by-name/br/brightness/package.nix
+++ b/pkgs/by-name/br/brightness/package.nix
@@ -1,14 +1,20 @@
 {
-  sysLib,
+  writeShellApplication,
+  # Arguments
   backlightName ? "intel_backlight", # nixosConfig.soispha.laptop.backlight
+  # Dependencies
+  gawk,
+  coreutils,
 }:
-sysLib.writeShellScript {
+writeShellApplication {
   name = "brightness";
-  src = ./brightness.sh;
-  generateCompletions = true;
-  keepPath = false;
+  text = builtins.readFile ./brightness.sh;
+  inheritPath = false;
 
-  replacementStrings = {BACKLIGHT_NAME = backlightName;};
+  runtimeEnv = {BACKLIGHT_NAME = backlightName;};
 
-  dependencies = [];
+  runtimeInputs = [
+    gawk
+    coreutils
+  ];
 }
diff --git a/pkgs/by-name/co/con2pdf/con2pdf.sh b/pkgs/by-name/co/con2pdf/con2pdf.sh
index 27c9d092..e5d8ce37 100755
--- a/pkgs/by-name/co/con2pdf/con2pdf.sh
+++ b/pkgs/by-name/co/con2pdf/con2pdf.sh
@@ -1,19 +1,8 @@
 #! /usr/bin/env dash
 
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
-
-# needed for help() and version
-# shellcheck disable=2034
-AUTHORS="Soispha"
-# shellcheck disable=2034
-YEARS="2023"
-# shellcheck disable=2034
-VERSION="1.0.0"
-
-# NAME is from the wrapper
-# shellcheck disable=SC2269
-NAME="$NAME"
+# TODO(@bpeetz): This should probably be rewritten in rust. <2025-04-14>
+
+NAME="con2pdf"
 help() {
     cat <<EOF
 Scan images and turn them into a pdf.
diff --git a/pkgs/by-name/co/con2pdf/package.nix b/pkgs/by-name/co/con2pdf/package.nix
index 8eb994fd..df24872c 100644
--- a/pkgs/by-name/co/con2pdf/package.nix
+++ b/pkgs/by-name/co/con2pdf/package.nix
@@ -1,24 +1,25 @@
 {
-  sysLib,
+  writeShellApplication,
   writeText,
-  # dependencies
+  # Dependencies
   sane-backends,
   imagemagick,
   coreutils,
   fd,
 }:
-sysLib.writeShellScript {
+writeShellApplication {
   name = "con2pdf";
-  src = ./con2pdf.sh;
-  generateCompletions = true;
-  keepPath = false;
-  dependencies = [
+  text = builtins.readFile ./con2pdf.sh;
+  inheritPath = false;
+
+  runtimeInputs = [
     sane-backends
     imagemagick
     coreutils
     fd
   ];
-  replacementStrings = {
+
+  runtimeEnv = {
     DEVICE_FUNCTION =
       # This is here, because escaping the whole function, to use it in the shell script
       # directly just isn't possible
diff --git a/pkgs/by-name/fu/fupdate-flake/fupdate-flake.sh b/pkgs/by-name/fu/fupdate-flake/fupdate-flake.sh
new file mode 100755
index 00000000..dd475cf3
--- /dev/null
+++ b/pkgs/by-name/fu/fupdate-flake/fupdate-flake.sh
@@ -0,0 +1,182 @@
+#! /usr/bin/env sh
+
+UPDATE_SCRIPT_NAME="update.sh"
+
+info() {
+    echo "Info: $1"
+}
+dbg() {
+    [ "${DEBUG_ENABLE-unset}" != "unset" ] && echo "Debug: $1" >&2
+}
+die() {
+    echo "Error: $1"
+    exit 1
+}
+
+# Search for a file “upwards”.
+# This will return the relative path from "$1" to the found file.
+#
+# # Type
+# upfind :: Path -> String -> Path
+#
+# # Arguments
+# $1
+# : The directory to use as start of your search.
+#
+# $2
+# : The file to search for.
+#
+# # Example
+# upfind "/home/user1" "/usr"
+# => /usr
+upfind() {
+    starting_directory="$(readlink --canonicalize "$1")"
+    search_string="$2"
+
+    current_directory="$starting_directory"
+
+    while
+        search_result=$(fd "$search_string" "$current_directory/" --max-depth 1)
+        dbg "upfind - search in $current_directory gives: $search_result"
+        [ -z "$search_result" ] && [ "$current_directory" != "/" ]
+    do current_directory=$(dirname "$current_directory"); done
+
+    realpath --relative-to="$1" "$search_result"
+}
+
+# Construct the storage path for the update script allowed hashes.
+#
+# # Type
+# get_storage_path :: Path -> Path
+#
+# # Arguments
+# $1
+# : The path to the update script
+#
+# # Returns
+# The constructed storage path.
+get_storage_path() {
+    update_script="$(realpath "$1")"
+
+    storage_path="$XDG_DATA_HOME/fupdate-flake/$update_script"
+    echo "$storage_path"
+}
+
+# Checks if a given path to the update script is allowed.
+#
+# # Type
+# is_allowed :: Path -> bool
+#
+# # Arguments
+# $1
+# : The path to the update script to check.
+#
+# # Return exit code
+# 0
+# : If the update script is allowed
+#
+# 1
+# : If it is not.
+is_allowed() {
+    update_script="$(realpath "$1")"
+
+    storage_path="$(get_storage_path "$update_script")"
+
+    # Use this invocation, to also include the path to the `$update_script`
+    update_script_hash="$(sha256sum "$update_script")"
+
+    if [ -f "$storage_path" ]; then
+        if [ "$(cat "$storage_path")" = "$update_script_hash" ]; then
+            return 0
+        else
+            return 1
+        fi
+    else
+        return 1
+    fi
+}
+
+# Asks the user if they want to allow a given script.
+#
+# # Type
+# ask_to_allow_update_script :: Path
+#
+# # Arguments
+# $1
+# : The path to the update script to ask for.
+ask_to_allow_update_script() {
+    update_script="$(realpath "$1")"
+
+    printf "\033[2J" # clear the screen
+    cat "$update_script"
+
+    printf "Do you want to allow this script?[N/y]: "
+    read -r allow
+
+    case "$allow" in
+    [yY])
+        info "Update script allowed."
+
+        storage_path="$(get_storage_path "$update_script")"
+        update_script_hash="$(sha256sum "$update_script")"
+
+        mkdir --parents "$(dirname "$storage_path")"
+        printf "%s" "$update_script_hash" >"$storage_path"
+        ;;
+    *)
+        info "Update script not allowed."
+        ;;
+    esac
+}
+
+# Performs a full update.
+# This consists of running an update script.
+# Additionally, it also checks for duplicated inputs in a `flake.lock` file, if it exists.
+#
+# # Type
+# update :: Path -> Path -> [String]
+#
+# # Arguments
+# $1
+# : The path to the update script to execute.
+#
+# $2
+# : The base directory from which to start the update.
+#
+# $3
+# : Arguments to pass to the update script.
+update() {
+    update_script="$1"
+    base_directory="$2"
+    shift 2
+
+    cd "$base_directory" || die "The provided base directory '$base_directory' cannot be accessed"
+    dbg "Changed directory to: $base_directory"
+
+    dbg "Executing update script ('$update_script') following args: '$*'"
+    "$update_script" "$@"
+
+    if [ -f "flake.lock" ] && grep '[^0-9]_[0-9]' flake.lock --quiet; then
+        batgrep '[^0-9]_[0-9]' flake.lock
+        die "Your flake.nix contains duplicate inputs!"
+    fi
+}
+
+main() {
+    base_directory="$(git rev-parse --show-toplevel)"
+    update_script="$(upfind "$PWD" "$UPDATE_SCRIPT_NAME")"
+    dbg "update_script is: $update_script"
+
+    if [ "$update_script" = "" ]; then
+        die "Failed to find update script."
+    elif is_allowed "$update_script"; then
+        update "$update_script" "$base_directory" "$@"
+    else
+        ask_to_allow_update_script "$update_script"
+        is_allowed "$update_script" && main "$@"
+    fi
+}
+
+main
+
+# vim: ft=sh
diff --git a/pkgs/by-name/fu/fupdate-flake/package.nix b/pkgs/by-name/fu/fupdate-flake/package.nix
new file mode 100644
index 00000000..5b2d7d29
--- /dev/null
+++ b/pkgs/by-name/fu/fupdate-flake/package.nix
@@ -0,0 +1,28 @@
+{
+  writeShellApplication,
+  # Dependencies
+  coreutils,
+  fd,
+  gnugrep,
+  bat-extras, # For `batgrep`
+  bat, # used by batgrep
+  gnused, # required by batgrep
+  git,
+}:
+writeShellApplication {
+  name = "fupdate-flake";
+  text = builtins.readFile ./fupdate-flake.sh;
+
+  # The `update.sh` script might actually want to keep the path.
+  inheritPath = true;
+
+  runtimeInputs = [
+    coreutils
+    fd
+    gnugrep
+    bat-extras.batgrep
+    bat # Used by `batgrep`
+    gnused # Required by `batgrep`
+    git
+  ];
+}
diff --git a/pkgs/by-name/fu/fupdate-sys/fupdate-sys.sh b/pkgs/by-name/fu/fupdate-sys/fupdate-sys.sh
new file mode 100755
index 00000000..28e09f3d
--- /dev/null
+++ b/pkgs/by-name/fu/fupdate-sys/fupdate-sys.sh
@@ -0,0 +1,158 @@
+#!/usr/bin/env dash
+
+# FIXME(@bpeetz): Ideally I could replace this script with a deployment tool. Thus we
+# would have the same tool on the server as I use in my config. <2025-04-14>
+
+# Shell library {{{
+die() {
+    error "$1"
+    if [ -n "$2" ]; then
+        exit "$2"
+    else
+        exit 1
+    fi
+}
+print() {
+    # shellcheck disable=SC2059
+    printf "$*"
+}
+println() {
+    # shellcheck disable=SC2059
+    printf "$*\n"
+}
+eprint() {
+    >&2 print "$@"
+}
+eprintln() {
+    >&2 println "$@"
+}
+if [ "${NO_COLOR-unset}" != "unset" ]; then
+    error() {
+        eprintln "==> ERROR:" "$*"
+    }
+    warning() {
+        eprintln "==> WARNING:" "$*"
+    }
+    debug() {
+        [ -n "$SHELL_LIBRARY_DEBUG" ] && eprintln "==> [Debug:]" "$*"
+    }
+    debug2() {
+        [ -n "$SHELL_LIBRARY_DEBUG" ] && eprintln " -> [Debug:]" "$*"
+    }
+    msg() {
+        eprintln "==>" "$*"
+    }
+    msg2() {
+        eprintln " ->" "$*"
+    }
+    prompt() {
+        eprint "..>" "$*"
+    }
+else
+    error() {
+        eprintln "\033[1;91m==> ERROR:\033[0m" "\033[1;93m$*\033[0m"
+    }
+    warning() {
+        eprintln "\033[1;91m==> WARNING:\033[0m" "\033[1;93m$*\033[0m"
+    }
+    debug() {
+        [ -n "$SHELL_LIBRARY_DEBUG" ] && eprintln "\033[1;94m==> [Debug:]\033[0m" "\033[1;93m$*\033[0m"
+    }
+    debug2() {
+        [ -n "$SHELL_LIBRARY_DEBUG" ] && eprintln "\033[1;94m -> [Debug:]\033[0m" "\033[1;93m$*\033[0m"
+    }
+    msg() {
+        eprintln "\033[1;96m==>\033[0m" "\033[1;93m$*\033[0m"
+    }
+    msg2() {
+        eprintln "\033[1;96m ->\033[0m" "\033[1;93m$*\033[0m"
+    }
+    prompt() {
+        eprint "\033[1;96m..>\033[0m" "\033[1;93m$*\033[0m"
+    }
+fi
+# }}}
+
+NAME="update-sys"
+help() {
+    cat <<EOF
+This is a NixOS System flake update manager.
+
+USAGE:
+    $NAME [--branch <branchname>] [--help]
+
+OPTIONS:
+    --branch | -b  BRANCHNAME
+                                select a branch to update from.
+
+    --mode   | -m  MODE
+                                select a mode to update with
+
+    --help   | -h
+                                output this help.
+ARGUMENTS:
+    BRANCHNAME := [[ git branch --list --format '%(refname:short)' ]]
+                                The name of the branch to deploy the config from
+
+    MODE := switch|boot|test|build|dry-build|dry-activate|edit|repl|build-vm|build-vm-with-bootloader
+                                See the 'nixos-rebuild' manpage for more information about these modes.
+EOF
+    exit "$1"
+}
+BRANCH=""
+
+while [ "$#" -gt 0 ]; do
+    case "$1" in
+    "--help" | "-h")
+        help 0
+        ;;
+    "--branch" | "-b")
+        if [ "${2-unset}" != "unset" ]; then
+            BRANCH="$2"
+        else
+            error "$1 requires an argument"
+            help 1
+        fi
+        shift 2
+        ;;
+    "--mode" | "-m")
+        if [ "${2-unset}" != "unset" ]; then
+            MODE="$2"
+        else
+            error "$1 requires an argument"
+            help 1
+        fi
+        shift 2
+        ;;
+    *)
+        error "the option $1 does not exist!"
+        help 1
+        ;;
+    esac
+done
+
+cd /etc/nixos || die "No /etc/nixos"
+msg "Starting system update..."
+git remote update origin --prune >/dev/null 2>&1
+if ! [ "$BRANCH" = "" ]; then
+    git switch "$BRANCH" >/dev/null 2>&1 && msg2 "Switched to branch '$BRANCH'"
+fi
+msg2 "Updating git repository..."
+git pull --rebase
+
+# We use a tempfile, to make this truly async.
+default_branch=$(mktemp)
+cleanup() {
+    rm "$default_branch"
+}
+trap cleanup EXIT
+
+git remote show origin | grep 'HEAD' | cut -d':' -f2 | sed -e 's/^ *//g' -e 's/ *$//g' >"$default_branch" &
+
+msg2 "Updating system..."
+nixos-rebuild "${MODE-switch}"
+
+git switch "$(cat "$default_branch")" >/dev/null 2>&1 && msg2 "Switched to branch '$(cat "$default_branch")'"
+msg "Finished Update!"
+
+# vim: ft=sh
diff --git a/pkgs/by-name/up/update-sys/package.nix b/pkgs/by-name/fu/fupdate-sys/package.nix
index 8777f82d..be692d12 100644
--- a/pkgs/by-name/up/update-sys/package.nix
+++ b/pkgs/by-name/fu/fupdate-sys/package.nix
@@ -1,5 +1,6 @@
 {
-  sysLib,
+  writeShellApplication,
+  # Dependencies
   git,
   nixos-rebuild,
   sudo,
@@ -10,12 +11,11 @@
   gnused,
   systemd,
 }:
-sysLib.writeShellScript {
-  name = "update-sys";
-  src = ./update-sys.sh;
-  generateCompletions = true;
-  keepPath = false;
-  dependencies = [
+writeShellApplication {
+  name = "fupdate-sys";
+  text = builtins.readFile ./fupdate-sys.sh;
+  inheritPath = false;
+  runtimeInputs = [
     git
     nixos-rebuild
     sudo
diff --git a/pkgs/by-name/fu/fupdate/.envrc b/pkgs/by-name/fu/fupdate/.envrc
new file mode 100644
index 00000000..fdd3e9d8
--- /dev/null
+++ b/pkgs/by-name/fu/fupdate/.envrc
@@ -0,0 +1,3 @@
+#!/usr/bin/env sh
+
+use flake
diff --git a/pkgs/by-name/fu/fupdate/.gitignore b/pkgs/by-name/fu/fupdate/.gitignore
new file mode 100644
index 00000000..2d5df85d
--- /dev/null
+++ b/pkgs/by-name/fu/fupdate/.gitignore
@@ -0,0 +1,2 @@
+/target
+.direnv
diff --git a/pkgs/by-name/fu/fupdate/Cargo.lock b/pkgs/by-name/fu/fupdate/Cargo.lock
new file mode 100644
index 00000000..4b160d08
--- /dev/null
+++ b/pkgs/by-name/fu/fupdate/Cargo.lock
@@ -0,0 +1,301 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "anstream"
+version = "0.6.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
+dependencies = [
+ "anstyle",
+ "anstyle-parse",
+ "anstyle-query",
+ "anstyle-wincon",
+ "colorchoice",
+ "is_terminal_polyfill",
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle"
+version = "1.0.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
+
+[[package]]
+name = "anstyle-parse"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
+dependencies = [
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle-query"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
+dependencies = [
+ "windows-sys",
+]
+
+[[package]]
+name = "anstyle-wincon"
+version = "3.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e"
+dependencies = [
+ "anstyle",
+ "once_cell",
+ "windows-sys",
+]
+
+[[package]]
+name = "anyhow"
+version = "1.0.97"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f"
+
+[[package]]
+name = "clap"
+version = "4.5.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d8aa86934b44c19c50f87cc2790e19f54f7a67aedb64101c2e1a2e5ecfb73944"
+dependencies = [
+ "clap_builder",
+ "clap_derive",
+]
+
+[[package]]
+name = "clap_builder"
+version = "4.5.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2414dbb2dd0695280da6ea9261e327479e9d37b0630f6b53ba2a11c60c679fd9"
+dependencies = [
+ "anstream",
+ "anstyle",
+ "clap_lex",
+ "strsim",
+]
+
+[[package]]
+name = "clap_complete"
+version = "4.5.47"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c06f5378ea264ad4f82bbc826628b5aad714a75abf6ece087e923010eb937fb6"
+dependencies = [
+ "clap",
+ "clap_lex",
+ "is_executable",
+ "shlex",
+]
+
+[[package]]
+name = "clap_derive"
+version = "4.5.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "clap_lex"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
+
+[[package]]
+name = "colorchoice"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
+
+[[package]]
+name = "fupdate"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "clap",
+ "clap_complete",
+]
+
+[[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
+[[package]]
+name = "is_executable"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d4a1b5bad6f9072935961dfbf1cced2f3d129963d091b6f69f007fe04e758ae2"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "is_terminal_polyfill"
+version = "1.70.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
+
+[[package]]
+name = "once_cell"
+version = "1.21.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.94"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "shlex"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+
+[[package]]
+name = "strsim"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+
+[[package]]
+name = "syn"
+version = "2.0.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
+
+[[package]]
+name = "utf8parse"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "windows-sys"
+version = "0.59.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
diff --git a/pkgs/by-name/fu/fupdate/Cargo.toml b/pkgs/by-name/fu/fupdate/Cargo.toml
new file mode 100644
index 00000000..c86afe2b
--- /dev/null
+++ b/pkgs/by-name/fu/fupdate/Cargo.toml
@@ -0,0 +1,71 @@
+[package]
+name = "fupdate"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+anyhow = "1.0.97"
+clap = { version = "4.5.35", features = ["derive"] }
+clap_complete = { version = "4.5.47", features = ["unstable-dynamic"] }
+
+[profile.release]
+lto = true
+codegen-units = 1
+panic = "abort"
+split-debuginfo = "off"
+
+[lints.rust]
+# rustc lint groups https://doc.rust-lang.org/rustc/lints/groups.html
+warnings = "warn"
+future_incompatible = { level = "warn", priority = -1 }
+let_underscore = { level = "warn", priority = -1 }
+nonstandard_style = { level = "warn", priority = -1 }
+rust_2018_compatibility = { level = "warn", priority = -1 }
+rust_2018_idioms = { level = "warn", priority = -1 }
+rust_2021_compatibility = { level = "warn", priority = -1 }
+unused = { level = "warn", priority = -1 }
+# rustc allowed-by-default lints https://doc.rust-lang.org/rustc/lints/listing/allowed-by-default.html
+# missing_docs = "warn"
+macro_use_extern_crate = "warn"
+meta_variable_misuse = "warn"
+missing_abi = "warn"
+missing_copy_implementations = "warn"
+missing_debug_implementations = "warn"
+non_ascii_idents = "warn"
+noop_method_call = "warn"
+single_use_lifetimes = "warn"
+trivial_casts = "warn"
+trivial_numeric_casts = "warn"
+unreachable_pub = "warn"
+unsafe_op_in_unsafe_fn = "warn"
+unused_crate_dependencies = "warn"
+unused_import_braces = "warn"
+unused_lifetimes = "warn"
+unused_qualifications = "warn"
+variant_size_differences = "warn"
+
+[lints.rustdoc]
+# rustdoc lints https://doc.rust-lang.org/rustdoc/lints.html
+broken_intra_doc_links = "warn"
+private_intra_doc_links = "warn"
+missing_crate_level_docs = "warn"
+private_doc_tests = "warn"
+invalid_codeblock_attributes = "warn"
+invalid_rust_codeblocks = "warn"
+bare_urls = "warn"
+
+[lints.clippy]
+# clippy allowed by default
+dbg_macro = "warn"
+# clippy categories https://doc.rust-lang.org/clippy/
+all = { level = "warn", priority = -1 }
+correctness = { level = "warn", priority = -1 }
+suspicious = { level = "warn", priority = -1 }
+style = { level = "warn", priority = -1 }
+complexity = { level = "warn", priority = -1 }
+perf = { level = "warn", priority = -1 }
+pedantic = { level = "warn", priority = -1 }
+missing_panics_doc = "allow"
+missing_errors_doc = "allow"
diff --git a/pkgs/by-name/fu/fupdate/flake.lock b/pkgs/by-name/fu/fupdate/flake.lock
new file mode 100644
index 00000000..eb3616c8
--- /dev/null
+++ b/pkgs/by-name/fu/fupdate/flake.lock
@@ -0,0 +1,27 @@
+{
+  "nodes": {
+    "nixpkgs": {
+      "locked": {
+        "lastModified": 1744096231,
+        "narHash": "sha256-kUfx3FKU1Etnua3EaKvpeuXs7zoFiAcli1gBwkPvGSs=",
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "rev": "b2b0718004cc9a5bca610326de0a82e6ea75920b",
+        "type": "github"
+      },
+      "original": {
+        "owner": "NixOS",
+        "ref": "nixpkgs-unstable",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
+    "root": {
+      "inputs": {
+        "nixpkgs": "nixpkgs"
+      }
+    }
+  },
+  "root": "root",
+  "version": 7
+}
diff --git a/pkgs/by-name/fu/fupdate/flake.nix b/pkgs/by-name/fu/fupdate/flake.nix
new file mode 100644
index 00000000..4777c1e5
--- /dev/null
+++ b/pkgs/by-name/fu/fupdate/flake.nix
@@ -0,0 +1,25 @@
+{
+  description = "This is a Nix flake update manager.";
+
+  inputs = {
+    nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
+  };
+
+  outputs = {nixpkgs, ...}: let
+    system = "x86_64-linux";
+    pkgs = nixpkgs.legacyPackages."${system}";
+  in {
+    devShells."${system}".default = pkgs.mkShell {
+      packages = with pkgs; [
+        cargo
+        clippy
+        rustc
+        rustfmt
+
+        cargo-edit
+      ];
+    };
+  };
+}
+# vim: ts=2
+
diff --git a/pkgs/by-name/fu/fupdate/fupdate.1.md b/pkgs/by-name/fu/fupdate/fupdate.1.md
deleted file mode 100644
index 710e8fb7..00000000
--- a/pkgs/by-name/fu/fupdate/fupdate.1.md
+++ /dev/null
@@ -1,70 +0,0 @@
-% FUPDATE(1) fupdate 1.0.0
-% Soispha
-% May 2023
-
-# NAME
-
-fupdate - updates your flake, while checking for common mistakes
-
-# SYNOPSIS
-
-**fupdate** list of \[*flake*|*\<some word>*|*--help*|*-h*\]
-
-# DESCRIPTION
-
-Argument can be stacked, this makes it possible to specify multiple targets to be updated in succession. See the Examples section for further details.
-
-No argument or *flake*
-: **fupdate**, when executed without arguments or with *flake*, will update your *flake.lock*, check for duplicate flake inputs, i.e., an input has an input declared, which you have also declared as input, and will run a script called *update.sh*, if you allow it.
-The allowance for the script is asked, when you run **fupdate** and the found script is not yet allowed. Furthermore, the allowance is based on the concrete sha256 hash of the script, so any changes will require another allowance.
-
-**\<some word>** as argument
-: If the executable **update-\<some word>** is reachable thought the PATH variable, than this is run. Otherwise, the program will exit.
-
-# OPTIONS
-
-**--help**, **-h**
-: Displays a help message and exit.
-
-**--version**, **-v**
-: Displays the software version and exit.
-
-# EXAMPLES
-
-**fupdate** or **fupdate flake**
-: Updates your *flake.lock*. See the Description section for further details.
-
-**fupdate sys**
-: Run the executable **update-sys**, if it exists. See the Description section for further details.
-
-**fupdate flake sys docs**
-: First updates your flake, then, if the command succeeded, runs **update-sys**, afterweich **update-docs** is run.
-
-# FILES
-
-*update.sh*
-: This is supposed to be a shell script located in your flake base directory, i.e., the directory which contains both a *flake.nix* and a *flake.lock* file.
-
-*~/.local/share/flake-update/*
-: **fupdate** will store the hashes to the allowed *update.sh* files here.
-
-# BUGS
-
-Report bugs to <https://codeberg.org/soispha/flake_update/issues>.
-
-# COPYRIGHT
-
-Copyright (C) 2023  Soispha
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <https://www.gnu.org/licenses/>.
diff --git a/pkgs/by-name/fu/fupdate/fupdate.sh b/pkgs/by-name/fu/fupdate/fupdate.sh
deleted file mode 100755
index 4322610a..00000000
--- a/pkgs/by-name/fu/fupdate/fupdate.sh
+++ /dev/null
@@ -1,197 +0,0 @@
-#! /usr/bin/env dash
-
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
-
-UPDATE_SCRIPT_NAME="update.sh"
-CONFIG_DIRECTORY_PATH="$HOME/.local/share/flake-update"
-
-# Both are used in version()
-# shellcheck disable=SC2034
-AUTHORS="Soispha"
-# shellcheck disable=SC2034
-YEARS="2023"
-
-UPDATE_SCRIPT_NOT_WANTED=false
-
-# Searches upward for a `UPDATE_SCRIPT_NAME` script
-# Returns a path to the script if it exists, otherwise nothing is returned
-check_for_update_script() {
-    dirname="$(search_upward_files "$UPDATE_SCRIPT_NAME")"
-    if [ "$dirname" ]; then
-        printf "%s/%s" "$dirname" "$UPDATE_SCRIPT_NAME"
-    fi
-}
-
-# Checks if a given path to the update script is allowed.
-# Takes the path as input
-# Return 0, if allowed, 1 if not.
-check_for_allowed_update_script() {
-    update_script="$1"
-    config_path="${CONFIG_DIRECTORY_PATH}${update_script}"
-    update_script_hash="$(sha256sum "$update_script")"
-    if [ -f "$config_path" ]; then
-        if [ "$(cat "$config_path")" = "$update_script_hash" ]; then
-            dbg "Recorded hash matches"
-            return 0
-        else
-            dbg "Recorded hash \'$(cat "$config_path")\' does not match real hash \'$update_script_hash\', assuming not allowed"
-            return 1
-        fi
-    else
-        dbg "Path \'$config_path\' does not exist, assuming not allowed"
-        return 1
-    fi
-}
-
-# Asks the user if they want to allow a given script.
-# Takes the path as input
-ask_to_allow_update_script() {
-    update_script="$1"
-    config_path="${CONFIG_DIRECTORY_PATH}${update_script}"
-    update_script_hash="$(sha256sum "$update_script")"
-    println "\033[2J" # clear the screen
-    cat "$update_script"
-    readp "Do you want to allow this script?[N/y]: " allow
-    # shellcheck disable=SC2154
-    dbg "allow is: $allow"
-    case "$allow" in
-    [yY])
-        dbg "allowed script"
-        dbg "storing contents in: $config_path"
-        mkdir --parents "$(dirname "$config_path")"
-        print "$update_script_hash" >"$config_path"
-        ;;
-    *)
-        UPDATE_SCRIPT_NOT_ALLOWED=true
-        ;;
-    esac
-}
-
-# Runs the provided script and continues to update the nix flake
-# Takes the path to the script and the directory to the flake as arguments
-# If the path to the update script is empty, it will be ignored
-update() {
-    update_script="$1"
-    flake_base_dir="$2"
-    shift 2
-    dbg "Provided following args to update script: '$*'"
-
-    cd "$flake_base_dir" || die "Provided dir \'$flake_base_dir\' can not be accessed"
-    dbg "changed directory to: $flake_base_dir"
-
-    nix flake update
-
-    if ! [ "$update_script" = "" ] && ! [ "$UPDATE_SCRIPT_NOT_WANTED" = "true" ]; then
-        "$update_script" "$@"
-    fi
-
-    if grep '[^0-9]_[0-9]' flake.lock >/dev/null; then
-        batgrep '[^0-9]_[0-9]' flake.lock
-        die "Your flake.nix contains duplicate inputs!"
-    fi
-}
-
-help() {
-    cat <<EOF
-This is a Nix flake update manager.
-
-USAGE:
-    $NAME [--help | --version] [flake [--no-script] | <some other command>]
-
-OPTIONS:
-    --help   | -h
-                            Display this help and exit.
-
-    --version   | -v
-                            Display version and copyright information and exit.
-
-    --no-script
-                            Avoid running the 'update.sh' script
-COMMANDS:
-    flake
-                            update the flake project
-
-    <some other command>
-                            runs a executable called "update-<some other command>", if it exists
-EOF
-}
-
-main() {
-    if ! [ "$UPDATE_SCRIPT_NOT_ALLOWED" = true ]; then
-        update_script="$(check_for_update_script)"
-        flake_base_dir="$(search_flake_base_dir)" # Assume, that the update script is in the base dir
-        dbg "update_script is: $update_script"
-        dbg "flake_base_dir is: $flake_base_dir"
-
-        if [ "$update_script" = "" ]; then
-            update "" "$flake_base_dir" "$@"
-        elif check_for_allowed_update_script "$update_script" && ! [ "$update_script" = "" ]; then
-            update "$update_script" "$flake_base_dir" "$@"
-        else
-            ask_to_allow_update_script "$update_script"
-            main "$@"
-        fi
-    fi
-}
-
-if [ "$#" -eq 0 ]; then
-    main
-    exit 0
-fi
-
-for input in "$@"; do
-    case "$input" in
-    "--help" | "-h")
-        help
-        exit 0
-        ;;
-    "--version" | "-v")
-        version
-        exit 0
-        ;;
-    "--no-script" | "-n")
-        UPDATE_SCRIPT_NOT_WANTED=true
-        ;;
-    "--")
-        end_of_cli_options=true
-
-        # Stop processing args after that marker.
-        break
-        ;;
-    esac
-    [ "$end_of_cli_options" = "true" ] && break
-done
-
-case "$1" in
-"flake")
-    shift 1
-
-    # Filter out fupdate specific flags
-    while [ "$1" != "--" ]; do
-        # FIXME: This check allows to add a flag multiple times, but this should probably
-        # not be allowed <2024-03-29>
-        case "$1" in
-        "--no-script" | "-n")
-            shift 1
-            ;;
-        *)
-            break
-            ;;
-        esac
-    done
-
-    [ "$1" = "--" ] && shift 1
-    main "$@"
-    ;;
-*)
-    command="$1"
-    shift 1
-    [ "$1" = "--" ] && shift 1
-    if which update-"$command" >/dev/null 2>&1; then
-        update-"$command" "$@"
-    else
-        die "command \"update-$command\" is not executable, or does not exist"
-    fi
-    ;;
-esac
diff --git a/pkgs/by-name/fu/fupdate/package.nix b/pkgs/by-name/fu/fupdate/package.nix
index 66372add..d33138e3 100644
--- a/pkgs/by-name/fu/fupdate/package.nix
+++ b/pkgs/by-name/fu/fupdate/package.nix
@@ -1,29 +1,32 @@
 {
-  sysLib,
-  dash,
-  lix,
-  gnugrep,
-  fd,
-  coreutils,
-  bat, # used by batgrep
-  bat-extras,
-  gnused, # required by batgrep
-  git, # needed to fetch through git
+  rustPlatform,
+  installShellFiles,
+  makeWrapper,
 }:
-sysLib.writeShellScript {
-  name = "fupdate";
-  src = ./fupdate.sh;
-  generateCompletions = true;
-  keepPath = true;
-  dependencies = [
-    dash
-    lix
-    gnugrep
-    fd
-    coreutils
-    bat # used by batgrep
-    bat-extras.batgrep
-    gnused # required by batgrep
-    git # needed to fetch through git
+rustPlatform.buildRustPackage (finalAttrs: {
+  pname = "fupdate";
+  version = "0.1.0";
+
+  src = ./.;
+  cargoLock = {
+    lockFile = ./Cargo.lock;
+  };
+
+  buildInputs = [];
+
+  nativeBuildInputs = [
+    installShellFiles
+    makeWrapper
   ];
-}
+
+  postInstall = ''
+    installShellCompletion --cmd fupdate \
+      --bash <(COMPLETE=bash $out/bin/fupdate) \
+      --fish <(COMPLETE=fish $out/bin/fupdate) \
+      --zsh <(COMPLETE=zsh $out/bin/fupdate)
+  '';
+
+  meta = {
+    mainProgram = "fupdate";
+  };
+})
diff --git a/pkgs/by-name/fu/fupdate/src/cli.rs b/pkgs/by-name/fu/fupdate/src/cli.rs
new file mode 100644
index 00000000..6f970ac4
--- /dev/null
+++ b/pkgs/by-name/fu/fupdate/src/cli.rs
@@ -0,0 +1,46 @@
+use std::{env, ffi::OsStr, fs::read_dir};
+
+use clap::Parser;
+use clap_complete::{engine::ArgValueCompleter, CompletionCandidate};
+
+/// This is a Nix flake update manager.
+#[derive(Parser, Debug)]
+#[command(author, version, about)]
+pub struct CliArgs {
+    /// The command to execute.
+    #[arg(add = ArgValueCompleter::new(get_fupdate_commands))]
+    pub command: Vec<String>,
+}
+
+fn get_fupdate_commands(current: &OsStr) -> Vec<CompletionCandidate> {
+    let mut output = vec![];
+    let path = env::var("PATH").unwrap_or_default();
+
+    let Some(current) = current.to_str() else {
+        return output;
+    };
+
+    for directory in path.split(':') {
+        if let Ok(mut read) = read_dir(directory) {
+            for value in read.by_ref().flatten() {
+                let file_name = value.file_name();
+                let name = file_name.to_string_lossy();
+                let Some(stripped) = name.strip_prefix("fupdate-") else {
+                    continue;
+                };
+
+                if stripped.starts_with(current) {
+                    output.push(CompletionCandidate::new(
+                        value
+                            .file_name()
+                            .to_string_lossy()
+                            .strip_prefix("fupdate-")
+                            .expect("Exists"),
+                    ));
+                }
+            }
+        }
+    }
+
+    output
+}
diff --git a/pkgs/by-name/fu/fupdate/src/main.rs b/pkgs/by-name/fu/fupdate/src/main.rs
new file mode 100644
index 00000000..850eaf87
--- /dev/null
+++ b/pkgs/by-name/fu/fupdate/src/main.rs
@@ -0,0 +1,40 @@
+use std::process::Command;
+
+use anyhow::{bail, Context, Result};
+use clap::{CommandFactory, Parser};
+
+pub mod cli;
+
+use crate::cli::CliArgs;
+
+fn main() -> Result<(), anyhow::Error> {
+    clap_complete::CompleteEnv::with_factory(CliArgs::command).complete();
+
+    let args = CliArgs::parse();
+
+    let other = args.command.first().map_or("flake", String::as_str);
+
+    {
+        let args = if args.command.len() > 1 {
+            &args.command[1..]
+        } else {
+            &[]
+        };
+
+        let status = Command::new(format!("fupdate-{other}"))
+            .args(args)
+            .status()
+            .with_context(|| format!("Failed to execute `fupdate-{other}`"))?;
+
+        if !status.success() {
+            bail!("Command `fupdate-{other}` failed!");
+        }
+    }
+
+    Ok(())
+}
+
+#[test]
+fn verify_cli() {
+    CliArgs::command().debug_assert();
+}
diff --git a/pkgs/by-name/fu/fupdate/update.sh b/pkgs/by-name/fu/fupdate/update.sh
new file mode 100755
index 00000000..9268caf2
--- /dev/null
+++ b/pkgs/by-name/fu/fupdate/update.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+cargo update && cargo upgrade
diff --git a/pkgs/by-name/ge/generate_moz_extension/Cargo.lock b/pkgs/by-name/ge/generate_moz_extension/Cargo.lock
index 10970fa6..9ca10746 100644
--- a/pkgs/by-name/ge/generate_moz_extension/Cargo.lock
+++ b/pkgs/by-name/ge/generate_moz_extension/Cargo.lock
@@ -76,9 +76,9 @@ checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
 
 [[package]]
 name = "cc"
-version = "1.2.17"
+version = "1.2.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a"
+checksum = "525046617d8376e3db1deffb079e91cef90a89fc3ca5c185bbf8c9ecdd15cd5c"
 dependencies = [
  "shlex",
 ]
@@ -133,9 +133,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
 
 [[package]]
 name = "errno"
-version = "0.3.10"
+version = "0.3.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
+checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e"
 dependencies = [
  "libc",
  "windows-sys 0.59.0",
@@ -427,9 +427,9 @@ dependencies = [
 
 [[package]]
 name = "hyper-util"
-version = "0.1.10"
+version = "0.1.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4"
+checksum = "497bbc33a26fdd4af9ed9c70d63f61cf56a938375fbb32df34db9b1cd6d643f2"
 dependencies = [
  "bytes",
  "futures-channel",
@@ -437,6 +437,7 @@ dependencies = [
  "http",
  "http-body",
  "hyper",
+ "libc",
  "pin-project-lite",
  "socket2",
  "tokio",
@@ -585,9 +586,9 @@ dependencies = [
 
 [[package]]
 name = "indexmap"
-version = "2.8.0"
+version = "2.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058"
+checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
 dependencies = [
  "equivalent",
  "hashbrown",
@@ -623,9 +624,9 @@ checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
 
 [[package]]
 name = "linux-raw-sys"
-version = "0.9.3"
+version = "0.9.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413"
+checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
 
 [[package]]
 name = "litemap"
@@ -653,9 +654,9 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
 
 [[package]]
 name = "miniz_oxide"
-version = "0.8.5"
+version = "0.8.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5"
+checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
 dependencies = [
  "adler2",
 ]
@@ -705,9 +706,9 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
 
 [[package]]
 name = "openssl"
-version = "0.10.71"
+version = "0.10.72"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5e14130c6a98cd258fdcb0fb6d744152343ff729cbfcb28c656a9d12b999fbcd"
+checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da"
 dependencies = [
  "bitflags",
  "cfg-if",
@@ -737,9 +738,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
 
 [[package]]
 name = "openssl-sys"
-version = "0.9.106"
+version = "0.9.107"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8bb61ea9811cc39e3c2069f40b8b8e2e70d8569b361f879786cc7ed48b777cdd"
+checksum = "8288979acd84749c744a9014b4382d42b8f7b2592847b5afb2ed29e5d16ede07"
 dependencies = [
  "cc",
  "libc",
@@ -861,9 +862,9 @@ checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
 
 [[package]]
 name = "rustix"
-version = "1.0.3"
+version = "1.0.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e56a18552996ac8d29ecc3b190b4fdbb2d91ca4ec396de7bbffaf43f3d637e96"
+checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf"
 dependencies = [
  "bitflags",
  "errno",
@@ -1016,15 +1017,15 @@ dependencies = [
 
 [[package]]
 name = "smallvec"
-version = "1.14.0"
+version = "1.15.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd"
+checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9"
 
 [[package]]
 name = "socket2"
-version = "0.5.8"
+version = "0.5.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8"
+checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef"
 dependencies = [
  "libc",
  "windows-sys 0.52.0",
@@ -1119,9 +1120,9 @@ dependencies = [
 
 [[package]]
 name = "tokio"
-version = "1.44.1"
+version = "1.44.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f382da615b842244d4b8738c82ed1275e6c5dd90c459a30941cd07080b06c91a"
+checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48"
 dependencies = [
  "backtrace",
  "bytes",
diff --git a/pkgs/by-name/ge/generate_moz_extension/Cargo.toml b/pkgs/by-name/ge/generate_moz_extension/Cargo.toml
index 1b3ff4f0..8a07d055 100644
--- a/pkgs/by-name/ge/generate_moz_extension/Cargo.toml
+++ b/pkgs/by-name/ge/generate_moz_extension/Cargo.toml
@@ -11,4 +11,4 @@ futures = "0.3.31"
 reqwest = "0.12.15"
 serde = { version = "1.0.219", features = ["derive"] }
 serde_json = "1.0.140"
-tokio = { version = "1.44.1", features = ["macros", "rt-multi-thread"] }
+tokio = { version = "1.44.2", features = ["macros", "rt-multi-thread"] }
diff --git a/pkgs/by-name/ge/generate_moz_extension/flake.lock b/pkgs/by-name/ge/generate_moz_extension/flake.lock
index 9d72fb5b..b6478e18 100644
--- a/pkgs/by-name/ge/generate_moz_extension/flake.lock
+++ b/pkgs/by-name/ge/generate_moz_extension/flake.lock
@@ -2,11 +2,11 @@
   "nodes": {
     "crane": {
       "locked": {
-        "lastModified": 1742394900,
-        "narHash": "sha256-vVOAp9ahvnU+fQoKd4SEXB2JG2wbENkpqcwlkIXgUC0=",
+        "lastModified": 1743908961,
+        "narHash": "sha256-e1idZdpnnHWuosI3KsBgAgrhMR05T2oqskXCmNzGPq0=",
         "owner": "ipetkov",
         "repo": "crane",
-        "rev": "70947c1908108c0c551ddfd73d4f750ff2ea67cd",
+        "rev": "80ceeec0dc94ef967c371dcdc56adb280328f591",
         "type": "github"
       },
       "original": {
@@ -35,11 +35,11 @@
     },
     "nixpkgs": {
       "locked": {
-        "lastModified": 1743076231,
-        "narHash": "sha256-yQugdVfi316qUfqzN8JMaA2vixl+45GxNm4oUfXlbgw=",
+        "lastModified": 1744096231,
+        "narHash": "sha256-kUfx3FKU1Etnua3EaKvpeuXs7zoFiAcli1gBwkPvGSs=",
         "owner": "NixOS",
         "repo": "nixpkgs",
-        "rev": "6c5963357f3c1c840201eda129a99d455074db04",
+        "rev": "b2b0718004cc9a5bca610326de0a82e6ea75920b",
         "type": "github"
       },
       "original": {
@@ -64,11 +64,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1743215516,
-        "narHash": "sha256-52qbrkG65U1hyrQWltgHTgH4nm0SJL+9TWv2UDCEPNI=",
+        "lastModified": 1744166053,
+        "narHash": "sha256-mpI7OzFwp+fUeDtZYQbVZ2YmtxTN2UNrrOwbYD27xKU=",
         "owner": "oxalica",
         "repo": "rust-overlay",
-        "rev": "524463199fdee49338006b049bc376b965a2cfed",
+        "rev": "896158be1835589db6f42f45ef0a49b8b492cc66",
         "type": "github"
       },
       "original": {
diff --git a/pkgs/by-name/gi/git-cm/git-cm.sh b/pkgs/by-name/gi/git-cm/git-cm.sh
index 2204e4d6..1eb46730 100755
--- a/pkgs/by-name/gi/git-cm/git-cm.sh
+++ b/pkgs/by-name/gi/git-cm/git-cm.sh
@@ -1,8 +1,5 @@
 #!/usr/bin/env dash
 
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
-
 ROOT="$(git rev-parse --show-toplevel)"
 
 # Take first line from previous commit
@@ -13,6 +10,6 @@ else
 fi
 sed '1d' "$(git config commit.template)" >>"$ROOT/.git/COMMIT_TEMPLATE"
 
-git commit --template "$ROOT/.git/COMMIT_TEMPLATE" --verbose "$@"
+git commit --template "$ROOT/.git/COMMIT_TEMPLATE" "$@"
 
 # vim: ft=sh
diff --git a/pkgs/by-name/gi/git-cm/package.nix b/pkgs/by-name/gi/git-cm/package.nix
index a9949783..576df2f7 100644
--- a/pkgs/by-name/gi/git-cm/package.nix
+++ b/pkgs/by-name/gi/git-cm/package.nix
@@ -1,13 +1,17 @@
 {
-  sysLib,
+  writeShellApplication,
+  # Dependencies
   git,
   gnused,
 }:
-sysLib.writeShellScript {
+writeShellApplication {
   name = "git-cm";
-  src = ./git-cm.sh;
-  keepPath = true;
-  dependencies = [
+  text = builtins.readFile ./git-cm.sh;
+
+  # We need access to the $EDITOR
+  inheritPath = true;
+
+  runtimeInputs = [
     git
     gnused
   ];
diff --git a/pkgs/by-name/gi/git-edit-index/git-edit-index.sh b/pkgs/by-name/gi/git-edit-index/git-edit-index.sh
index e73dc53c..94a8d4a4 100755
--- a/pkgs/by-name/gi/git-edit-index/git-edit-index.sh
+++ b/pkgs/by-name/gi/git-edit-index/git-edit-index.sh
@@ -1,19 +1,10 @@
 #!/usr/bin/env dash
 
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
+NAME="git-edit-index"
 
-# needed for help() and version
-# shellcheck disable=2034
-AUTHORS="Soispha"
-# shellcheck disable=2034
-YEARS="2024"
-# shellcheck disable=2034
-VERSION="1.0.0"
-
-# NAME is from the wrapper
-# shellcheck disable=SC2269
-NAME="$NAME"
+warn() {
+    echo "WARNING: $1"
+}
 
 help() {
     cat <<EOF
@@ -55,23 +46,24 @@ materialize_file() {
 }
 
 edit() {
-    files_to_add="$(mktmp)"
-    realpath --relative-to=. "$@" >"$files_to_add"
+    files_to_add="$(mktemp)"
+    cleanup() {
+        rm "$files_to_add"
+    }
+    trap cleanup EXIT
 
-    index_files="$(mktmp)"
-    git diff --name-only --cached --diff-filter=AM >"$index_files"
+    realpath --relative-to=. "$@" >"$files_to_add"
 
-    while read -r file; do
-        if grep -q "$file" "$files_to_add"; then
-            sed -i "s|$file||" "$files_to_add"
-            materialize_file "$file"
+    git diff --name-only --cached --diff-filter=AM | while read -r index_file; do
+        if grep -q "$index_file" "$files_to_add"; then
+            sed -i "s|$index_file||" "$files_to_add"
+            materialize_file "$index_file"
         fi
-    done <"$index_files"
+    done
 
-    files_to_check="$(mktmp)"
-    clean "$files_to_add" >"$files_to_check"
-    if [ "$(wc -l <"$files_to_check")" -gt 0 ]; then
-        warn "Could not edit every file:"
+    unedided_files="$(sed '/^\s*$/d' "$files_to_add" | wc -l)"
+    if [ "$unedided_files" -gt 0 ]; then
+        warn "Failed to edit $unedided_files file(s):"
         cat "$files_to_add"
     fi
 }
@@ -82,10 +74,6 @@ for arg in "$@"; do
         help
         exit 0
         ;;
-    "--version" | "-v")
-        version
-        exit 0
-        ;;
     "--")
         end_of_cli_options=true
         ;;
diff --git a/pkgs/by-name/gi/git-edit-index/package.nix b/pkgs/by-name/gi/git-edit-index/package.nix
index 8ac085bf..d7bba6af 100644
--- a/pkgs/by-name/gi/git-edit-index/package.nix
+++ b/pkgs/by-name/gi/git-edit-index/package.nix
@@ -1,19 +1,20 @@
 {
-  sysLib,
+  writeShellApplication,
+  # Dependencies
+  coreutils,
   git,
   gnused,
 }:
-sysLib.writeShellScript {
+writeShellApplication {
   name = "git-edit-index";
-  src = ./git-edit-index.sh;
-  generateCompletions = true;
+  text = builtins.readFile ./git-edit-index.sh;
 
   # `git-edit-index` starts neovim, wich might want to shell out from
-  keepPath = true;
+  inheritPath = true;
 
-  dependencies = [
+  runtimeInputs = [
+    coreutils
     git
     gnused
-    # $EDITOR
   ];
 }
diff --git a/pkgs/by-name/hi/hibernate/hibernate.sh b/pkgs/by-name/hi/hibernate/hibernate.sh
index 30868fd1..59b08ec0 100755
--- a/pkgs/by-name/hi/hibernate/hibernate.sh
+++ b/pkgs/by-name/hi/hibernate/hibernate.sh
@@ -1,7 +1,6 @@
 #!/usr/bin/env dash
 
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
+# TODO(@bpeetz): This functionality could be moved to `tskm`. <2025-04-14>
 
 context="$(task _get rc.context)"
 [ "$context" ] && task context none
diff --git a/pkgs/by-name/hi/hibernate/package.nix b/pkgs/by-name/hi/hibernate/package.nix
index 24754f09..f0fb4e96 100644
--- a/pkgs/by-name/hi/hibernate/package.nix
+++ b/pkgs/by-name/hi/hibernate/package.nix
@@ -1,15 +1,14 @@
 {
-  sysLib,
+  writeShellApplication,
   systemd,
-  taskwarrior,
+  taskwarrior3,
 }:
-sysLib.writeShellScript {
+writeShellApplication {
   name = "hibernate";
-  src = ./hibernate.sh;
-  generateCompletions = false;
-  keepPath = false;
-  dependencies = [
+  text = builtins.readFile ./hibernate.sh;
+  inheritPath = false;
+  runtimeInputs = [
     systemd
-    taskwarrior
+    taskwarrior3
   ];
 }
diff --git a/pkgs/by-name/lf/lf-make-map/Cargo.lock b/pkgs/by-name/lf/lf-make-map/Cargo.lock
index d68f7492..3e651a8b 100644
--- a/pkgs/by-name/lf/lf-make-map/Cargo.lock
+++ b/pkgs/by-name/lf/lf-make-map/Cargo.lock
@@ -87,9 +87,9 @@ checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
 
 [[package]]
 name = "cc"
-version = "1.2.17"
+version = "1.2.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a"
+checksum = "525046617d8376e3db1deffb079e91cef90a89fc3ca5c185bbf8c9ecdd15cd5c"
 dependencies = [
  "shlex",
 ]
@@ -116,9 +116,9 @@ dependencies = [
 
 [[package]]
 name = "clap"
-version = "4.5.34"
+version = "4.5.35"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e958897981290da2a852763fe9cdb89cd36977a5d729023127095fa94d95e2ff"
+checksum = "d8aa86934b44c19c50f87cc2790e19f54f7a67aedb64101c2e1a2e5ecfb73944"
 dependencies = [
  "clap_builder",
  "clap_derive",
@@ -126,9 +126,9 @@ dependencies = [
 
 [[package]]
 name = "clap_builder"
-version = "4.5.34"
+version = "4.5.35"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "83b0f35019843db2160b5bb19ae09b4e6411ac33fc6a712003c33e03090e2489"
+checksum = "2414dbb2dd0695280da6ea9261e327479e9d37b0630f6b53ba2a11c60c679fd9"
 dependencies = [
  "anstream",
  "anstyle",
@@ -180,9 +180,9 @@ checksum = "fbd780fe5cc30f81464441920d82ac8740e2e46b29a6fad543ddd075229ce37e"
 
 [[package]]
 name = "iana-time-zone"
-version = "0.1.62"
+version = "0.1.63"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b2fd658b06e56721792c5df4475705b6cda790e9298d19d2f8af083457bcd127"
+checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8"
 dependencies = [
  "android_system_properties",
  "core-foundation-sys",
@@ -446,11 +446,37 @@ dependencies = [
 
 [[package]]
 name = "windows-core"
-version = "0.52.0"
+version = "0.61.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
+checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980"
 dependencies = [
- "windows-targets",
+ "windows-implement",
+ "windows-interface",
+ "windows-link",
+ "windows-result",
+ "windows-strings",
+]
+
+[[package]]
+name = "windows-implement"
+version = "0.60.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "windows-interface"
+version = "0.59.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
 ]
 
 [[package]]
@@ -460,6 +486,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38"
 
 [[package]]
+name = "windows-result"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "windows-strings"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
 name = "windows-sys"
 version = "0.59.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/pkgs/by-name/lf/lf-make-map/Cargo.toml b/pkgs/by-name/lf/lf-make-map/Cargo.toml
index d2427d73..4266ce0c 100644
--- a/pkgs/by-name/lf/lf-make-map/Cargo.toml
+++ b/pkgs/by-name/lf/lf-make-map/Cargo.toml
@@ -8,7 +8,7 @@ edition = "2021"
 
 [dependencies]
 anyhow = "1.0.97"
-clap = { version = "4.5.34", features = ["derive", "env"] }
+clap = { version = "4.5.35", features = ["derive", "env"] }
 log = "0.4.27"
 stderrlog = "0.6.0"
 walkdir = "2.5.0"
diff --git a/pkgs/by-name/lf/lf-make-map/flake.lock b/pkgs/by-name/lf/lf-make-map/flake.lock
index c9c523d9..2e19a47e 100644
--- a/pkgs/by-name/lf/lf-make-map/flake.lock
+++ b/pkgs/by-name/lf/lf-make-map/flake.lock
@@ -2,11 +2,11 @@
   "nodes": {
     "crane": {
       "locked": {
-        "lastModified": 1742394900,
-        "narHash": "sha256-vVOAp9ahvnU+fQoKd4SEXB2JG2wbENkpqcwlkIXgUC0=",
+        "lastModified": 1743908961,
+        "narHash": "sha256-e1idZdpnnHWuosI3KsBgAgrhMR05T2oqskXCmNzGPq0=",
         "owner": "ipetkov",
         "repo": "crane",
-        "rev": "70947c1908108c0c551ddfd73d4f750ff2ea67cd",
+        "rev": "80ceeec0dc94ef967c371dcdc56adb280328f591",
         "type": "github"
       },
       "original": {
@@ -53,11 +53,11 @@
     },
     "nixpkgs": {
       "locked": {
-        "lastModified": 1743076231,
-        "narHash": "sha256-yQugdVfi316qUfqzN8JMaA2vixl+45GxNm4oUfXlbgw=",
+        "lastModified": 1744096231,
+        "narHash": "sha256-kUfx3FKU1Etnua3EaKvpeuXs7zoFiAcli1gBwkPvGSs=",
         "owner": "NixOS",
         "repo": "nixpkgs",
-        "rev": "6c5963357f3c1c840201eda129a99d455074db04",
+        "rev": "b2b0718004cc9a5bca610326de0a82e6ea75920b",
         "type": "github"
       },
       "original": {
@@ -85,11 +85,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1743215516,
-        "narHash": "sha256-52qbrkG65U1hyrQWltgHTgH4nm0SJL+9TWv2UDCEPNI=",
+        "lastModified": 1744166053,
+        "narHash": "sha256-mpI7OzFwp+fUeDtZYQbVZ2YmtxTN2UNrrOwbYD27xKU=",
         "owner": "oxalica",
         "repo": "rust-overlay",
-        "rev": "524463199fdee49338006b049bc376b965a2cfed",
+        "rev": "896158be1835589db6f42f45ef0a49b8b492cc66",
         "type": "github"
       },
       "original": {
@@ -120,11 +120,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1743081648,
-        "narHash": "sha256-WRAylyYptt6OX5eCEBWyTwOEqEtD6zt33rlUkr6u3cE=",
+        "lastModified": 1743748085,
+        "narHash": "sha256-uhjnlaVTWo5iD3LXics1rp9gaKgDRQj6660+gbUU3cE=",
         "owner": "numtide",
         "repo": "treefmt-nix",
-        "rev": "29a3d7b768c70addce17af0869f6e2bd8f5be4b7",
+        "rev": "815e4121d6a5d504c0f96e5be2dd7f871e4fd99d",
         "type": "github"
       },
       "original": {
diff --git a/pkgs/by-name/ll/ll/ll.sh b/pkgs/by-name/ll/ll/ll.sh
index 73328e3e..3fb8d9aa 100755
--- a/pkgs/by-name/ll/ll/ll.sh
+++ b/pkgs/by-name/ll/ll/ll.sh
@@ -1,9 +1,10 @@
 #!/usr/bin/env dash
 
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
-
 last_directory="$(mktemp)"
+cleanup() {
+    rm "$last_directory"
+}
+trap cleanup EXIT
 
 command lf -last-dir-path="$last_directory" "$@"
 
@@ -15,5 +16,4 @@ else
     die "$dir does not exist!"
 fi
 
-rm "$last_directory"
 # vim: ft=sh
diff --git a/pkgs/by-name/ll/ll/package.nix b/pkgs/by-name/ll/ll/package.nix
index 4c13b40e..caca5b4e 100644
--- a/pkgs/by-name/ll/ll/package.nix
+++ b/pkgs/by-name/ll/ll/package.nix
@@ -1,9 +1,9 @@
-{sysLib}:
-sysLib.writeShellScript {
+{writeShellApplication}:
+writeShellApplication {
   name = "ll";
-  src = ./ll.sh;
-  generateCompletions = false;
+  text = builtins.readFile ./ll.sh;
 
-  # `ll` must be able to change the path of the running shell.
-  wrap = false;
+  # This is sourced in the shell
+  inheritPath = true;
+  bashOptions = [];
 }
diff --git a/pkgs/by-name/lm/lm/lm.sh b/pkgs/by-name/lm/lm/lm.sh
index d5fdca10..9c61f30f 100755
--- a/pkgs/by-name/lm/lm/lm.sh
+++ b/pkgs/by-name/lm/lm/lm.sh
@@ -1,7 +1,13 @@
 #!/usr/bin/env dash
 
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
+die() {
+    echo "ERROR: $1"
+    exit 1
+}
+
+msg() {
+    echo "$1"
+}
 
 if [ -f "$XDG_RUNTIME_DIR/ll/last_directory" ]; then
     last_dir="$(cat "$XDG_RUNTIME_DIR/ll/last_directory")"
diff --git a/pkgs/by-name/lm/lm/package.nix b/pkgs/by-name/lm/lm/package.nix
index ef417cd2..a80c473e 100644
--- a/pkgs/by-name/lm/lm/package.nix
+++ b/pkgs/by-name/lm/lm/package.nix
@@ -1,9 +1,9 @@
-{sysLib}:
-sysLib.writeShellScript {
+{writeShellApplication}:
+writeShellApplication {
   name = "lm";
-  src = ./lm.sh;
-  generateCompletions = false;
+  text = builtins.readFile ./lm.sh;
 
-  # `ll` must be able to change the path of the running shell.
-  wrap = false;
+  # This is sourced in the shell
+  inheritPath = true;
+  bashOptions = [];
 }
diff --git a/pkgs/by-name/lo/lock/package.nix b/pkgs/by-name/lo/lock/package.nix
index 1c857cd6..a59fbdd0 100644
--- a/pkgs/by-name/lo/lock/package.nix
+++ b/pkgs/by-name/lo/lock/package.nix
@@ -1,13 +1,13 @@
 {
   writeShellApplication,
-  taskwarrior,
+  taskwarrior3,
   swaylock,
 }:
 writeShellApplication {
   name = "lock";
   text = builtins.readFile ./lock.sh;
   runtimeInputs = [
-    taskwarrior
+    taskwarrior3
     swaylock
   ];
   meta = {
diff --git a/pkgs/by-name/mp/mpp-beetrm/mpp-beetrm.sh b/pkgs/by-name/mp/mpp-beetrm/mpp-beetrm.sh
index 3209503c..5a94662b 100755
--- a/pkgs/by-name/mp/mpp-beetrm/mpp-beetrm.sh
+++ b/pkgs/by-name/mp/mpp-beetrm/mpp-beetrm.sh
@@ -1,8 +1,5 @@
 #!/usr/bin/env dash
 
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
-
 beet remove --delete \
     title:"$(mpc --format '%title%' current)" \
     album:"$(mpc --format '%album%' current)"
diff --git a/pkgs/by-name/mp/mpp-beetrm/package.nix b/pkgs/by-name/mp/mpp-beetrm/package.nix
index 24b56606..425d05fd 100644
--- a/pkgs/by-name/mp/mpp-beetrm/package.nix
+++ b/pkgs/by-name/mp/mpp-beetrm/package.nix
@@ -1,15 +1,15 @@
 {
-  sysLib,
+  writeShellApplication,
+  # Dependencies
   mpc,
   beets,
 }:
-sysLib.writeShellScript {
+writeShellApplication {
   name = "mpp-beetrm";
-  src = ./mpp-beetrm.sh;
-  generateCompletions = false;
-  keepPath = false;
+  text = builtins.readFile ./mpp-beetrm.sh;
+  inheritPath = false;
 
-  dependencies = [
+  runtimeInputs = [
     mpc
     beets
   ];
diff --git a/pkgs/by-name/mp/mpp-lyrics/mpp-lyrics.sh b/pkgs/by-name/mp/mpp-lyrics/mpp-lyrics.sh
index 004c67c7..178eb924 100755
--- a/pkgs/by-name/mp/mpp-lyrics/mpp-lyrics.sh
+++ b/pkgs/by-name/mp/mpp-lyrics/mpp-lyrics.sh
@@ -1,11 +1,11 @@
 #!/usr/bin/env dash
 
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
+die() {
+    echo "Error: $1"
+    exit 1
+}
 
-(
-    cd "%MPD_MUSIC_DIR" || die "No music dir!"
-    exiftool "$(mpc --format '%file%' current)" -json | jq '.[0].Lyrics' -r | less
-)
+cd "$XDG_MUSIC_DIR" || die "No music dir!"
+exiftool "$(mpc --format '%file%' current)" -json | jq '.[0].Lyrics' --raw-output | less
 
 # vim: ft=sh
diff --git a/pkgs/by-name/mp/mpp-lyrics/package.nix b/pkgs/by-name/mp/mpp-lyrics/package.nix
index 76b590c7..23979c14 100644
--- a/pkgs/by-name/mp/mpp-lyrics/package.nix
+++ b/pkgs/by-name/mp/mpp-lyrics/package.nix
@@ -1,23 +1,18 @@
 {
-  sysLib,
+  writeShellApplication,
+  # Dependencies
   exiftool,
   mpc,
   jq,
   less,
   locale, # dependency of less
-  mpd_music_dir ? "\${XDG_MUSIC_DIR}",
 }:
-sysLib.writeShellScript {
+writeShellApplication {
   name = "mpp-lyrics";
-  src = ./mpp-lyrics.sh;
-  generateCompletions = false;
-  keepPath = false;
+  text = builtins.readFile ./mpp-lyrics.sh;
+  inheritPath = false;
 
-  replacementStrings = {
-    MPD_MUSIC_DIR = mpd_music_dir;
-  };
-
-  dependencies = [
+  runtimeInputs = [
     exiftool
     mpc
     jq
diff --git a/pkgs/by-name/mp/mpp-searchadd/mpp-searchadd.sh b/pkgs/by-name/mp/mpp-searchadd/mpp-searchadd.sh
index 3fe9a6b6..7195bd35 100755
--- a/pkgs/by-name/mp/mpp-searchadd/mpp-searchadd.sh
+++ b/pkgs/by-name/mp/mpp-searchadd/mpp-searchadd.sh
@@ -1,14 +1,8 @@
 #!/usr/bin/env dash
 
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
-
-tracks="$(mktmp)"
-beet list "$@" --path >"$tracks"
-
-while read -r track; do
+beet list "$@" --path | while read -r track; do
     mpc add "$track"
-done <"$tracks"
+done
 
 mpc playlist
 # vim: ft=sh
diff --git a/pkgs/by-name/mp/mpp-searchadd/package.nix b/pkgs/by-name/mp/mpp-searchadd/package.nix
index a98472d1..2f9db4ca 100644
--- a/pkgs/by-name/mp/mpp-searchadd/package.nix
+++ b/pkgs/by-name/mp/mpp-searchadd/package.nix
@@ -1,15 +1,15 @@
 {
-  sysLib,
+  writeShellApplication,
+  # Dependencies.
   mpc,
   beets,
 }:
-sysLib.writeShellScript {
+writeShellApplication {
   name = "mpp-searchadd";
-  src = ./mpp-searchadd.sh;
-  generateCompletions = false;
-  keepPath = false;
+  text = builtins.readFile ./mpp-searchadd.sh;
+  inheritPath = false;
 
-  dependencies = [
+  runtimeInputs = [
     mpc
     beets
   ];
diff --git a/pkgs/by-name/mp/mpp/mpp.sh b/pkgs/by-name/mp/mpp/mpp.sh
index 538a56ee..7941df07 100755
--- a/pkgs/by-name/mp/mpp/mpp.sh
+++ b/pkgs/by-name/mp/mpp/mpp.sh
@@ -1,8 +1,5 @@
 #!/usr/bin/env dash
 
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
-
 case "$1" in
 "searchadd")
     shift 1
diff --git a/pkgs/by-name/mp/mpp/package.nix b/pkgs/by-name/mp/mpp/package.nix
index 9c5315b0..7d7e0527 100644
--- a/pkgs/by-name/mp/mpp/package.nix
+++ b/pkgs/by-name/mp/mpp/package.nix
@@ -1,20 +1,26 @@
 {
-  sysLib,
-  mpc,
-  fd,
+  writeShellApplication,
   symlinkJoin,
   stdenv,
+  # Dependencies
+  mpc,
+  mpp-searchadd,
+  mpp-lyrics,
+  mpp-beetrm,
+  # Build dependencies
+  fd,
   zsh,
 }: let
-  script = sysLib.writeShellScript {
+  script = writeShellApplication {
     name = "mpp";
-    src = ./mpp.sh;
-    generateCompletions = false;
-    # We source the wrappers from the environment, to ensure that they have the same
-    # configurations (e.g. MPD_MUSIC_DIR in `mpc-lyrics`)
-    keepPath = true;
-    dependencies = [
+    text = builtins.readFile ./mpp.sh;
+    inheritPath = false;
+
+    runtimeInputs = [
       mpc
+      mpp-searchadd
+      mpp-lyrics
+      mpp-beetrm
     ];
   };
 
diff --git a/pkgs/by-name/ri/river-mk-keymap/Cargo.lock b/pkgs/by-name/ri/river-mk-keymap/Cargo.lock
index 7fb009ef..c555a367 100644
--- a/pkgs/by-name/ri/river-mk-keymap/Cargo.lock
+++ b/pkgs/by-name/ri/river-mk-keymap/Cargo.lock
@@ -60,9 +60,9 @@ checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f"
 
 [[package]]
 name = "clap"
-version = "4.5.34"
+version = "4.5.35"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e958897981290da2a852763fe9cdb89cd36977a5d729023127095fa94d95e2ff"
+checksum = "d8aa86934b44c19c50f87cc2790e19f54f7a67aedb64101c2e1a2e5ecfb73944"
 dependencies = [
  "clap_builder",
  "clap_derive",
@@ -70,9 +70,9 @@ dependencies = [
 
 [[package]]
 name = "clap_builder"
-version = "4.5.34"
+version = "4.5.35"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "83b0f35019843db2160b5bb19ae09b4e6411ac33fc6a712003c33e03090e2489"
+checksum = "2414dbb2dd0695280da6ea9261e327479e9d37b0630f6b53ba2a11c60c679fd9"
 dependencies = [
  "anstream",
  "anstyle",
diff --git a/pkgs/by-name/ri/river-mk-keymap/Cargo.toml b/pkgs/by-name/ri/river-mk-keymap/Cargo.toml
index f14411f2..19b3cbcb 100644
--- a/pkgs/by-name/ri/river-mk-keymap/Cargo.toml
+++ b/pkgs/by-name/ri/river-mk-keymap/Cargo.toml
@@ -7,7 +7,7 @@ edition = "2021"
 
 [dependencies]
 anyhow = "1.0.97"
-clap = { version = "4.5.34", features = ["derive"] }
+clap = { version = "4.5.35", features = ["derive"] }
 keymaps = { version = "1.0.0", features = ["serde", "mouse-keys"] }
 serde = { version = "1.0.219", features = ["derive"] }
 serde_json = "1.0.140"
diff --git a/pkgs/by-name/ri/river-mk-keymap/flake.lock b/pkgs/by-name/ri/river-mk-keymap/flake.lock
index 82448387..eb3616c8 100644
--- a/pkgs/by-name/ri/river-mk-keymap/flake.lock
+++ b/pkgs/by-name/ri/river-mk-keymap/flake.lock
@@ -2,11 +2,11 @@
   "nodes": {
     "nixpkgs": {
       "locked": {
-        "lastModified": 1743076231,
-        "narHash": "sha256-yQugdVfi316qUfqzN8JMaA2vixl+45GxNm4oUfXlbgw=",
+        "lastModified": 1744096231,
+        "narHash": "sha256-kUfx3FKU1Etnua3EaKvpeuXs7zoFiAcli1gBwkPvGSs=",
         "owner": "NixOS",
         "repo": "nixpkgs",
-        "rev": "6c5963357f3c1c840201eda129a99d455074db04",
+        "rev": "b2b0718004cc9a5bca610326de0a82e6ea75920b",
         "type": "github"
       },
       "original": {
diff --git a/pkgs/by-name/sc/screenshot_temporary/package.nix b/pkgs/by-name/sc/screenshot_temporary/package.nix
index f3739b01..1c45a07b 100644
--- a/pkgs/by-name/sc/screenshot_temporary/package.nix
+++ b/pkgs/by-name/sc/screenshot_temporary/package.nix
@@ -1,15 +1,15 @@
 {
-  sysLib,
+  writeShellApplication,
+  # Dependencies
   grim,
   slurp,
   wl-clipboard,
 }:
-sysLib.writeShellScript {
+writeShellApplication {
   name = "screenshot_temporary";
-  src = ./screenshot_temporary.sh;
-  generateCompletions = false;
-  keepPath = false;
-  dependencies = [
+  text = builtins.readFile ./screenshot_temporary.sh;
+  inheritPath = false;
+  runtimeInputs = [
     grim
     slurp
     wl-clipboard
diff --git a/pkgs/by-name/sc/screenshot_temporary/screenshot_temporary.sh b/pkgs/by-name/sc/screenshot_temporary/screenshot_temporary.sh
index 8968ca79..60a27057 100755
--- a/pkgs/by-name/sc/screenshot_temporary/screenshot_temporary.sh
+++ b/pkgs/by-name/sc/screenshot_temporary/screenshot_temporary.sh
@@ -1,8 +1,5 @@
 #! /usr/bin/env dash
 
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
-
 grim -g "$(slurp)" | wl-copy
 
 # vim: ft=sh
diff --git a/pkgs/by-name/sn/snap-sync-forked/package.nix b/pkgs/by-name/sn/snap-sync-forked/package.nix
index b3f40b24..6e020b60 100644
--- a/pkgs/by-name/sn/snap-sync-forked/package.nix
+++ b/pkgs/by-name/sn/snap-sync-forked/package.nix
@@ -1,5 +1,5 @@
 {
-  sysLib,
+  writeShellApplication,
   bash,
   btrfs-progs,
   coreutils,
@@ -14,10 +14,11 @@
   rsync,
   sudo,
 }:
-sysLib.writeShellScript {
+writeShellApplication {
   name = "snap-sync-forked";
-  src = ./snap-sync-forked.sh;
-  dependencies = [
+  text = builtins.readFile ./snap-sync-forked.sh;
+  inheritPath = false;
+  runtimeInputs = [
     bash
     btrfs-progs
     coreutils
diff --git a/pkgs/by-name/sn/snap-sync-forked/snap-sync-forked.sh b/pkgs/by-name/sn/snap-sync-forked/snap-sync-forked.sh
index 3d9c1ac9..29f14b4f 100755
--- a/pkgs/by-name/sn/snap-sync-forked/snap-sync-forked.sh
+++ b/pkgs/by-name/sn/snap-sync-forked/snap-sync-forked.sh
@@ -1,8 +1,5 @@
 #!/usr/bin/env bash
 
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
-
 #
 # snap-sync
 # https://github.com/wesbarnett/snap-sync
diff --git a/pkgs/by-name/st/stamp/package.nix b/pkgs/by-name/st/stamp/package.nix
index 703f73e3..998268a6 100644
--- a/pkgs/by-name/st/stamp/package.nix
+++ b/pkgs/by-name/st/stamp/package.nix
@@ -1,20 +1,18 @@
 {
-  sysLib,
-  findutils,
+  writeShellApplication,
+  # Dependencies
   fd,
-  reuse,
   git,
+  reuse,
 }:
-sysLib.writeShellScript {
+writeShellApplication {
   name = "stamp";
-  src = ./stamp.sh;
-  generateCompletions = false;
-  keepPath = false;
+  text = builtins.readFile ./stamp.sh;
+  inheritPath = false;
 
-  dependencies = [
-    findutils
+  runtimeInputs = [
     fd
-    reuse
     git
+    reuse
   ];
 }
diff --git a/pkgs/by-name/st/stamp/stamp.sh b/pkgs/by-name/st/stamp/stamp.sh
index 0aa6c281..63b915a0 100755
--- a/pkgs/by-name/st/stamp/stamp.sh
+++ b/pkgs/by-name/st/stamp/stamp.sh
@@ -1,7 +1,9 @@
 #!/usr/bin/env dash
 
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
+die() {
+    echo "Error: $1"
+    exit 1
+}
 
 help() {
     cat <<EOF
diff --git a/pkgs/by-name/ts/tskm/.envrc b/pkgs/by-name/ts/tskm/.envrc
index d21a17fc..a83561cc 100644
--- a/pkgs/by-name/ts/tskm/.envrc
+++ b/pkgs/by-name/ts/tskm/.envrc
@@ -1,8 +1,5 @@
 #!/usr/bin/env sh
 
-SHELL_COMPLETION_DIR="$(pwd)/target/shell"
-export SHELL_COMPLETION_DIR
-
 export TSKM_PROJECT_FILE=/home/soispha/repos/nix/config/modules/common/projects.json
 
 use flake
diff --git a/pkgs/by-name/ts/tskm/Cargo.lock b/pkgs/by-name/ts/tskm/Cargo.lock
index 4a064858..58c4e505 100644
--- a/pkgs/by-name/ts/tskm/Cargo.lock
+++ b/pkgs/by-name/ts/tskm/Cargo.lock
@@ -3,6 +3,24 @@
 version = 4
 
 [[package]]
+name = "adler2"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
+
+[[package]]
+name = "ahash"
+version = "0.8.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+ "version_check",
+ "zerocopy",
+]
+
+[[package]]
 name = "android-tzdata"
 version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -92,10 +110,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
 
 [[package]]
+name = "byteorder"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+
+[[package]]
 name = "cc"
-version = "1.2.17"
+version = "1.2.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a"
+checksum = "525046617d8376e3db1deffb079e91cef90a89fc3ca5c185bbf8c9ecdd15cd5c"
 dependencies = [
  "shlex",
 ]
@@ -116,15 +140,16 @@ dependencies = [
  "iana-time-zone",
  "js-sys",
  "num-traits",
+ "serde",
  "wasm-bindgen",
  "windows-link",
 ]
 
 [[package]]
 name = "clap"
-version = "4.5.34"
+version = "4.5.35"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e958897981290da2a852763fe9cdb89cd36977a5d729023127095fa94d95e2ff"
+checksum = "d8aa86934b44c19c50f87cc2790e19f54f7a67aedb64101c2e1a2e5ecfb73944"
 dependencies = [
  "clap_builder",
  "clap_derive",
@@ -132,9 +157,9 @@ dependencies = [
 
 [[package]]
 name = "clap_builder"
-version = "4.5.34"
+version = "4.5.35"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "83b0f35019843db2160b5bb19ae09b4e6411ac33fc6a712003c33e03090e2489"
+checksum = "2414dbb2dd0695280da6ea9261e327479e9d37b0630f6b53ba2a11c60c679fd9"
 dependencies = [
  "anstream",
  "anstyle",
@@ -149,6 +174,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c06f5378ea264ad4f82bbc826628b5aad714a75abf6ece087e923010eb937fb6"
 dependencies = [
  "clap",
+ "clap_lex",
+ "is_executable",
+ "shlex",
 ]
 
 [[package]]
@@ -182,6 +210,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
 
 [[package]]
+name = "crc32fast"
+version = "1.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
 name = "dirs"
 version = "6.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -214,6 +251,28 @@ dependencies = [
 ]
 
 [[package]]
+name = "fallible-iterator"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"
+
+[[package]]
+name = "fallible-streaming-iterator"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
+
+[[package]]
+name = "flate2"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece"
+dependencies = [
+ "crc32fast",
+ "miniz_oxide",
+]
+
+[[package]]
 name = "form_urlencoded"
 version = "1.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -230,7 +289,37 @@ checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
 dependencies = [
  "cfg-if",
  "libc",
- "wasi",
+ "wasi 0.11.0+wasi-snapshot-preview1",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "r-efi",
+ "wasi 0.14.2+wasi-0.2.4",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.14.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
+dependencies = [
+ "ahash",
+]
+
+[[package]]
+name = "hashlink"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af"
+dependencies = [
+ "hashbrown",
 ]
 
 [[package]]
@@ -247,9 +336,9 @@ checksum = "fbd780fe5cc30f81464441920d82ac8740e2e46b29a6fad543ddd075229ce37e"
 
 [[package]]
 name = "iana-time-zone"
-version = "0.1.62"
+version = "0.1.63"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b2fd658b06e56721792c5df4475705b6cda790e9298d19d2f8af083457bcd127"
+checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8"
 dependencies = [
  "android_system_properties",
  "core-foundation-sys",
@@ -420,6 +509,15 @@ dependencies = [
 ]
 
 [[package]]
+name = "is_executable"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d4a1b5bad6f9072935961dfbf1cced2f3d129963d091b6f69f007fe04e758ae2"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
 name = "is_terminal_polyfill"
 version = "1.70.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -458,6 +556,16 @@ dependencies = [
 ]
 
 [[package]]
+name = "libsqlite3-sys"
+version = "0.30.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149"
+dependencies = [
+ "pkg-config",
+ "vcpkg",
+]
+
+[[package]]
 name = "litemap"
 version = "0.7.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -485,6 +593,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
 
 [[package]]
+name = "miniz_oxide"
+version = "0.8.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
+dependencies = [
+ "adler2",
+]
+
+[[package]]
 name = "num-traits"
 version = "0.2.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -512,6 +629,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
 
 [[package]]
+name = "pkg-config"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
+
+[[package]]
 name = "proc-macro2"
 version = "1.0.94"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -530,17 +653,37 @@ dependencies = [
 ]
 
 [[package]]
+name = "r-efi"
+version = "5.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
+
+[[package]]
 name = "redox_users"
 version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b"
 dependencies = [
- "getrandom",
+ "getrandom 0.2.15",
  "libredox",
  "thiserror",
 ]
 
 [[package]]
+name = "rusqlite"
+version = "0.32.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7753b721174eb8ff87a9a0e799e2d7bc3749323e773db92e0984debb00019d6e"
+dependencies = [
+ "bitflags",
+ "fallible-iterator",
+ "fallible-streaming-iterator",
+ "hashlink",
+ "libsqlite3-sys",
+ "smallvec",
+]
+
+[[package]]
 name = "rustversion"
 version = "1.0.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -601,9 +744,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
 
 [[package]]
 name = "smallvec"
-version = "1.14.0"
+version = "1.15.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd"
+checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9"
 
 [[package]]
 name = "stable_deref_trait"
@@ -637,6 +780,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
 
 [[package]]
+name = "strum"
+version = "0.27.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f64def088c51c9510a8579e3c5d67c65349dcf755e5479ad3d010aa6454e2c32"
+
+[[package]]
+name = "strum_macros"
+version = "0.27.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c77a8c5abcaf0f9ce05d62342b7d298c346515365c36b673df4ebe3ced01fde8"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "rustversion",
+ "syn",
+]
+
+[[package]]
 name = "syn"
 version = "2.0.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -659,6 +821,26 @@ dependencies = [
 ]
 
 [[package]]
+name = "taskchampion"
+version = "2.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b010f5ebe51e88ae490691ed2a43b699e3468c8e3838e244accd8526aca7751b"
+dependencies = [
+ "anyhow",
+ "byteorder",
+ "chrono",
+ "flate2",
+ "log",
+ "rusqlite",
+ "serde",
+ "serde_json",
+ "strum",
+ "strum_macros",
+ "thiserror",
+ "uuid",
+]
+
+[[package]]
 name = "termcolor"
 version = "1.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -720,6 +902,7 @@ dependencies = [
  "serde",
  "serde_json",
  "stderrlog",
+ "taskchampion",
  "url",
  "walkdir",
 ]
@@ -771,6 +954,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
 
 [[package]]
+name = "uuid"
+version = "1.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9"
+dependencies = [
+ "getrandom 0.3.2",
+ "serde",
+]
+
+[[package]]
+name = "vcpkg"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
+
+[[package]]
+name = "version_check"
+version = "0.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
+
+[[package]]
 name = "walkdir"
 version = "2.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -787,6 +992,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
+name = "wasi"
+version = "0.14.2+wasi-0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
+dependencies = [
+ "wit-bindgen-rt",
+]
+
+[[package]]
 name = "wasm-bindgen"
 version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -845,6 +1059,22 @@ dependencies = [
 ]
 
 [[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
 name = "winapi-util"
 version = "0.1.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -854,12 +1084,44 @@ dependencies = [
 ]
 
 [[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
 name = "windows-core"
-version = "0.52.0"
+version = "0.61.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
+checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980"
 dependencies = [
- "windows-targets",
+ "windows-implement",
+ "windows-interface",
+ "windows-link",
+ "windows-result",
+ "windows-strings",
+]
+
+[[package]]
+name = "windows-implement"
+version = "0.60.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "windows-interface"
+version = "0.59.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
 ]
 
 [[package]]
@@ -869,6 +1131,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38"
 
 [[package]]
+name = "windows-result"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "windows-strings"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
 name = "windows-sys"
 version = "0.59.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -942,6 +1222,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
 
 [[package]]
+name = "wit-bindgen-rt"
+version = "0.39.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
 name = "write16"
 version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -978,6 +1267,26 @@ dependencies = [
 ]
 
 [[package]]
+name = "zerocopy"
+version = "0.7.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
+dependencies = [
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.7.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
 name = "zerofrom"
 version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/pkgs/by-name/ts/tskm/Cargo.toml b/pkgs/by-name/ts/tskm/Cargo.toml
index d2990b0c..38c9aab2 100644
--- a/pkgs/by-name/ts/tskm/Cargo.toml
+++ b/pkgs/by-name/ts/tskm/Cargo.toml
@@ -7,13 +7,15 @@ edition = "2021"
 
 [dependencies]
 anyhow = "1.0.97"
-clap = { version = "4.5.34", features = ["derive"] }
+clap = { version = "4.5.35", features = ["derive"] }
+clap_complete = { version = "4.5.47", features = ["unstable-dynamic"] }
 dirs = "6.0.0"
 log = "0.4.27"
 lz4_flex = "0.11.3"
 serde = { version = "1.0.219", features = ["derive"] }
 serde_json = "1.0.140"
 stderrlog = "0.6.0"
+taskchampion = { version = "2.0.3", default-features = false }
 url = { version = "2.5.4", features = ["serde"] }
 walkdir = "2.5.0"
 
@@ -74,14 +76,5 @@ style = { level = "warn", priority = -1 }
 complexity = { level = "warn", priority = -1 }
 perf = { level = "warn", priority = -1 }
 pedantic = { level = "warn", priority = -1 }
-
-[build-dependencies]
-anyhow = "1.0.97"
-clap = { version = "4.5.34", features = ["derive"] }
-clap_complete = "4.5.47"
-dirs = "6.0.0"
-log = "0.4.27"
-serde = { version = "1.0.219", features = ["derive"] }
-serde_json = "1.0.140"
-url = "2.5.4"
-walkdir = "2.5.0"
+missing_panics_doc = "allow"
+missing_errors_doc = "allow"
diff --git a/pkgs/by-name/ts/tskm/build.rs b/pkgs/by-name/ts/tskm/build.rs
deleted file mode 100644
index 8dfb213b..00000000
--- a/pkgs/by-name/ts/tskm/build.rs
+++ /dev/null
@@ -1,49 +0,0 @@
-use anyhow::{Context, Result};
-use clap::{CommandFactory, ValueEnum};
-use clap_complete::generate_to;
-use clap_complete::Shell;
-
-use std::env;
-use std::fs;
-use std::path::PathBuf;
-
-use crate::cli::CliArgs;
-
-pub mod task {
-    include!("src/task/mod.rs");
-}
-
-pub mod interface {
-    pub mod input {
-        include!("src/interface/input/mod.rs");
-    }
-    pub mod project {
-        include!("src/interface/project/mod.rs");
-    }
-}
-
-pub mod cli {
-    include!("src/cli.rs");
-}
-
-fn main() -> Result<()> {
-    let outdir = match env::var_os("SHELL_COMPLETION_DIR") {
-        None => return Ok(()),
-        Some(outdir) => outdir,
-    };
-
-    if !PathBuf::from(&outdir).exists() {
-        fs::create_dir_all(&outdir)?;
-    }
-
-    let mut cmd = CliArgs::command();
-
-    for &shell in Shell::value_variants() {
-        let path = generate_to(shell, &mut cmd, "tskm", &outdir).with_context(|| {
-            format!("Failed to output shell completion for {shell} to {outdir:?}")
-        })?;
-        println!("cargo:warning=completion file for {shell} is generated at: {path:?}");
-    }
-
-    Ok(())
-}
diff --git a/pkgs/by-name/ts/tskm/flake.lock b/pkgs/by-name/ts/tskm/flake.lock
index 82448387..eb3616c8 100644
--- a/pkgs/by-name/ts/tskm/flake.lock
+++ b/pkgs/by-name/ts/tskm/flake.lock
@@ -2,11 +2,11 @@
   "nodes": {
     "nixpkgs": {
       "locked": {
-        "lastModified": 1743076231,
-        "narHash": "sha256-yQugdVfi316qUfqzN8JMaA2vixl+45GxNm4oUfXlbgw=",
+        "lastModified": 1744096231,
+        "narHash": "sha256-kUfx3FKU1Etnua3EaKvpeuXs7zoFiAcli1gBwkPvGSs=",
         "owner": "NixOS",
         "repo": "nixpkgs",
-        "rev": "6c5963357f3c1c840201eda129a99d455074db04",
+        "rev": "b2b0718004cc9a5bca610326de0a82e6ea75920b",
         "type": "github"
       },
       "original": {
diff --git a/pkgs/by-name/ts/tskm/flake.nix b/pkgs/by-name/ts/tskm/flake.nix
index 4b1142d6..5a5f628b 100644
--- a/pkgs/by-name/ts/tskm/flake.nix
+++ b/pkgs/by-name/ts/tskm/flake.nix
@@ -10,6 +10,10 @@
     pkgs = nixpkgs.legacyPackages."${system}";
   in {
     devShells."${system}".default = pkgs.mkShell {
+      buildInputs = [
+        pkgs.sqlite
+      ];
+
       packages = with pkgs; [
         cargo
         clippy
diff --git a/pkgs/by-name/ts/tskm/package.nix b/pkgs/by-name/ts/tskm/package.nix
index a57dc4aa..71ef7ed6 100644
--- a/pkgs/by-name/ts/tskm/package.nix
+++ b/pkgs/by-name/ts/tskm/package.nix
@@ -1,8 +1,16 @@
 {
   rustPlatform,
   installShellFiles,
+  makeWrapper,
+  lib,
+  # Dependencies
+  taskwarrior3,
+  git,
+  rofi,
+  firefox,
+  sqlite,
 }:
-rustPlatform.buildRustPackage {
+rustPlatform.buildRustPackage (finalAttrs: {
   pname = "tskm";
   version = "0.1.0";
 
@@ -11,22 +19,31 @@ rustPlatform.buildRustPackage {
     lockFile = ./Cargo.lock;
   };
 
-  env = {
-    SHELL_COMPLETION_DIR = "./shell";
-  };
+  buildInputs = [
+    taskwarrior3
+    git
+    rofi
+    firefox
+    sqlite
+  ];
 
   nativeBuildInputs = [
     installShellFiles
+    makeWrapper
   ];
 
   postInstall = ''
     installShellCompletion --cmd tskm \
-      --bash ./shell/tskm.bash \
-      --fish ./shell/tskm.fish \
-      --zsh ./shell/_tskm
+      --bash <(COMPLETE=bash $out/bin/tskm) \
+      --fish <(COMPLETE=fish $out/bin/tskm) \
+      --zsh <(COMPLETE=zsh $out/bin/tskm)
+
+    # NOTE: We cannot clear the path, because we need access to the $EDITOR. <2025-04-04>
+    wrapProgram $out/bin/tskm \
+      --prefix PATH : ${lib.makeBinPath finalAttrs.buildInputs}
   '';
 
   meta = {
     mainProgram = "tskm";
   };
-}
+})
diff --git a/pkgs/by-name/ts/tskm/src/cli.rs b/pkgs/by-name/ts/tskm/src/cli.rs
index bf0af7fb..c1eba387 100644
--- a/pkgs/by-name/ts/tskm/src/cli.rs
+++ b/pkgs/by-name/ts/tskm/src/cli.rs
@@ -1,10 +1,13 @@
-use std::path::PathBuf;
+use std::{ffi::OsStr, path::PathBuf};
 
-use clap::{Parser, Subcommand};
+use anyhow::{bail, Result};
+use clap::{builder::StyledStr, ArgAction, Parser, Subcommand};
+use clap_complete::{ArgValueCompleter, CompletionCandidate};
+use url::Url;
 
 use crate::{
     interface::{input::Input, project::ProjectName},
-    task,
+    state, task,
 };
 
 #[derive(Parser, Debug)]
@@ -14,13 +17,23 @@ use crate::{
 /// `tskm` effectively combines multiple applications together:
 /// - `taskwarrior` projects are raised connected to `firefox` profiles, making it possible to “open”
 ///   a project.
+///
 /// - Every `taskwarrior` project has a determined `neorg` path, so that extra information for a
 ///   `project` can be stored in this `norg` file.
+///
 /// - `tskm` can track inputs for you. These are URLs with optional tags which you can that
 ///   “review” to open tasks based on them.
 pub struct CliArgs {
     #[command(subcommand)]
     pub command: Command,
+
+    /// Increase message verbosity
+    #[arg(long="verbose", short = 'v', action = ArgAction::Count, default_value_t = 2)]
+    pub verbosity: u8,
+
+    /// Silence all output
+    #[arg(long, short = 'q')]
+    pub quiet: bool,
 }
 
 #[derive(Subcommand, Debug)]
@@ -66,7 +79,21 @@ pub enum ProjectCommand {
 #[derive(Subcommand, Debug, Clone, Copy)]
 pub enum NeorgCommand {
     /// Open the `neorg` project associated with id of the task.
-    Task { id: task::Id },
+    Task {
+        /// The working set id of the task
+        #[arg(value_parser = task_from_working_set_id, add = ArgValueCompleter::new(complete_task_id))]
+        id: task::Task,
+    },
+}
+
+fn task_from_working_set_id(id: &str) -> Result<task::Task> {
+    let id: usize = id.parse()?;
+    let mut state = state::State::new_ro()?;
+
+    let Some(task) = task::Task::from_working_set(id, &mut state)? else {
+        bail!("Working set id '{id}' is not valid!")
+    };
+    Ok(task)
 }
 
 #[derive(Subcommand, Debug)]
@@ -79,22 +106,28 @@ pub enum OpenCommand {
     /// Opens Firefox with either the supplied project or the currently active project profile.
     Project {
         /// The project to open.
-        #[arg(value_parser = task::Project::from_project_string)]
-        project: Option<task::Project>,
+        #[arg(value_parser = task::Project::from_project_string, add = ArgValueCompleter::new(complete_project))]
+        project: task::Project,
+
+        /// The URL to open.
+        url: Option<Url>,
     },
 
     /// Open a selected project in it's Firefox profile.
     ///
     /// This will use rofi's dmenu mode to select one project from the list of all registered
     /// projects.
-    Select,
+    Select {
+        /// The URL to open.
+        url: Option<Url>,
+    },
 
     /// List all open tabs in the project.
     ListTabs {
         /// The project to open.
-        #[arg(value_parser = task::Project::from_project_string)]
+        #[arg(value_parser = task::Project::from_project_string, add = ArgValueCompleter::new(complete_project))]
         project: Option<task::Project>,
-    }
+    },
 }
 
 #[derive(Subcommand, Debug)]
@@ -102,7 +135,10 @@ pub enum InputCommand {
     /// Add URLs as inputs to be categorized.
     Add { inputs: Vec<Input> },
     /// Remove URLs
-    Remove { inputs: Vec<Input> },
+    Remove {
+        #[arg(add = ArgValueCompleter::new(complete_input_url))]
+        inputs: Vec<Input>,
+    },
 
     /// Add all URLs in the file as inputs to be categorized.
     ///
@@ -113,10 +149,118 @@ pub enum InputCommand {
     /// It takes a project in which to open the URLs.
     Review {
         /// Opens all the URLs in this project.
-        #[arg(value_parser = task::Project::from_project_string)]
+        #[arg(value_parser = task::Project::from_project_string, add = ArgValueCompleter::new(complete_project))]
         project: task::Project,
     },
 
     /// List all the previously added inputs.
     List,
 }
+
+fn complete_task_id(current: &OsStr) -> Vec<CompletionCandidate> {
+    fn format_task(
+        task: task::Task,
+        current: &str,
+        state: &mut state::State,
+    ) -> Option<CompletionCandidate> {
+        let id = {
+            let Ok(base) = task.working_set_id(state) else {
+                return None;
+            };
+            base.to_string()
+        };
+
+        if !id.starts_with(current) {
+            return None;
+        }
+
+        let description = {
+            let Ok(base) = task.description(state) else {
+                return None;
+            };
+            StyledStr::from(base)
+        };
+
+        Some(CompletionCandidate::new(id).help(Some(description)))
+    }
+
+    let mut output = vec![];
+
+    let Some(current) = current.to_str() else {
+        return output;
+    };
+
+    let Ok(mut state) = state::State::new_ro() else {
+        return output;
+    };
+
+    let Ok(pending) = state.replica().pending_tasks() else {
+        return output;
+    };
+
+    let Ok(current_project) = task::Project::get_current() else {
+        return output;
+    };
+
+    if let Some(current_project) = current_project {
+        for t in pending {
+            let task = task::Task::from(&t);
+            if let Ok(project) = task.project(&mut state) {
+                if project == current_project {
+                    if let Some(out) = format_task(task, current, &mut state) {
+                        output.push(out);
+                    } else {
+                        continue;
+                    }
+                }
+            }
+        }
+    } else {
+        for t in pending {
+            let task = task::Task::from(&t);
+            if let Some(out) = format_task(task, current, &mut state) {
+                output.push(out);
+            }
+        }
+    }
+
+    output
+}
+fn complete_project(current: &OsStr) -> Vec<CompletionCandidate> {
+    let mut output = vec![];
+
+    let Some(current) = current.to_str() else {
+        return output;
+    };
+
+    let Ok(all) = task::Project::all() else {
+        return output;
+    };
+
+    for a in all {
+        if a.to_project_display().starts_with(current) {
+            output.push(CompletionCandidate::new(a.to_project_display()));
+        }
+    }
+
+    output
+}
+fn complete_input_url(current: &OsStr) -> Vec<CompletionCandidate> {
+    let mut output = vec![];
+
+    let Some(current) = current.to_str() else {
+        return output;
+    };
+
+    let Ok(all) = Input::all() else {
+        return output;
+    };
+
+    for a in all {
+        if a.to_string().starts_with(current) {
+            output.push(CompletionCandidate::new(a.to_string()));
+        }
+    }
+
+    output
+}
diff --git a/pkgs/by-name/ts/tskm/src/interface/neorg/handle.rs b/pkgs/by-name/ts/tskm/src/interface/neorg/handle.rs
index a9a46ee7..d904b12e 100644
--- a/pkgs/by-name/ts/tskm/src/interface/neorg/handle.rs
+++ b/pkgs/by-name/ts/tskm/src/interface/neorg/handle.rs
@@ -1,33 +1,46 @@
 use std::{
     env,
-    fs::{self, read_to_string, OpenOptions},
+    fs::{self, read_to_string, File, OpenOptions},
     io::Write,
     process::Command,
 };
 
-use anyhow::{bail, Result};
+use anyhow::{bail, Context, Result};
 
-use crate::cli::NeorgCommand;
+use crate::{cli::NeorgCommand, state::State};
 
-pub fn handle(command: NeorgCommand) -> Result<()> {
+pub fn handle(command: NeorgCommand, state: &mut State) -> Result<()> {
     match command {
         NeorgCommand::Task { id } => {
-            let project = id.project()?;
-            let path = dirs::data_local_dir()
+            let project = id.project(state)?;
+            let base = dirs::data_local_dir()
                 .expect("This should exists")
-                .join("notes")
-                .join(project.get_neorg_path()?);
+                .join("tskm/notes");
+            let path = base.join(project.get_neorg_path()?);
 
             fs::create_dir_all(path.parent().expect("This should exist"))?;
 
             {
-                let contents = read_to_string(&path)?;
-                if contents.contains(format!("% {}", id.to_uuid()?).as_str()) {
+                let contents = if path.exists() {
+                    read_to_string(&path)
+                        .with_context(|| format!("Failed to read file: '{}'", path.display()))?
+                } else {
+                    File::create(&path)
+                        .with_context(|| format!("Failed to create file: '{}'", path.display()))?;
+                    String::new()
+                };
+
+                if !contents.contains(format!("% {}", id.uuid()).as_str()) {
                     let mut options = OpenOptions::new();
-                    options.append(true).create(true);
+                    options.append(true).create(false);
 
                     let mut file = options.open(&path)?;
-                    file.write_all(format!("* TITLE (% {})", id.to_uuid()?).as_bytes())?;
+                    file.write_all(format!("* TITLE (% {})", id.uuid()).as_bytes())
+                        .with_context(|| {
+                            format!("Failed to write task uuid to file: '{}'", path.display())
+                        })?;
+                    file.flush()
+                        .with_context(|| format!("Failed to flush file: '{}'", path.display()))?;
                 }
             }
 
@@ -36,7 +49,7 @@ pub fn handle(command: NeorgCommand) -> Result<()> {
                 .args([
                     path.to_str().expect("Should be a utf-8 str"),
                     "-c",
-                    format!("/% {}", id.to_uuid()?).as_str(),
+                    format!("/% {}", id.uuid()).as_str(),
                 ])
                 .status()?;
             if !status.success() {
@@ -46,7 +59,7 @@ pub fn handle(command: NeorgCommand) -> Result<()> {
             {
                 let status = Command::new("git")
                     .args(["add", "."])
-                    .current_dir(&path)
+                    .current_dir(path.parent().expect("Will exist"))
                     .status()?;
                 if !status.success() {
                     bail!("Git add . failed!");
@@ -56,14 +69,10 @@ pub fn handle(command: NeorgCommand) -> Result<()> {
                     .args([
                         "commit",
                         "--message",
-                        format!(
-                            "chore({}): Update",
-                            path.parent().expect("Should have a parent").display()
-                        )
-                        .as_str(),
+                        format!("chore({}): Update", project.get_neorg_path()?.display()).as_str(),
                         "--no-gpg-sign",
                     ])
-                    .current_dir(&path)
+                    .current_dir(path.parent().expect("Will exist"))
                     .status()?;
                 if !status.success() {
                     bail!("Git commit failed!");
@@ -71,7 +80,7 @@ pub fn handle(command: NeorgCommand) -> Result<()> {
             }
 
             {
-                id.annotate("[neorg data]")?;
+                id.mark_neorg_data(state)?;
             }
         }
     }
diff --git a/pkgs/by-name/ts/tskm/src/interface/neorg/mod.rs b/pkgs/by-name/ts/tskm/src/interface/neorg/mod.rs
index dc5cdf19..51d58ab3 100644
--- a/pkgs/by-name/ts/tskm/src/interface/neorg/mod.rs
+++ b/pkgs/by-name/ts/tskm/src/interface/neorg/mod.rs
@@ -8,11 +8,18 @@ pub mod handle;
 pub use handle::handle;
 
 impl Project {
+    /// Return the stored neorg path of this project.
+    /// The returned path will never start with a slash (/).
     pub(super) fn get_neorg_path(&self) -> Result<PathBuf> {
         let project_path = run_task(&[
             "_get",
             format!("rc.context.{}.rc.neorg_path", self.to_context_display()).as_str(),
         ])?;
-        Ok(PathBuf::from(project_path.as_str()))
+
+        let final_path = project_path
+            .strip_prefix('/')
+            .unwrap_or(project_path.as_str());
+
+        Ok(PathBuf::from(final_path))
     }
 }
diff --git a/pkgs/by-name/ts/tskm/src/interface/open/handle.rs b/pkgs/by-name/ts/tskm/src/interface/open/handle.rs
index dc0d165d..4d7341b2 100644
--- a/pkgs/by-name/ts/tskm/src/interface/open/handle.rs
+++ b/pkgs/by-name/ts/tskm/src/interface/open/handle.rs
@@ -1,17 +1,23 @@
-use std::process;
+use std::{
+    fs,
+    net::{IpAddr, Ipv4Addr},
+    path::PathBuf,
+    process,
+};
 
 use anyhow::{bail, Context, Result};
-use log::{error, info};
+use log::{error, info, warn};
+use url::Url;
 
-use crate::{cli::OpenCommand, rofi, task};
+use crate::{cli::OpenCommand, rofi, state::State, task};
 
-pub fn handle(command: OpenCommand) -> Result<()> {
+pub fn handle(command: OpenCommand, state: &mut State) -> Result<()> {
     match command {
         OpenCommand::Review => {
             for project in task::Project::all().context("Failed to get all project files")? {
                 if project.is_touched() {
                     info!("Reviewing project: '{}'", project.to_project_display());
-                    open_in_browser(project).with_context(|| {
+                    open_in_browser(project, state, None).with_context(|| {
                         format!(
                             "Failed to open project ('{}') in Firefox",
                             project.to_project_display()
@@ -26,23 +32,13 @@ pub fn handle(command: OpenCommand) -> Result<()> {
                 }
             }
         }
-        OpenCommand::Project { project } => {
-            let project = if let Some(p) = project {
-                p
-            } else if let Some(p) =
-                task::Project::get_current().context("Failed to get currently focused project")?
-            {
-                p
-            } else {
-                bail!("You need to either supply a project or have a project active!");
-            };
-
+        OpenCommand::Project { project, url } => {
             project.touch().context("Failed to touch project")?;
-            open_in_browser(&project).with_context(|| {
+            open_in_browser(&project, state, url).with_context(|| {
                 format!("Failed to open project: {}", project.to_project_display())
             })?;
         }
-        OpenCommand::Select => {
+        OpenCommand::Select { url } => {
             let selected_project: task::Project = task::Project::from_project_string(
                 &rofi::select(
                     task::Project::all()
@@ -60,7 +56,7 @@ pub fn handle(command: OpenCommand) -> Result<()> {
                 .touch()
                 .context("Failed to touch project")?;
 
-            open_in_browser(&selected_project).context("Failed to open project")?;
+            open_in_browser(&selected_project, state, url).context("Failed to open project")?;
         }
         OpenCommand::ListTabs { project } => {
             let project = if let Some(p) = project {
@@ -109,12 +105,15 @@ pub fn handle(command: OpenCommand) -> Result<()> {
     Ok(())
 }
 
-fn open_in_browser(selected_project: &task::Project) -> Result<()> {
+fn open_in_browser(
+    selected_project: &task::Project,
+    state: &mut State,
+    url: Option<Url>,
+) -> Result<()> {
     let old_project: Option<task::Project> =
         task::Project::get_current().context("Failed to get currently active project")?;
-    // We have ensured that only one task may be active
-    let old_task: Option<task::Id> =
-        task::Id::get_current().context("Failed to get currently active task")?;
+    let old_task: Option<task::Task> =
+        task::Task::get_current(state).context("Failed to get currently active task")?;
 
     selected_project.activate().with_context(|| {
         format!(
@@ -124,7 +123,7 @@ fn open_in_browser(selected_project: &task::Project) -> Result<()> {
     })?;
 
     let tracking_task = {
-        let all_tasks = selected_project.get_tasks().with_context(|| {
+        let all_tasks = selected_project.get_tasks(state).with_context(|| {
             format!(
                 "Failed to get assoctiated tasks for project: '{}'",
                 selected_project.to_project_display()
@@ -132,7 +131,7 @@ fn open_in_browser(selected_project: &task::Project) -> Result<()> {
         })?;
 
         let tracking_task = all_tasks.into_iter().find(|t| {
-            let maybe_desc = t.description();
+            let maybe_desc = t.description(state);
             if let Ok(desc) = maybe_desc {
                 desc == "tracking"
             } else {
@@ -149,31 +148,75 @@ fn open_in_browser(selected_project: &task::Project) -> Result<()> {
                 "Starting task {} -> tracking",
                 selected_project.to_project_display()
             );
-            task.start()
+            task.start(state)
                 .with_context(|| format!("Failed to start task {task}"))?;
         }
         tracking_task
     };
 
-    let status = process::Command::new("firefox")
-        .args([
-            "-P",
-            selected_project.to_project_display().as_str(),
-            "about:newtab",
-        ])
-        .status()
-        .context("Failed to start firefox")?;
+    let status = {
+        let mut args = vec!["-P".to_owned(), selected_project.to_project_display()];
+        if let Some(url) = url {
+            args.push(url.to_string());
+        } else {
+            let lock_file = dirs::home_dir()
+                .expect("Exists")
+                .join(".mozilla/firefox")
+                .join(selected_project.to_project_display())
+                .join("lock");
+
+            if lock_file.exists() {
+                let (ip, pid): (IpAddr, u32) = {
+                    let link = fs::read_link(&lock_file).with_context(|| {
+                        format!("Failed to readlink lock at '{}'", lock_file.display())
+                    })?;
+
+                    let (ip, pid) = link
+                        .to_str()
+                        .expect("Should work")
+                        .split_once(':')
+                        .expect("The split works");
+
+                    (
+                        ip.parse().expect("Should be a valid ip address"),
+                        pid.parse().expect("Should be a valid pid"),
+                    )
+                };
+
+                if ip != Ipv4Addr::new(127, 0, 0, 2) {
+                    warn!("Your ip is weird..");
+                }
+
+                if PathBuf::from("/proc").join(pid.to_string()).exists() {
+                    // Another Firefox instance has already been started for this project
+                    // Add a buffer URL to force Firefox to open it in the already open instance
+                    args.push("about:newtab".to_owned());
+                } else {
+                    // This project does not yet have another Firefox instance
+                    // We do not need to add anything to the arguments, Firefox will open a new
+                    // instance.
+                }
+            } else {
+                // There is no lock file and thus no instance already open.
+            }
+        };
+
+        process::Command::new("firefox")
+            .args(args)
+            .status()
+            .context("Failed to start firefox")?
+    };
 
     if !status.success() {
         error!("Firefox run exited with error.");
     }
 
     if let Some(task) = tracking_task {
-        task.stop()
+        task.stop(state)
             .with_context(|| format!("Failed to stop task {task}"))?;
     }
     if let Some(task) = old_task {
-        task.start()
+        task.start(state)
             .with_context(|| format!("Failed to start task {task}"))?;
     }
 
diff --git a/pkgs/by-name/ts/tskm/src/main.rs b/pkgs/by-name/ts/tskm/src/main.rs
index 7fc9c0d4..77f2dcca 100644
--- a/pkgs/by-name/ts/tskm/src/main.rs
+++ b/pkgs/by-name/ts/tskm/src/main.rs
@@ -1,64 +1,39 @@
-#![allow(clippy::missing_panics_doc)]
-#![allow(clippy::missing_errors_doc)]
-
 use anyhow::Result;
-use clap::Parser;
+use clap::{CommandFactory, Parser};
 
-use crate::interface::{input, neorg, open, project};
+use crate::{
+    cli::{CliArgs, Command},
+    interface::{input, neorg, open, project},
+    state::State,
+};
 
 pub mod cli;
 pub mod interface;
 pub mod rofi;
+pub mod state;
 pub mod task;
 
-use crate::cli::{CliArgs, Command};
-
 fn main() -> Result<(), anyhow::Error> {
-    // TODO: Support these completions for the respective types <2025-04-04>
-    //
-    // ID_GENERATION_FUNCTION
-    // ```sh
-    //  context="$(task _get rc.context)"
-    //  if [ "$context" ]; then
-    //      filter="project:$context"
-    //  else
-    //      filter="0-10000"
-    //  fi
-    //  tasks="$(task "$filter" _ids)"
-    //
-    //  if [ "$tasks" ]; then
-    //      echo "$tasks" | xargs task _zshids | awk -F: -v q="'" '{gsub(/'\''/, q "\\" q q ); print $1 ":" q $2 q}'
-    //  fi
-    // ```
-    //
-    // ARGUMENTS:
-    //     ID | *([0-9]) := [[%ID_GENERATION_FUNCTION]]
-    //                             The function displays all possible IDs of the eligible tasks.
-    //
-    //     WS := %ALL_WORKSPACES
-    //                             All possible workspaces.
-    //
-    //     P := %ALL_PROJECTS_PIPE
-    //                             The possible project.
-    //
-    //     F := [[fd . --max-depth 3]]
-    //                             A URL-Input file to use as source.
+    clap_complete::CompleteEnv::with_factory(CliArgs::command).complete();
+
     let args = CliArgs::parse();
 
     stderrlog::new()
         .module(module_path!())
-        .quiet(false)
+        .quiet(args.quiet)
         .show_module_names(true)
         .color(stderrlog::ColorChoice::Auto)
-        .verbosity(5)
+        .verbosity(usize::from(args.verbosity))
         .timestamp(stderrlog::Timestamp::Off)
         .init()
         .expect("Let's just hope that this does not panic");
 
+    let mut state = State::new_rw()?;
+
     match args.command {
         Command::Inputs { command } => input::handle(command)?,
-        Command::Neorg { command } => neorg::handle(command)?,
-        Command::Open { command } => open::handle(command)?,
+        Command::Neorg { command } => neorg::handle(command, &mut state)?,
+        Command::Open { command } => open::handle(command, &mut state)?,
         Command::Projects { command } => project::handle(command)?,
     }
 
diff --git a/pkgs/by-name/ts/tskm/src/state.rs b/pkgs/by-name/ts/tskm/src/state.rs
new file mode 100644
index 00000000..175a7f03
--- /dev/null
+++ b/pkgs/by-name/ts/tskm/src/state.rs
@@ -0,0 +1,45 @@
+use std::path::PathBuf;
+
+use anyhow::Result;
+use taskchampion::{storage::AccessMode, Replica, StorageConfig};
+
+pub struct State {
+    replica: Replica,
+}
+
+impl std::fmt::Debug for State {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "State")
+    }
+}
+
+impl State {
+    fn taskdb_dir() -> PathBuf {
+        dirs::data_local_dir().expect("Should exist").join("task")
+    }
+
+    fn new(taskdb_dir: PathBuf, access_mode: AccessMode) -> Result<Self> {
+        let storage = StorageConfig::OnDisk {
+            taskdb_dir,
+            create_if_missing: false,
+            access_mode,
+        }
+        .into_storage()?;
+
+        let replica = Replica::new(storage);
+
+        Ok(Self { replica })
+    }
+
+    pub fn new_ro() -> Result<Self> {
+        Self::new(Self::taskdb_dir(), AccessMode::ReadOnly)
+    }
+    pub fn new_rw() -> Result<Self> {
+        Self::new(Self::taskdb_dir(), AccessMode::ReadWrite)
+    }
+
+    #[must_use]
+    pub fn replica(&mut self) -> &mut Replica {
+        &mut self.replica
+    }
+}
diff --git a/pkgs/by-name/ts/tskm/src/task/mod.rs b/pkgs/by-name/ts/tskm/src/task/mod.rs
index c3a6d614..989f273a 100644
--- a/pkgs/by-name/ts/tskm/src/task/mod.rs
+++ b/pkgs/by-name/ts/tskm/src/task/mod.rs
@@ -9,109 +9,144 @@ use std::{
 
 use anyhow::{bail, Context, Result};
 use log::{debug, info, trace};
+use taskchampion::Tag;
 
-use crate::interface::project::ProjectName;
+use crate::{interface::project::ProjectName, state::State};
 
 /// The `taskwarrior` id of a task.
 #[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Ord, Eq)]
-pub struct Id {
-    id: u64,
+pub struct Task {
+    uuid: taskchampion::Uuid,
 }
-impl Id {
-    /// # Errors
-    /// When `task` execution fails
-    pub fn get_current() -> Result<Option<Self>> {
-        // We have ensured that only one task may be active
-        let self_str = run_task(&["+ACTIVE", "_ids"])?;
 
-        if self_str.is_empty() {
-            Ok(None)
+impl From<&taskchampion::Task> for Task {
+    fn from(value: &taskchampion::Task) -> Self {
+        Self {
+            uuid: value.get_uuid(),
+        }
+    }
+}
+impl From<&taskchampion::TaskData> for Task {
+    fn from(value: &taskchampion::TaskData) -> Self {
+        Self {
+            uuid: value.get_uuid(),
+        }
+    }
+}
+
+impl Task {
+    pub fn from_working_set(id: usize, state: &mut State) -> Result<Option<Self>> {
+        Ok(state
+            .replica()
+            .working_set()?
+            .by_index(id)
+            .map(|uuid| Self { uuid }))
+    }
+
+    pub fn get_current(state: &mut State) -> Result<Option<Self>> {
+        let tasks = state
+            .replica()
+            .pending_tasks()?
+            .into_iter()
+            .filter(taskchampion::Task::is_active)
+            .collect::<Vec<_>>();
+
+        assert!(
+            tasks.len() <= 1,
+            "We have ensured that only one task may be active, via a hook"
+        );
+        if let Some(active) = tasks.first() {
+            Ok(Some(Self::from(active)))
         } else {
-            Self::from_str(&self_str).map(Some)
+            Ok(None)
         }
     }
 
-    /// # Errors
-    /// When `task` execution fails
-    pub fn to_uuid(&self) -> Result<String> {
-        let uuid = run_task(&[self.to_string().as_str(), "uuids"])?;
+    #[must_use]
+    pub fn uuid(&self) -> &taskchampion::Uuid {
+        &self.uuid
+    }
+    #[must_use]
+    pub fn working_set_id(&self, state: &mut State) -> Result<usize> {
+        Ok(state
+            .replica()
+            .working_set()?
+            .by_uuid(self.uuid)
+            .expect("The task should be in the working set"))
+    }
 
-        Ok(uuid)
+    fn as_task(&self, state: &mut State) -> Result<taskchampion::Task> {
+        Ok(state
+            .replica()
+            .get_task(self.uuid)?
+            .expect("We have the task from this replica, it should still be in it"))
     }
 
-    /// # Panics
-    /// When internal assertions fail.
-    /// # Errors
-    /// When `task` execution fails
-    pub fn annotate(&self, message: &str) -> Result<()> {
-        run_task(&["annotate", self.to_string().as_str(), "--", message])?;
+    /// Adds a tag to the task, to show the user that it has additional neorg data.
+    pub fn mark_neorg_data(&self, state: &mut State) -> Result<()> {
+        let mut ops = vec![];
+        self.as_task(state)?
+            .add_tag(&Tag::from_str("neorg_data").expect("Is valid"), &mut ops)?;
+        state.replica().commit_operations(ops)?;
         Ok(())
     }
 
-    /// # Panics
-    /// When internal assertions fail.
-    /// # Errors
-    /// When `task` execution fails
-    pub fn start(&self) -> Result<()> {
+    /// Try to start this task.
+    /// It will stop previously active tasks.
+    pub fn start(&self, state: &mut State) -> Result<()> {
         info!("Activating {self}");
 
-        let output = run_task(&["start", self.to_string().as_str()])?;
-        assert!(output.is_empty());
+        if let Some(active) = Self::get_current(state)? {
+            active.stop(state)?;
+        }
+
+        let mut ops = vec![];
+        self.as_task(state)?.start(&mut ops)?;
+        state.replica().commit_operations(ops)?;
         Ok(())
     }
-    /// # Panics
-    /// When internal assertions fail.
-    /// # Errors
-    /// When `task` execution fails
-    pub fn stop(&self) -> Result<()> {
+
+    /// Stops this task.
+    pub fn stop(&self, state: &mut State) -> Result<()> {
         info!("Stopping {self}");
 
-        let output = run_task(&["stop", self.to_string().as_str()])?;
-        assert!(output.is_empty());
+        let mut ops = vec![];
+        self.as_task(state)?.stop(&mut ops)?;
+        state.replica().commit_operations(ops)?;
         Ok(())
     }
 
-    /// # Panics
-    /// When internal assertions fail.
-    /// # Errors
-    /// When `task` execution fails
-    pub fn description(&self) -> Result<String> {
-        let output = run_task(&["rc.context=none", "_zshids", self.to_string().as_str()])?;
-        let (id, desc) = output
-            .split_once(':')
-            .expect("The output should always contain one colon");
-        assert_eq!(id.parse::<Id>().expect("This should be a valid id"), *self);
-        Ok(desc.to_owned())
+    pub fn description(&self, state: &mut State) -> Result<String> {
+        Ok(self.as_task(state)?.get_description().to_owned())
     }
 
-    /// # Panics
-    /// When internal assertions fail.
-    /// # Errors
-    /// When `task` execution fails
-    pub fn project(&self) -> Result<Project> {
-        let output = run_task(&[
-            "rc.context=none",
-            "_get",
-            format!("{self}.project").as_str(),
-        ])?;
-        let project = Project::from_project_string(output.as_str())
+    pub fn project(&self, state: &mut State) -> Result<Project> {
+        let output = {
+            let task = self.as_task(state)?;
+            let task_data = task.into_task_data();
+            task_data
+                .get("project")
+                .expect("Every task should have a project")
+                .to_owned()
+        };
+        let project = Project::from_project_string(output.as_str().trim())
             .expect("This comes from tw, it should be valid");
         Ok(project)
     }
 }
 
-impl Display for Id {
+impl Display for Task {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        self.id.fmt(f)
+        self.uuid.fmt(f)
     }
 }
 
-impl FromStr for Id {
+impl FromStr for Task {
     type Err = anyhow::Error;
 
     fn from_str(s: &str) -> Result<Self, Self::Err> {
-        let id = u64::from_str(s)?;
-        Ok(Self { id })
+        let uuid = taskchampion::Uuid::from_str(s)?;
+        Ok(Self { uuid })
     }
 }
 
@@ -259,21 +294,14 @@ impl Project {
 
     /// # Errors
     /// When `task` execution fails.
-    pub fn get_tasks(&self) -> Result<Vec<Id>> {
-        let output = run_task(&[
-            "rc.context=none",
-            format!("project:{}", self.to_project_display()).as_str(),
-            "_ids",
-        ])?;
-
-        if output.is_empty() {
-            Ok(vec![])
-        } else {
-            output
-                .lines()
-                .map(Id::from_str)
-                .collect::<Result<Vec<Id>>>()
-        }
+    pub fn get_tasks(&self, state: &mut State) -> Result<Vec<Task>> {
+        Ok(state
+            .replica()
+            .pending_task_data()?
+            .into_iter()
+            .filter(|t| t.get("project").expect("Is set") == self.to_project_display())
+            .map(|t| Task::from(&t))
+            .collect())
     }
 
     /// # Errors
diff --git a/pkgs/by-name/up/update-sys/update-sys.sh b/pkgs/by-name/up/update-sys/update-sys.sh
deleted file mode 100755
index d28247f6..00000000
--- a/pkgs/by-name/up/update-sys/update-sys.sh
+++ /dev/null
@@ -1,85 +0,0 @@
-#!/usr/bin/env dash
-
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
-
-help() {
-    cat <<EOF
-This is a NixOS System flake update manager.
-
-USAGE:
-    $NAME [--branch <branchname>] [--help]
-
-OPTIONS:
-    --branch | -b  BRANCHNAME
-                                select a branch to update from.
-
-    --mode   | -m  MODE
-                                select a mode to update with
-
-    --help   | -h
-                                output this help.
-ARGUMENTS:
-    BRANCHNAME := [[ git branch --list --format '%(refname:short)' ]]
-                                The name of the branch to deploy the config from
-
-    MODE := switch|boot|test|build|dry-build|dry-activate|edit|repl|build-vm|build-vm-with-bootloader
-                                See the 'nixos-rebuild' manpage for more information about these modes.
-EOF
-    exit "$1"
-}
-default_branch=$(mktmp)
-BRANCH=""
-
-while [ "$#" -gt 0 ]; do
-    case "$1" in
-    "--help" | "-h")
-        help 0
-        ;;
-    "--branch" | "-b")
-        if [ -n "$2" ]; then
-            BRANCH="$2"
-        else
-            error "$1 requires an argument"
-            help 1
-        fi
-        shift 2
-        ;;
-    "--mode" | "-m")
-        if [ -n "$2" ]; then
-            MODE="$2"
-        else
-            error "$1 requires an argument"
-            help 1
-        fi
-        shift 2
-        ;;
-    *)
-        error "the option $1 does not exist!"
-        help 1
-        ;;
-    esac
-done
-
-cd /etc/nixos || die "No /etc/nixos"
-msg "Starting system update..."
-git remote update origin --prune >/dev/null 2>&1
-if ! [ "$BRANCH" = "" ]; then
-    git switch "$BRANCH" >/dev/null 2>&1 && msg2 "Switched to branch '$BRANCH'"
-fi
-msg2 "Updating git repository..."
-git pull --rebase
-
-git remote show origin | grep 'HEAD' | cut -d':' -f2 | sed -e 's/^ *//g' -e 's/ *$//g' >"$default_branch" &
-
-msg2 "Updating system..."
-if [ -n "$MODE" ]; then
-    nixos-rebuild "$MODE"
-else
-    nixos-rebuild switch
-fi
-
-git switch "$(cat "$default_branch")" >/dev/null 2>&1 && msg2 "Switched to branch '$(cat "$default_branch")'"
-msg "Finished Update!"
-
-# vim: ft=sh
diff --git a/pkgs/default.nix b/pkgs/default.nix
index 41bb654f..dfef2b60 100644
--- a/pkgs/default.nix
+++ b/pkgs/default.nix
@@ -1,21 +1,10 @@
 {
   pkgs,
-  sysLib,
   nixLib,
 }: let
   inherit (pkgs) lib;
 
-  maybeMergeMessage = "the ./pkgs/by-name set";
-  mMM = maybeMergeMessage;
-  callPackage =
-    lib.callPackageWith
-    (nixLib.warnMerge
-      (nixLib.warnMerge
-        pkgs
-        myPkgs
-        mMM)
-      {inherit sysLib;}
-      mMM);
+  callPackage = lib.callPackageWith (nixLib.warnMerge pkgs myPkgs "the ./pkgs/by-name set");
 
   myPkgs = nixLib.mkByName {
     baseDirectory = ./by-name;
diff --git a/update.sh b/update.sh
index b4408bea..3a8c7cb1 100755
--- a/update.sh
+++ b/update.sh
@@ -13,6 +13,9 @@ __update_sh_run() {
 __update_sh_run ./modules/by-name/fi/firefox/update_extensions.sh "$@"
 __update_sh_run ./pkgs/update_pkgs.sh "$@"
 
-echo "Also update out-of tree dependencies, like yt!" 2>&1
+__update_sh_run nix flake check
+__update_sh_run ./build.sh
+
+printf "\033[31;1m%s\033[0m\033[33;1m%s\033[0m\n" "Also update out-of-tree dependencies, like " "yt" 2>&1
 
 # vim: ft=sh