about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--README.md10
-rw-r--r--corp/rih/frontend/Cargo.lock25
-rw-r--r--corp/rih/frontend/Cargo.toml2
-rw-r--r--corp/russian/predlozhnik/Cargo.lock35
-rw-r--r--corp/russian/predlozhnik/Cargo.toml2
-rw-r--r--default.nix10
-rw-r--r--ops/glesys/dns-tvix-dev.tf8
-rw-r--r--ops/glesys/dns-tvl-fyi.tf46
-rw-r--r--ops/glesys/dns-tvl-su.tf41
-rw-r--r--ops/glesys/main.tf28
-rw-r--r--ops/keycloak/main.tf2
-rw-r--r--ops/machines/all-systems.nix1
-rw-r--r--ops/machines/bugry/default.nix36
-rw-r--r--ops/machines/nevsky/default.nix332
-rw-r--r--ops/machines/whitby/OWNERS5
-rw-r--r--ops/machines/whitby/README.md5
-rw-r--r--ops/machines/whitby/default.nix682
-rw-r--r--ops/modules/builderball.nix1
-rw-r--r--ops/modules/known-hosts.nix15
-rw-r--r--ops/modules/monitoring.nix106
-rw-r--r--ops/modules/monorepo-gerrit.nix2
-rw-r--r--ops/modules/restic.nix27
-rw-r--r--ops/modules/teleirc.nix2
-rw-r--r--ops/modules/tvl-buildkite.nix14
-rw-r--r--ops/modules/www/cache.tvl.fyi.nix7
-rw-r--r--ops/mq_cli/Cargo.toml2
-rw-r--r--ops/mq_cli/README.md2
-rw-r--r--ops/nixos.nix3
-rw-r--r--ops/pipelines/depot.nix4
-rw-r--r--ops/pipelines/static-pipeline.yaml3
-rw-r--r--ops/posix_mq.rs/Cargo.toml2
-rw-r--r--ops/posix_mq.rs/README.md2
-rw-r--r--ops/secrets/besadii.agebin1416 -> 1416 bytes
-rw-r--r--ops/secrets/buildkite-agent-token.agebin1033 -> 1007 bytes
-rw-r--r--ops/secrets/buildkite-graphql-token.agebin1022 -> 1022 bytes
-rw-r--r--ops/secrets/buildkite-ssh-private-key.agebin1393 -> 1393 bytes
-rw-r--r--ops/secrets/clbot-ssh.agebin1162 -> 1369 bytes
-rw-r--r--ops/secrets/clbot.agebin747 -> 1026 bytes
-rw-r--r--ops/secrets/depot-inbox-imap.age30
-rw-r--r--ops/secrets/depot-replica-key.agebin1208 -> 1393 bytes
-rw-r--r--ops/secrets/gerrit-autosubmit.agebin853 -> 1122 bytes
-rw-r--r--ops/secrets/gerrit-secrets.agebin913 -> 1166 bytes
-rw-r--r--ops/secrets/grafana.agebin883 -> 1051 bytes
-rw-r--r--ops/secrets/irccat.agebin825 -> 1048 bytes
-rw-r--r--ops/secrets/journaldriver.agebin3202 -> 3518 bytes
-rw-r--r--ops/secrets/keycloak-db.age32
-rw-r--r--ops/secrets/litestream-glesys14
-rw-r--r--ops/secrets/nix-cache-priv.agebin1084 -> 1084 bytes
-rw-r--r--ops/secrets/nix-cache-pub.age36
-rw-r--r--ops/secrets/owothia.age34
-rw-r--r--ops/secrets/panettone.age32
-rw-r--r--ops/secrets/restic-bugry.age17
-rw-r--r--ops/secrets/restic-nevsky.age17
-rw-r--r--ops/secrets/restic-sanduny.agebin0 -> 913 bytes
-rw-r--r--ops/secrets/secrets.nix74
-rw-r--r--ops/secrets/smtprelay.age34
-rw-r--r--ops/secrets/teleirc.agebin1006 -> 1093 bytes
-rw-r--r--ops/secrets/tf-buildkite.agebin943 -> 950 bytes
-rw-r--r--ops/secrets/tf-glesys.agebin959 -> 945 bytes
-rw-r--r--ops/secrets/tf-keycloak.agebin1135 -> 1025 bytes
-rw-r--r--ops/secrets/tf-yandex.age17
-rw-r--r--ops/secrets/tvl-alerts-bot-telegram-token.age32
-rw-r--r--ops/secrets/wg-bugry.agebin917 -> 917 bytes
-rw-r--r--ops/secrets/wg-nevsky.age32
-rw-r--r--ops/secrets/yc-restic.agebin0 -> 1209 bytes
-rw-r--r--ops/yandex-cloud-rs/Cargo.toml2
-rw-r--r--ops/yandex-cloud-rs/README.md2
-rw-r--r--third_party/bqn-libs/default.nix39
-rw-r--r--third_party/smtprelay/default.nix2
-rw-r--r--third_party/sources/sources.json48
-rw-r--r--tools/emacs-pkgs/tvl/tvl.el21
-rw-r--r--tools/nixery/README.md2
-rw-r--r--tools/nixery/web/index.html4
-rw-r--r--tvix/README.md2
-rw-r--r--tvix/boot/tests/default.nix166
-rw-r--r--tvix/build-go/build.pb.go14
-rw-r--r--tvix/build-go/rpc_build.pb.go10
-rw-r--r--tvix/castore-go/castore.pb.go14
-rw-r--r--tvix/castore-go/rpc_blobstore.pb.go14
-rw-r--r--tvix/castore-go/rpc_directory.pb.go14
-rw-r--r--tvix/docs/src/eval/vm-loop.md4
-rw-r--r--tvix/docs/src/introduction.md2
-rw-r--r--tvix/store-go/pathinfo.pb.go14
-rw-r--r--tvix/store-go/rpc_pathinfo.pb.go14
-rw-r--r--tvix/website/landing-en.md2
-rw-r--r--users/aspen/resume/resume.tex8
-rw-r--r--users/aspen/system/system/machines/yeren.nix3
-rw-r--r--users/aspen/web/index.org6
-rw-r--r--users/fogti/store-ref-scanner/Cargo.toml2
-rw-r--r--users/kranzes/wasm-hello-world/Cargo.lock31
-rw-r--r--users/kranzes/wasm-hello-world/Cargo.nix67
-rw-r--r--users/kranzes/wasm-hello-world/Cargo.toml2
-rw-r--r--users/sterni/acme/README.md14
-rwxr-xr-xusers/sterni/acme/mkbqnkeyboard.bqn3
-rw-r--r--users/sterni/acme/mkbqnkeyboard.md60
-rw-r--r--users/sterni/acme/plan9port/default.nix7
-rw-r--r--users/sterni/acme/plan9port/devdraw-ignore-primary-selection.patch83
-rw-r--r--users/sterni/blipqn/blipqn.bqn5
-rw-r--r--users/sterni/blërg/README.md25
-rwxr-xr-xusers/sterni/blërg/blërg.bqn170
-rw-r--r--users/sterni/blërg/default.nix42
-rw-r--r--users/sterni/emacs/subscriptions.el29
-rw-r--r--users/sterni/exercises/aoc/lib.bqn2
-rw-r--r--users/sterni/mn2html/.gitignore1
-rw-r--r--users/sterni/mn2html/Cargo.lock534
-rw-r--r--users/sterni/mn2html/Cargo.toml14
-rw-r--r--users/sterni/mn2html/README.md20
-rw-r--r--users/sterni/mn2html/default.nix25
-rw-r--r--users/sterni/mn2html/mn2html.rs165
-rw-r--r--users/tazjin/blog/default.nix2
-rw-r--r--users/tazjin/blog/posts/nixery-layers.md6
-rw-r--r--users/tazjin/nixos/modules/physical.nix1
-rw-r--r--users/wpcarro/common.nix2
-rw-r--r--users/wpcarro/website/blog/posts/restic.md2
-rw-r--r--users/wpcarro/website/default.nix2
-rw-r--r--web/panettone/src/panettone.lisp2
-rw-r--r--web/pwcrypt/Cargo.lock25
-rw-r--r--web/pwcrypt/Cargo.toml2
-rw-r--r--web/tvixbolt/Cargo.lock25
-rw-r--r--web/tvixbolt/Cargo.nix54
-rw-r--r--web/tvixbolt/Cargo.toml2
-rw-r--r--web/tvixbolt/src/lib.rs2
-rw-r--r--web/tvl/blog/2024-02-tvix-update.md6
-rw-r--r--web/tvl/blog/rewriting-nix.md2
-rw-r--r--web/tvl/blog/tvix-status-202209.md2
125 files changed, 2400 insertions, 1308 deletions
diff --git a/README.md b/README.md
index 938eb4b96663..a430db8a3fb2 100644
--- a/README.md
+++ b/README.md
@@ -35,7 +35,7 @@ partially see this as [an experiment][] in tooling for monorepos.
 * We use Buildkite for CI. Recent builds are listed on
   [tvl.fyi/builds](https://tvl.fyi/builds) and pipelines are configured
   dynamically via
-  [`//ops/pipelines`](https://cs.tvl.fyi/depot/-/tree/ops/pipelines).
+  [`//ops/pipelines`](https://code.tvl.fyi/tree/ops/pipelines).
 
 * A search service that makes TVL services available via textual
   shortcuts is available: [atward](https://at.tvl.fyi)
@@ -45,10 +45,10 @@ configuration is tracked in `//ops/{modules,machines}`.
 
 ## Nix
 
-* [`//nix/readTree`](https://cs.tvl.fyi/depot/-/blob/nix/readTree/README.md)
+* [`//nix/readTree`](https://code.tvl.fyi/about/nix/readTree/README.md)
   contains the Nix code which automatically registers projects in our Nix
   attribute hierarchy based on their in-tree location
-* [`//tools/nixery`](https://cs.tvl.fyi/depot/-/tree/tools/nixery)
+* [`//tools/nixery`](https://code.tvl.fyi/tree/tools/nixery)
   contains the source code of [Nixery][], a container registry that
   can build images ad-hoc from Nix packages
 * `//nix/yants` contains **Y**et **A**nother **N**ix **T**ype **S**ystem, which
@@ -83,7 +83,7 @@ be of interest.
 ## User packages
 
 Contributors to the repository have user directories under
-[`//users`](https://cs.tvl.fyi/depot@canon/-/tree/users), which can be used for
+[`//users`](https://code.tvl.fyi/tree/users), which can be used for
 personal or experimental code that does not require review.
 
 Some examples:
@@ -112,7 +112,7 @@ Hackint also provide a [web chat][tvl-webchat].
 [tvl]: https://tvl.fyi
 [Nix]: https://nixos.org/nix
 [an experiment]: https://tvl.fyi/monorepo-doc
-[panettone]: https://cs.tvl.fyi/depot@canon/-/tree/web/panettone
+[panettone]: https://code.tvl.fyi/tree/web/panettone
 [dottime]: https://dotti.me
 [tvl-irc]: ircs://irc.hackint.org:6697/#tvl
 [hackint]: https://hackint.org/
diff --git a/corp/rih/frontend/Cargo.lock b/corp/rih/frontend/Cargo.lock
index 44c962cee31c..402a44e52341 100644
--- a/corp/rih/frontend/Cargo.lock
+++ b/corp/rih/frontend/Cargo.lock
@@ -1500,24 +1500,24 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
 name = "wasm-bindgen"
-version = "0.2.95"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e"
+checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
 dependencies = [
  "cfg-if",
  "once_cell",
+ "rustversion",
  "wasm-bindgen-macro",
 ]
 
 [[package]]
 name = "wasm-bindgen-backend"
-version = "0.2.95"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358"
+checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
 dependencies = [
  "bumpalo",
  "log",
- "once_cell",
  "proc-macro2",
  "quote",
  "syn 2.0.15",
@@ -1538,9 +1538,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro"
-version = "0.2.95"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56"
+checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
 dependencies = [
  "quote",
  "wasm-bindgen-macro-support",
@@ -1548,9 +1548,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro-support"
-version = "0.2.95"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68"
+checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1561,9 +1561,12 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-shared"
-version = "0.2.95"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d"
+checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
+dependencies = [
+ "unicode-ident",
+]
 
 [[package]]
 name = "web-sys"
diff --git a/corp/rih/frontend/Cargo.toml b/corp/rih/frontend/Cargo.toml
index 10d63296c4b9..d07ed7aecd31 100644
--- a/corp/rih/frontend/Cargo.toml
+++ b/corp/rih/frontend/Cargo.toml
@@ -19,7 +19,7 @@ yew-router = "0.17"
 wasm-bindgen-futures = "0.4"
 
 # needs to be in sync with nixpkgs
-wasm-bindgen = "= 0.2.95"
+wasm-bindgen = "= 0.2.100"
 uuid = { version = "1.3.3", features = ["v4", "serde"] }
 
 [dependencies.serde]
diff --git a/corp/russian/predlozhnik/Cargo.lock b/corp/russian/predlozhnik/Cargo.lock
index 9743bc33532e..369b5427191f 100644
--- a/corp/russian/predlozhnik/Cargo.lock
+++ b/corp/russian/predlozhnik/Cargo.lock
@@ -256,6 +256,12 @@ dependencies = [
 ]
 
 [[package]]
+name = "rustversion"
+version = "1.0.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4"
+
+[[package]]
 name = "ryu"
 version = "1.0.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -351,9 +357,9 @@ dependencies = [
 
 [[package]]
 name = "unicode-ident"
-version = "1.0.4"
+version = "1.0.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd"
+checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034"
 
 [[package]]
 name = "version_check"
@@ -363,24 +369,24 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
 
 [[package]]
 name = "wasm-bindgen"
-version = "0.2.95"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e"
+checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
 dependencies = [
  "cfg-if",
  "once_cell",
+ "rustversion",
  "wasm-bindgen-macro",
 ]
 
 [[package]]
 name = "wasm-bindgen-backend"
-version = "0.2.95"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358"
+checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
 dependencies = [
  "bumpalo",
  "log",
- "once_cell",
  "proc-macro2",
  "quote",
  "syn 2.0.28",
@@ -401,9 +407,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro"
-version = "0.2.95"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56"
+checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
 dependencies = [
  "quote",
  "wasm-bindgen-macro-support",
@@ -411,9 +417,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro-support"
-version = "0.2.95"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68"
+checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -424,9 +430,12 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-shared"
-version = "0.2.95"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d"
+checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
+dependencies = [
+ "unicode-ident",
+]
 
 [[package]]
 name = "web-sys"
diff --git a/corp/russian/predlozhnik/Cargo.toml b/corp/russian/predlozhnik/Cargo.toml
index f215256247fc..7e42da8917ea 100644
--- a/corp/russian/predlozhnik/Cargo.toml
+++ b/corp/russian/predlozhnik/Cargo.toml
@@ -9,4 +9,4 @@ lazy_static = "1.4"
 yew = "0.19"
 
 # needs to be in sync with nixpkgs
-wasm-bindgen = "= 0.2.95"
+wasm-bindgen = "= 0.2.100"
diff --git a/default.nix b/default.nix
index d7623eeeee2f..caeab3519967 100644
--- a/default.nix
+++ b/default.nix
@@ -27,13 +27,12 @@ let
     '';
 
     exceptions = [
-      # whitby is allowed to access //users for several reasons:
+      # machines is allowed to access //users for several reasons:
       #
       # 1. User SSH keys are set in //users.
-      # 2. Some personal websites or demo projects are served from it.
+      # 2. Some personal websites or demo projects are served from there.
       [ "ops" "machines" "bugry" ]
       [ "ops" "machines" "nevsky" ]
-      [ "ops" "machines" "whitby" ]
 
       # Due to evaluation order this also affects these targets.
       # TODO(tazjin): Can this one be removed somehow?
@@ -51,9 +50,8 @@ let
     '';
 
     exceptions = [
-      # For the same reason as above, whitby is exempt to serve the
-      # corp website.
-      [ "ops" "machines" "whitby" ]
+      # For the same reason as above, machines are exempt to serve the corp
+      # website.
       [ "ops" "nixos" ]
       [ "ops" "machines" "all-systems" ]
     ];
diff --git a/ops/glesys/dns-tvix-dev.tf b/ops/glesys/dns-tvix-dev.tf
index 296532a02b04..d6c56077dc8d 100644
--- a/ops/glesys/dns-tvix-dev.tf
+++ b/ops/glesys/dns-tvix-dev.tf
@@ -8,28 +8,28 @@ resource "glesys_dnsdomain_record" "tvix_dev_apex_A" {
   domain = glesys_dnsdomain.tvix_dev.id
   host   = "@"
   type   = "A"
-  data   = var.whitby_ipv4
+  data   = var.bugry_ipv4
 }
 
 resource "glesys_dnsdomain_record" "tvix_dev_apex_AAAA" {
   domain = glesys_dnsdomain.tvix_dev.id
   host   = "@"
   type   = "AAAA"
-  data   = var.whitby_ipv6
+  data   = var.bugry_ipv6
 }
 
 resource "glesys_dnsdomain_record" "tvix_dev_bolt_CNAME" {
   domain = glesys_dnsdomain.tvix_dev.id
   host   = "bolt"
   type   = "CNAME"
-  data   = "whitby.tvl.su."
+  data   = "bugry.tvl.fyi."
 }
 
 resource "glesys_dnsdomain_record" "tvix_dev_docs_CNAME" {
   domain = glesys_dnsdomain.tvix_dev.id
   host   = "docs"
   type   = "CNAME"
-  data   = "whitby.tvl.fyi."
+  data   = "bugry.tvl.fyi."
 }
 
 resource "glesys_dnsdomain_record" "tvix_dev_NS1" {
diff --git a/ops/glesys/dns-tvl-fyi.tf b/ops/glesys/dns-tvl-fyi.tf
index ff9469badd0c..837f40aedef2 100644
--- a/ops/glesys/dns-tvl-fyi.tf
+++ b/ops/glesys/dns-tvl-fyi.tf
@@ -29,28 +29,14 @@ resource "glesys_dnsdomain_record" "tvl_fyi_apex_A" {
   domain = glesys_dnsdomain.tvl_fyi.id
   host   = "@"
   type   = "A"
-  data   = var.whitby_ipv4
+  data   = var.bugry_ipv4
 }
 
 resource "glesys_dnsdomain_record" "tvl_fyi_apex_AAAA" {
   domain = glesys_dnsdomain.tvl_fyi.id
   host   = "@"
   type   = "AAAA"
-  data   = var.whitby_ipv6
-}
-
-resource "glesys_dnsdomain_record" "tvl_fyi_whitby_A" {
-  domain = glesys_dnsdomain.tvl_fyi.id
-  host   = "whitby"
-  type   = "A"
-  data   = var.whitby_ipv4
-}
-
-resource "glesys_dnsdomain_record" "tvl_fyi_whitby_AAAA" {
-  domain = glesys_dnsdomain.tvl_fyi.id
-  host   = "whitby"
-  type   = "AAAA"
-  data   = var.whitby_ipv6
+  data   = var.bugry_ipv6
 }
 
 resource "glesys_dnsdomain_record" "tvl_fyi_nevsky_A" {
@@ -81,13 +67,22 @@ resource "glesys_dnsdomain_record" "tvl_fyi_bugry_AAAA" {
   data   = var.bugry_ipv6
 }
 
-# Explicit records for all services running on whitby
-resource "glesys_dnsdomain_record" "tvl_fyi_whitby_services" {
+# Explicit records for all services running on nevsky
+resource "glesys_dnsdomain_record" "tvl_fyi_nevsky_services" {
   domain   = glesys_dnsdomain.tvl_fyi.id
   type     = "CNAME"
-  data     = "whitby.tvl.fyi."
+  data     = "nevsky.tvl.fyi."
   host     = each.key
-  for_each = toset(local.whitby_services)
+  for_each = toset(local.nevsky_services)
+}
+
+# Explicit records for all services running on bugry
+resource "glesys_dnsdomain_record" "tvl_fyi_bugry_services" {
+  domain   = glesys_dnsdomain.tvl_fyi.id
+  type     = "CNAME"
+  data     = "bugry.tvl.fyi."
+  host     = each.key
+  for_each = toset(local.bugry_services)
 }
 
 resource "glesys_dnsdomain_record" "tvl_fyi_net_CNAME" {
@@ -104,7 +99,7 @@ resource "glesys_dnsdomain_record" "cache_tvl_fyi_A" {
   host     = "cache"
   type     = "A"
   data     = each.key
-  for_each = toset([var.whitby_ipv4, var.nevsky_ipv4])
+  for_each = toset([var.nevsky_ipv4])
 }
 
 resource "glesys_dnsdomain_record" "cache_tvl_fyi_AAAA" {
@@ -112,18 +107,11 @@ resource "glesys_dnsdomain_record" "cache_tvl_fyi_AAAA" {
   host     = "cache"
   type     = "AAAA"
   data     = each.key
-  for_each = toset([var.whitby_ipv6, var.nevsky_ipv6])
+  for_each = toset([var.nevsky_ipv6])
 }
 
 # Builderball cache records
 
-resource "glesys_dnsdomain_record" "tvl_fyi_cache_whitby_CNAME" {
-  domain = glesys_dnsdomain.tvl_fyi.id
-  type   = "CNAME"
-  data   = "whitby.tvl.fyi."
-  host   = "whitby.cache"
-}
-
 resource "glesys_dnsdomain_record" "tvl_fyi_cache_nevsky_CNAME" {
   domain = glesys_dnsdomain.tvl_fyi.id
   type   = "CNAME"
diff --git a/ops/glesys/dns-tvl-su.tf b/ops/glesys/dns-tvl-su.tf
index 97c7d60ac5e2..df5685893f35 100644
--- a/ops/glesys/dns-tvl-su.tf
+++ b/ops/glesys/dns-tvl-su.tf
@@ -29,28 +29,14 @@ resource "glesys_dnsdomain_record" "tvl_su_apex_A" {
   domain = glesys_dnsdomain.tvl_su.id
   host   = "@"
   type   = "A"
-  data   = var.whitby_ipv4
+  data   = var.bugry_ipv4
 }
 
 resource "glesys_dnsdomain_record" "tvl_su_apex_AAAA" {
   domain = glesys_dnsdomain.tvl_su.id
   host   = "@"
   type   = "AAAA"
-  data   = var.whitby_ipv6
-}
-
-resource "glesys_dnsdomain_record" "tvl_su_whitby_A" {
-  domain = glesys_dnsdomain.tvl_su.id
-  host   = "whitby"
-  type   = "A"
-  data   = var.whitby_ipv4
-}
-
-resource "glesys_dnsdomain_record" "tvl_su_whitby_AAAA" {
-  domain = glesys_dnsdomain.tvl_su.id
-  host   = "whitby"
-  type   = "AAAA"
-  data   = var.whitby_ipv6
+  data   = var.bugry_ipv6
 }
 
 resource "glesys_dnsdomain_record" "tvl_su_sanduny_A" {
@@ -67,20 +53,29 @@ resource "glesys_dnsdomain_record" "tvl_su_sanduny_AAAA" {
   data   = var.sanduny_ipv6
 }
 
-resource "glesys_dnsdomain_record" "cache_tvl_su_whitby_CNAME" {
+resource "glesys_dnsdomain_record" "cache_tvl_su_nevsky_CNAME" {
   domain = glesys_dnsdomain.tvl_su.id
   host   = "cache"
   type   = "CNAME"
-  data   = "whitby.tvl.su."
+  data   = "nevsky.tvl.fyi."
+}
+
+# Explicit records for all services running on nevsky
+resource "glesys_dnsdomain_record" "tvl_su_nevsky_services" {
+  domain   = glesys_dnsdomain.tvl_su.id
+  type     = "CNAME"
+  data     = "nevsky.tvl.fyi."
+  host     = each.key
+  for_each = toset(local.nevsky_services)
 }
 
-# Explicit records for all services running on whitby
-resource "glesys_dnsdomain_record" "tvl_su_whitby_services" {
+# Explicit records for all services running on bugry
+resource "glesys_dnsdomain_record" "tvl_su_bugry_services" {
   domain   = glesys_dnsdomain.tvl_su.id
   type     = "CNAME"
-  data     = "whitby.tvl.su."
+  data     = "bugry.tvl.fyi."
   host     = each.key
-  for_each = toset(local.whitby_services)
+  for_each = toset(local.bugry_services)
 }
 
 # historical tvixbolt.tvl.su record, redirects to bolt.tvix.dev
@@ -88,7 +83,7 @@ resource "glesys_dnsdomain_record" "tvix_su_tvixbolt_CNAME" {
   domain = glesys_dnsdomain.tvl_su.id
   host   = "tvixbolt"
   type   = "CNAME"
-  data   = "whitby.tvl.su."
+  data   = "nevsky.tvl.fyi."
 }
 
 resource "glesys_dnsdomain_record" "tvl_su_inbox_CNAME" {
diff --git a/ops/glesys/main.tf b/ops/glesys/main.tf
index d92740d0882b..3c566376b139 100644
--- a/ops/glesys/main.tf
+++ b/ops/glesys/main.tf
@@ -51,16 +51,6 @@ resource "glesys_objectstorage_credential" "litestream" {
   description = "key for litestream"
 }
 
-variable "whitby_ipv4" {
-  type    = string
-  default = "49.12.129.211"
-}
-
-variable "whitby_ipv6" {
-  type    = string
-  default = "2a01:4f8:242:5b21:0:feed:edef:beef"
-}
-
 variable "nevsky_ipv4" {
   type    = string
   default = "188.225.81.75"
@@ -92,20 +82,24 @@ variable "sanduny_ipv6" {
 }
 
 locals {
-  # Hostnames of all public services on whitby
-  whitby_services = [
-    "at",
-    "atward",
+  # Hostnames of all public services on nevsky
+  nevsky_services = [
     "auth",
     "b",
     "cl",
     "code",
     "cs",
-    "deploys",
-    "images",
+    "deploys", # TODO: unsupported (b/437)
+    "grep",
+    "status",
+  ]
+
+  # Hostnames of all public services on bugry
+  bugry_services = [
+    "at",
+    "atward",
     "signup",
     "static",
-    "status",
     "todo",
   ]
 }
diff --git a/ops/keycloak/main.tf b/ops/keycloak/main.tf
index d5698700ce58..b330e2a4da7c 100644
--- a/ops/keycloak/main.tf
+++ b/ops/keycloak/main.tf
@@ -5,7 +5,7 @@
 terraform {
   required_providers {
     keycloak = {
-      source = "mrparkers/keycloak"
+      source = "keycloak/keycloak"
     }
   }
 
diff --git a/ops/machines/all-systems.nix b/ops/machines/all-systems.nix
index fd31dfa25699..c8a325a1c7bb 100644
--- a/ops/machines/all-systems.nix
+++ b/ops/machines/all-systems.nix
@@ -2,7 +2,6 @@
 
 (with depot.ops.machines; [
   sanduny
-  whitby
   bugry
   nevsky
 ]) ++
diff --git a/ops/machines/bugry/default.nix b/ops/machines/bugry/default.nix
index 92d09741cac4..5815d4348095 100644
--- a/ops/machines/bugry/default.nix
+++ b/ops/machines/bugry/default.nix
@@ -6,12 +6,22 @@ let
 in
 {
   imports = [
+    (mod "atward.nix")
     (mod "depot-replica.nix")
     (mod "known-hosts.nix")
     (mod "nixery.nix")
     (mod "tvl-cache.nix")
     (mod "tvl-users.nix")
+    (mod "www/atward.tvl.fyi.nix")
     (mod "www/nixery.dev.nix")
+    (mod "www/self-redirect.nix")
+    (mod "www/signup.tvl.fyi.nix")
+    (mod "www/static.tvl.fyi.nix")
+    (mod "www/todo.tvl.fyi.nix")
+    (mod "www/tvix.dev.nix")
+    (mod "www/tvl.fyi.nix")
+    (mod "www/tvl.su.nix")
+    (mod "www/wigglydonke.rs.nix")
 
     (depot.third_party.agenix.src + "/modules/age.nix")
   ];
@@ -172,18 +182,24 @@ in
   tvl.cache.enable = true;
   tvl.cache.builderball = true;
 
-  services.depot.nixery.enable = true;
+  services.depot =
+    {
+      nixery.enable = true;
 
-  # Allow Gerrit to replicate depot to /var/lib/depot
-  services.depot.replica.enable = true;
+      # Allow Gerrit to replicate depot to /var/lib/depot
+      replica.enable = true;
 
-  services.depot.automatic-gc = {
-    enable = true;
-    interval = "1 hour";
-    diskThreshold = 50; # GiB (10% of disk)
-    maxFreed = 150; # GiB
-    preserveGenerations = "14d";
-  };
+      # Run atward, the search engine redirection thing.
+      atward.enable = true;
+
+      automatic-gc = {
+        enable = true;
+        interval = "1 hour";
+        diskThreshold = 50; # GiB (10% of disk)
+        maxFreed = 150; # GiB
+        preserveGenerations = "14d";
+      };
+    };
 
   system.stateVersion = "24.11";
 }
diff --git a/ops/machines/nevsky/default.nix b/ops/machines/nevsky/default.nix
index ec66e1e0e319..983f4bcb8759 100644
--- a/ops/machines/nevsky/default.nix
+++ b/ops/machines/nevsky/default.nix
@@ -6,19 +6,44 @@ let
 in
 {
   imports = [
+    (depot.third_party.agenix.src + "/modules/age.nix")
     (mod "builderball.nix")
+    (mod "cgit.nix")
+    (mod "cheddar.nix")
+    (mod "clbot.nix")
+    (mod "gerrit-autosubmit.nix")
     (mod "harmonia.nix")
+    (mod "irccat.nix")
+    (mod "josh.nix")
     (mod "known-hosts.nix")
+    (mod "livegrep.nix")
+    (mod "monitoring.nix")
+    (mod "monorepo-gerrit.nix")
+    (mod "owothia.nix")
+    (mod "panettone.nix")
+    (mod "paroxysm.nix")
+    (mod "restic.nix")
+    (mod "smtprelay.nix")
+    (mod "teleirc.nix")
     (mod "tvl-buildkite.nix")
+    (mod "tvl-slapd/default.nix")
     (mod "tvl-users.nix")
+    (mod "www/auth.tvl.fyi.nix")
+    (mod "www/b.tvl.fyi.nix")
     (mod "www/cache.tvl.fyi.nix")
+    (mod "www/cache.tvl.su.nix")
+    (mod "www/cl.tvl.fyi.nix")
+    (mod "www/code.tvl.fyi.nix")
+    (mod "www/cs.tvl.fyi.nix")
+    (mod "www/grep.tvl.fyi.nix")
     (mod "www/self-cache.tvl.fyi.nix")
     (mod "www/self-redirect.nix")
-    (depot.third_party.agenix.src + "/modules/age.nix")
+    (mod "www/status.tvl.su.nix")
   ];
 
   hardware.cpu.amd.updateMicrocode = true;
   hardware.enableRedistributableFirmware = true;
+  powerManagement.cpuFreqGovernor = "performance";
 
   boot = {
     tmp.useTmpfs = true;
@@ -96,6 +121,15 @@ in
       secretFile = name: depot.ops.secrets."${name}.age";
     in
     {
+      clbot.file = secretFile "clbot";
+      gerrit-autosubmit.file = secretFile "gerrit-autosubmit";
+      grafana.file = secretFile "grafana";
+      irccat.file = secretFile "irccat";
+      keycloak-db.file = secretFile "keycloak-db";
+      owothia.file = secretFile "owothia";
+      panettone.file = secretFile "panettone";
+      smtprelay.file = secretFile "smtprelay";
+      teleirc.file = secretFile "teleirc";
       wg-privkey.file = depot.ops.secrets."wg-nevsky.age";
 
       nix-cache-priv = {
@@ -133,6 +167,31 @@ in
         mode = "0440";
         group = "buildkite-agents";
       };
+
+      gerrit-besadii-config = {
+        file = secretFile "besadii";
+        owner = "git";
+      };
+
+      gerrit-secrets = {
+        file = secretFile "gerrit-secrets";
+        path = "/var/lib/gerrit/etc/secure.config";
+        owner = "git";
+        mode = "0400";
+      };
+
+      clbot-ssh = {
+        file = secretFile "clbot-ssh";
+        owner = "clbot";
+      };
+
+      depot-replica-key = {
+        file = secretFile "depot-replica-key";
+        mode = "0500";
+        owner = "git";
+        group = "git";
+        path = "/var/lib/git/.ssh/id_ed25519";
+      };
     };
 
   networking = {
@@ -165,10 +224,12 @@ in
 
       postSetup = ''
         ${pkgs.iptables}/bin/ip6tables -t nat -A POSTROUTING -s '2a03:6f00:2:514b:5bc7:95ef::1/96' -o enp1s0f0np0 -j MASQUERADE
+        ip -6 neigh add proxy 2a03:6f00:2:514b:5bc7:95ef:0:2 dev enp1s0f0np0
       '';
 
       postShutdown = ''
         ${pkgs.iptables}/bin/ip6tables -t nat -D POSTROUTING -s '2a03:6f00:2:514b:5bc7:95ef::1/96' -o enp1s0f0np0 -j MASQUERADE
+        ip -6 neigh del proxy 2a03:6f00:2:514b:5bc7:95ef:0:2 dev enp1s0f0np0
       '';
 
       peers = [{
@@ -184,7 +245,7 @@ in
       "8.8.4.4"
     ];
 
-    firewall.allowedTCPPorts = [ 22 80 443 ];
+    firewall.allowedTCPPorts = [ 22 80 443 29418 ];
     firewall.allowedUDPPorts = [ 51820 ];
   };
 
@@ -215,40 +276,285 @@ in
 
   services.fwupd.enable = true;
 
+  services.postgresql = {
+    enable = true;
+    enableTCPIP = true;
+    package = pkgs.postgresql_16;
+
+    authentication = lib.mkForce ''
+      local all all trust
+      host all all 127.0.0.1/32 password
+      host all all ::1/128 password
+      hostnossl all all 127.0.0.1/32 password
+      hostnossl all all ::1/128  password
+    '';
+
+    ensureDatabases = [
+      "panettone"
+    ];
+
+    ensureUsers = [{
+      name = "panettone";
+      ensureDBOwnership = true;
+    }];
+  };
+
   # Join TVL Tailscale network at net.tvl.fyi
   services.tailscale = {
     enable = true;
     useRoutingFeatures = "both";
   };
 
-  # Run a Harmonia binary cache.
-  #
-  # TODO(tazjin): switch to upstream module after fix for Nix 2.3
-  services.depot.harmonia = {
+  services.depot = {
+    # Run a Harmonia binary cache.
+    #
+    # TODO(tazjin): switch to upstream module after fix for Nix 2.3
+    harmonia = {
+      enable = true;
+      signKeyPaths = [ (config.age.secretsDir + "/nix-cache-priv") ];
+      settings.bind = "127.0.0.1:6443";
+      settings.priority = 50;
+    };
+
+    builderball.enable = true;
+
+    # Run Markdown/code renderer
+    cheddar.enable = true;
+
+    # Run a livegrep code search instance
+    livegrep.enable = true;
+
+    # Automatically collect garbage from the Nix store.
+    automatic-gc = {
+      enable = true;
+      interval = "1 hour";
+      diskThreshold = 200; # GiB
+      maxFreed = 420; # GiB
+      preserveGenerations = "60d";
+    };
+
+    # Run cgit & josh to serve git
+    cgit = {
+      enable = true;
+      user = "git"; # run as the same user as gerrit
+    };
+
+    josh.enable = true;
+
+    # Run a handful of Buildkite agents to support parallel builds.
+    buildkite = {
+      enable = true;
+      agentCount = 24;
+      largeSlots = 6;
+    };
+
+    # Run the Panettone issue tracker
+    panettone = {
+      enable = true;
+      dbUser = "panettone";
+      dbName = "panettone";
+      irccatChannel = "#tvl";
+    };
+
+    # Run the first cursed bot (quote bot)
+    paroxysm.enable = true;
+
+    # make our channel more owo
+    owothia = {
+      enable = true;
+      ircServer = "localhost";
+      ircPort = config.services.znc.config.Listener.l.Port;
+    };
+
+    # Run irccat to forward messages to IRC
+    irccat = {
+      enable = true;
+      config = {
+        tcp.listen = ":4722"; # "ircc"
+        irc = {
+          server = "localhost:${toString config.services.znc.config.Listener.l.Port}";
+          tls = false;
+          nick = "tvlbot";
+          # Note: irccat means 'ident' where it says 'realname', so
+          # this is critical for connecting to ZNC.
+          realname = "tvlbot";
+          channels = [
+            "#tvl"
+          ];
+        };
+      };
+    };
+
+    # Start the Gerrit->IRC bot
+    clbot = {
+      enable = true;
+      channels = {
+        "#tvl" = { };
+        "#tvix-dev" = {
+          only_display = "tvix,nix-compat,third_party,third-party,3p";
+        };
+      };
+
+      # See //fun/clbot for details.
+      flags = {
+        gerrit_host = "cl.tvl.fyi:29418";
+        gerrit_ssh_auth_username = "clbot";
+        gerrit_ssh_auth_key = config.age.secretsDir + "/clbot-ssh";
+
+        irc_server = "localhost:${toString config.services.znc.config.Listener.l.Port}";
+        irc_user = "tvlbot";
+        irc_nick = "tvlbot";
+
+        notify_branches = "canon,refs/meta/config";
+        notify_repo = "depot";
+
+        # This secret is read from an environment variable, which is
+        # populated by a systemd EnvironmentFile.
+        irc_pass = "$CLBOT_PASS";
+      };
+    };
+
+    # Start a local SMTP relay to Gmail (used by gerrit)
+    smtprelay = {
+      enable = true;
+      args = {
+        listen = ":2525";
+        remote_host = "smtp.gmail.com:587";
+        remote_auth = "plain";
+        remote_user = "tvlbot@tazj.in";
+      };
+    };
+
+    # Run the Telegram<>IRC bridge for Volga Sprint.
+    teleirc.enable = true;
+
+    # Configure backups to GleSYS
+    restic = {
+      enable = true;
+      paths = [
+        "/var/backup/postgresql"
+        "/var/lib/grafana"
+        "/var/lib/znc"
+      ];
+    };
+
+    # Run autosubmit bot for Gerrit
+    gerrit-autosubmit.enable = true;
+  };
+
+  # Start a ZNC instance which bounces for tvlbot and owothia.
+  services.znc = {
     enable = true;
-    signKeyPaths = [ (config.age.secretsDir + "/nix-cache-priv") ];
-    settings.bind = "127.0.0.1:6443";
-    settings.priority = 50;
+    useLegacyConfig = false;
+    config = {
+      LoadModule = [
+        "webadmin"
+        "adminlog"
+      ];
+
+      User.admin = {
+        Admin = true;
+        Pass.password = {
+          Method = "sha256";
+          Hash = "bb00aa8239de484c2925b1c3f6a196fb7612633f001daa9b674f83abe7e1103f";
+          Salt = "TiB0Ochb1CrtpMTl;2;j";
+        };
+      };
+
+      Listener.l = {
+        Host = "localhost";
+        Port = 2627; # bncr
+        SSL = false;
+      };
+
+      Listener.tailscale = {
+        Host = "100.64.0.11";
+        Port = 2627; # bncr
+        SSL = false;
+      };
+    };
   };
 
-  services.depot.builderball.enable = true;
+  services.keycloak = {
+    enable = true;
+
+    settings = {
+      http-port = 5925; # kycl
+      hostname = "auth.tvl.fyi";
+      http-relative-path = "/auth";
+      proxy-headers = "xforwarded";
+      http-enabled = true;
+    };
 
-  # Run a handful of Buildkite agents to support parallel builds.
-  services.depot.buildkite = {
+    database = {
+      type = "postgresql";
+      passwordFile = config.age.secretsDir + "/keycloak-db";
+      createLocally = false;
+    };
+  };
+
+  services.postgresqlBackup = {
     enable = true;
-    agentCount = 16;
+    databases = [
+      "keycloak"
+      "panettone"
+      "tvldb"
+    ];
   };
 
   # Use TVL cache locally through the proxy; for cross-builder substitution.
   tvl.cache.enable = true;
   tvl.cache.builderball = true;
 
+  # Disable background git gc system-wide, as it has a tendency to break CI.
+  environment.etc."gitconfig".source = pkgs.writeText "gitconfig" ''
+    [gc]
+    autoDetach = false
+  '';
+
   security.sudo.extraRules = [{
     groups = [ "wheel" ];
     commands = [{ command = "ALL"; options = [ "NOPASSWD" ]; }];
   }];
 
+  users = {
+    # Set up a user & group for git shenanigans
+    groups.git = { };
+    users.git = {
+      group = "git";
+      isSystemUser = true;
+      createHome = true;
+      home = "/var/lib/git";
+    };
+  };
+
   zramSwap.enable = true;
 
+  environment.systemPackages = (with pkgs; [
+    bat
+    bb
+    curl
+    direnv
+    emacs-nox
+    fd
+    git
+    htop
+    hyperfine
+    jq
+    nano
+    nix-diff
+    nix-top
+    nvd
+    ripgrep
+    screen
+    tig
+    tree
+    unzip
+    vim
+    watchexec
+    zfs
+    zfstools
+  ]);
+
   system.stateVersion = "24.11";
 }
diff --git a/ops/machines/whitby/OWNERS b/ops/machines/whitby/OWNERS
deleted file mode 100644
index 4581a80d617d..000000000000
--- a/ops/machines/whitby/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-set noparent
-
-# Want in on this list? Try paying!
-lukegb
-tazjin
diff --git a/ops/machines/whitby/README.md b/ops/machines/whitby/README.md
deleted file mode 100644
index 55287c541256..000000000000
--- a/ops/machines/whitby/README.md
+++ /dev/null
@@ -1,5 +0,0 @@
-whitby
-======
-
-`whitby.tvl.fyi` is our dedicated server providing continuous
-integration services and other random nonsense.
diff --git a/ops/machines/whitby/default.nix b/ops/machines/whitby/default.nix
deleted file mode 100644
index 786b240004f3..000000000000
--- a/ops/machines/whitby/default.nix
+++ /dev/null
@@ -1,682 +0,0 @@
-{ depot, lib, pkgs, ... }: # readTree options
-{ config, ... }: # passed by module system
-
-let
-  inherit (builtins) listToAttrs;
-  inherit (lib) range;
-
-  mod = name: depot.path.origSrc + ("/ops/modules/" + name);
-in
-{
-  imports = [
-    (mod "atward.nix")
-    (mod "builderball.nix")
-    (mod "cgit.nix")
-    (mod "cheddar.nix")
-    (mod "clbot.nix")
-    (mod "gerrit-autosubmit.nix")
-    (mod "harmonia.nix")
-    (mod "irccat.nix")
-    (mod "josh.nix")
-    (mod "journaldriver.nix")
-    (mod "known-hosts.nix")
-    (mod "livegrep.nix")
-    (mod "monorepo-gerrit.nix")
-    (mod "owothia.nix")
-    (mod "panettone.nix")
-    (mod "paroxysm.nix")
-    (mod "restic.nix")
-    (mod "smtprelay.nix")
-    (mod "teleirc.nix")
-    (mod "tvl-buildkite.nix")
-    (mod "tvl-slapd/default.nix")
-    (mod "tvl-users.nix")
-    (mod "www/atward.tvl.fyi.nix")
-    (mod "www/auth.tvl.fyi.nix")
-    (mod "www/b.tvl.fyi.nix")
-    (mod "www/cache.tvl.fyi.nix")
-    (mod "www/cache.tvl.su.nix")
-    (mod "www/cl.tvl.fyi.nix")
-    (mod "www/code.tvl.fyi.nix")
-    (mod "www/cs.tvl.fyi.nix")
-    (mod "www/deploys.tvl.fyi.nix")
-    (mod "www/self-cache.tvl.fyi.nix")
-    (mod "www/self-redirect.nix")
-    (mod "www/signup.tvl.fyi.nix")
-    (mod "www/static.tvl.fyi.nix")
-    (mod "www/status.tvl.su.nix")
-    (mod "www/todo.tvl.fyi.nix")
-    (mod "www/tvix.dev.nix")
-    (mod "www/tvl.fyi.nix")
-    (mod "www/tvl.su.nix")
-    (mod "www/wigglydonke.rs.nix")
-
-    # experimental!
-    (mod "www/grep.tvl.fyi.nix")
-
-    (depot.third_party.agenix.src + "/modules/age.nix")
-  ];
-
-  hardware = {
-    enableRedistributableFirmware = true;
-    cpu.amd.updateMicrocode = true;
-  };
-
-  boot = {
-    tmp.useTmpfs = true;
-    kernelModules = [ "kvm-amd" ];
-    supportedFilesystems = [ "zfs" ];
-
-    initrd = {
-      availableKernelModules = [
-        "igb"
-        "xhci_pci"
-        "nvme"
-        "ahci"
-        "usbhid"
-        "usb_storage"
-        "sr_mod"
-      ];
-
-      # Enable SSH in the initrd so that we can enter disk encryption
-      # passwords remotely.
-      network = {
-        enable = true;
-        ssh = {
-          enable = true;
-          port = 2222;
-          authorizedKeys =
-            depot.users.tazjin.keys.all
-            ++ depot.users.lukegb.keys.all
-            ++ [ depot.users.aspen.keys.whitby ];
-
-          hostKeys = [
-            /etc/secrets/initrd_host_ed25519_key
-          ];
-        };
-
-        # this will launch the zfs password prompt on login and kill the
-        # other prompt
-        postCommands = ''
-          echo "zfs load-key -a && killall zfs" >> /root/.profile
-        '';
-      };
-    };
-
-    kernel.sysctl = {
-      "net.ipv4.tcp_congestion_control" = "bbr";
-    };
-
-    loader.grub = {
-      enable = true;
-      efiSupport = true;
-      efiInstallAsRemovable = true;
-      device = "/dev/disk/by-id/nvme-SAMSUNG_MZQLB1T9HAJR-00007_S439NA0N201620";
-    };
-
-    zfs.requestEncryptionCredentials = true;
-  };
-
-  fileSystems = {
-    "/" = {
-      device = "zroot/root";
-      fsType = "zfs";
-    };
-
-    "/boot" = {
-      device = "/dev/disk/by-uuid/073E-7FBD";
-      fsType = "vfat";
-    };
-
-    "/nix" = {
-      device = "zroot/nix";
-      fsType = "zfs";
-    };
-
-    "/home" = {
-      device = "zroot/home";
-      fsType = "zfs";
-    };
-  };
-
-  networking = {
-    # Glass is boring, but Luke doesn't like Wapping - the Prospect of
-    # Whitby, however, is quite a pleasant establishment.
-    hostName = "whitby";
-    domain = "tvl.fyi";
-    hostId = "b38ca543";
-    useDHCP = false;
-
-    # Don't use Hetzner's DNS servers.
-    nameservers = [
-      "8.8.8.8"
-      "8.8.4.4"
-    ];
-
-    defaultGateway6 = {
-      address = "fe80::1";
-      interface = "enp196s0";
-    };
-
-    firewall.allowedTCPPorts = [ 22 80 443 4238 8443 29418 ];
-    firewall.allowedUDPPorts = [ 8443 ];
-
-    interfaces.enp196s0.useDHCP = true;
-    interfaces.enp196s0.ipv6.addresses = [
-      {
-        address = "2a01:04f8:0242:5b21::feed:edef:beef";
-        prefixLength = 64;
-      }
-    ];
-  };
-
-  # Generate an immutable /etc/resolv.conf from the nameserver settings
-  # above (otherwise DHCP overwrites it):
-  environment.etc."resolv.conf" = with lib; {
-    source = pkgs.writeText "resolv.conf" ''
-      ${concatStringsSep "\n" (map (ns: "nameserver ${ns}") config.networking.nameservers)}
-      options edns0
-    '';
-  };
-
-  # Disable background git gc system-wide, as it has a tendency to break CI.
-  environment.etc."gitconfig".source = pkgs.writeText "gitconfig" ''
-    [gc]
-    autoDetach = false
-  '';
-
-  time.timeZone = "UTC";
-
-  nix = {
-    nrBuildUsers = 256;
-    settings = {
-      max-jobs = lib.mkDefault 64;
-      secret-key-files = "/run/agenix/nix-cache-priv";
-
-      trusted-users = [
-        "aspen"
-        "lukegb"
-        "tazjin"
-        "sterni"
-      ];
-    };
-
-    sshServe = {
-      enable = true;
-      keys = with depot.users;
-        tazjin.keys.all
-        ++ lukegb.keys.all
-        ++ [ aspen.keys.whitby ]
-        ++ sterni.keys.all
-      ;
-    };
-  };
-
-  programs.mtr.enable = true;
-  programs.mosh.enable = true;
-  services.openssh = {
-    enable = true;
-    settings = {
-      PasswordAuthentication = false;
-      KbdInteractiveAuthentication = false;
-    };
-  };
-
-  # Configure secrets for services that need them.
-  age.secrets =
-    let
-      secretFile = name: depot.ops.secrets."${name}.age";
-    in
-    {
-      clbot.file = secretFile "clbot";
-      gerrit-autosubmit.file = secretFile "gerrit-autosubmit";
-      grafana.file = secretFile "grafana";
-      irccat.file = secretFile "irccat";
-      keycloak-db.file = secretFile "keycloak-db";
-      owothia.file = secretFile "owothia";
-      panettone.file = secretFile "panettone";
-      smtprelay.file = secretFile "smtprelay";
-      teleirc.file = secretFile "teleirc";
-
-      nix-cache-priv = {
-        file = secretFile "nix-cache-priv";
-        mode = "0440";
-        group = "harmonia";
-      };
-
-      buildkite-agent-token = {
-        file = secretFile "buildkite-agent-token";
-        mode = "0440";
-        group = "buildkite-agents";
-      };
-
-      buildkite-graphql-token = {
-        file = secretFile "buildkite-graphql-token";
-        mode = "0440";
-        group = "buildkite-agents";
-      };
-
-      buildkite-besadii-config = {
-        file = secretFile "besadii";
-        mode = "0440";
-        group = "buildkite-agents";
-      };
-
-      buildkite-private-key = {
-        file = secretFile "buildkite-ssh-private-key";
-        mode = "0440";
-        group = "buildkite-agents";
-      };
-
-      gerrit-besadii-config = {
-        file = secretFile "besadii";
-        owner = "git";
-      };
-
-      gerrit-secrets = {
-        file = secretFile "gerrit-secrets";
-        path = "/var/lib/gerrit/etc/secure.config";
-        owner = "git";
-        mode = "0400";
-      };
-
-      clbot-ssh = {
-        file = secretFile "clbot-ssh";
-        owner = "clbot";
-      };
-
-      # Not actually a secret
-      nix-cache-pub = {
-        file = secretFile "nix-cache-pub";
-        mode = "0444";
-      };
-
-      depot-replica-key = {
-        file = secretFile "depot-replica-key";
-        mode = "0500";
-        owner = "git";
-        group = "git";
-        path = "/var/lib/git/.ssh/id_ed25519";
-      };
-    };
-
-  # Automatically collect garbage from the Nix store.
-  services.depot.automatic-gc = {
-    enable = true;
-    interval = "1 hour";
-    diskThreshold = 200; # GiB
-    maxFreed = 420; # GiB
-    preserveGenerations = "90d";
-  };
-
-  # Run a handful of Buildkite agents to support parallel builds.
-  services.depot.buildkite = {
-    enable = true;
-    agentCount = 32;
-  };
-
-  # Run Markdown/code renderer
-  services.depot.cheddar.enable = true;
-
-  # Start a local SMTP relay to Gmail (used by gerrit)
-  services.depot.smtprelay = {
-    enable = true;
-    args = {
-      listen = ":2525";
-      remote_host = "smtp.gmail.com:587";
-      remote_auth = "plain";
-      remote_user = "tvlbot@tazj.in";
-    };
-  };
-
-  # Start a ZNC instance which bounces for tvlbot and owothia.
-  services.znc = {
-    enable = true;
-    useLegacyConfig = false;
-    config = {
-      LoadModule = [
-        "webadmin"
-        "adminlog"
-      ];
-
-      User.admin = {
-        Admin = true;
-        Pass.password = {
-          Method = "sha256";
-          Hash = "bb00aa8239de484c2925b1c3f6a196fb7612633f001daa9b674f83abe7e1103f";
-          Salt = "TiB0Ochb1CrtpMTl;2;j";
-        };
-      };
-
-      Listener.l = {
-        Host = "localhost";
-        Port = 2627; # bncr
-        SSL = false;
-      };
-    };
-  };
-
-  # Start the Gerrit->IRC bot
-  services.depot.clbot = {
-    enable = true;
-    channels = {
-      "#tvl" = { };
-      "#tvix-dev" = {
-        only_display = "tvix,nix-compat,third_party,third-party,3p";
-      };
-    };
-
-    # See //fun/clbot for details.
-    flags = {
-      gerrit_host = "cl.tvl.fyi:29418";
-      gerrit_ssh_auth_username = "clbot";
-      gerrit_ssh_auth_key = config.age.secretsDir + "/clbot-ssh";
-
-      irc_server = "localhost:${toString config.services.znc.config.Listener.l.Port}";
-      irc_user = "tvlbot";
-      irc_nick = "tvlbot";
-
-      notify_branches = "canon,refs/meta/config";
-      notify_repo = "depot";
-
-      # This secret is read from an environment variable, which is
-      # populated by a systemd EnvironmentFile.
-      irc_pass = "$CLBOT_PASS";
-    };
-  };
-
-  services.depot = {
-    # Run a livegrep code search instance
-    livegrep.enable = true;
-
-    # Run Nix cache proxy
-    builderball.enable = true;
-
-    # Run the Panettone issue tracker
-    panettone = {
-      enable = true;
-      dbUser = "panettone";
-      dbName = "panettone";
-      irccatChannel = "#tvl";
-    };
-
-    # Run the first cursed bot (quote bot)
-    paroxysm.enable = true;
-
-    # Run the second cursed bot
-    owothia = {
-      enable = true;
-      ircServer = "localhost";
-      ircPort = config.services.znc.config.Listener.l.Port;
-    };
-
-    # Run irccat to forward messages to IRC
-    irccat = {
-      enable = true;
-      config = {
-        tcp.listen = ":4722"; # "ircc"
-        irc = {
-          server = "localhost:${toString config.services.znc.config.Listener.l.Port}";
-          tls = false;
-          nick = "tvlbot";
-          # Note: irccat means 'ident' where it says 'realname', so
-          # this is critical for connecting to ZNC.
-          realname = "tvlbot";
-          channels = [
-            "#tvl"
-          ];
-        };
-      };
-    };
-
-    # Run the Telegram<>IRC bridge for Volga Sprint.
-    teleirc.enable = true;
-
-    # Run atward, the search engine redirection thing.
-    atward.enable = true;
-
-    # Run cgit & josh to serve git
-    cgit = {
-      enable = true;
-      user = "git"; # run as the same user as gerrit
-    };
-
-    josh.enable = true;
-
-    # Configure backups to GleSYS
-    restic = {
-      enable = true;
-      paths = [
-        "/var/backup/postgresql"
-        "/var/lib/grafana"
-        "/var/lib/znc"
-      ];
-    };
-
-    # Run autosubmit bot for Gerrit
-    gerrit-autosubmit.enable = true;
-  };
-
-  services.postgresql = {
-    enable = true;
-    enableTCPIP = true;
-    package = pkgs.postgresql_16;
-
-    authentication = lib.mkForce ''
-      local all all trust
-      host all all 127.0.0.1/32 password
-      host all all ::1/128 password
-      hostnossl all all 127.0.0.1/32 password
-      hostnossl all all ::1/128  password
-    '';
-
-    ensureDatabases = [
-      "panettone"
-    ];
-
-    ensureUsers = [{
-      name = "panettone";
-      ensureDBOwnership = true;
-    }];
-  };
-
-  services.postgresqlBackup = {
-    enable = true;
-    databases = [
-      "keycloak"
-      "panettone"
-      "tvldb"
-    ];
-  };
-
-  # Run a Harmonia binary cache.
-  #
-  # TODO(tazjin): switch to upstream module after fix for Nix 2.3
-  services.depot.harmonia = {
-    enable = true;
-    signKeyPaths = [ (config.age.secretsDir + "/nix-cache-priv") ];
-    settings.bind = "127.0.0.1:6443";
-    settings.priority = 50;
-  };
-
-  services.fail2ban.enable = true;
-
-  environment.systemPackages = (with pkgs; [
-    bat
-    bb
-    curl
-    direnv
-    emacs-nox
-    fd
-    git
-    htop
-    hyperfine
-    jq
-    nano
-    nvd
-    ripgrep
-    tree
-    unzip
-    vim
-    zfs
-    zfstools
-  ]) ++ (with depot; [
-    ops.deploy-whitby
-  ]);
-
-  # Required for prometheus to be able to scrape stats
-  services.nginx.statusPage = true;
-
-  # Configure Prometheus & Grafana. Exporter configuration for
-  # Prometheus is inside the respective service modules.
-  services.prometheus = {
-    enable = true;
-    retentionTime = "90d";
-
-    exporters = {
-      node = {
-        enable = true;
-
-        enabledCollectors = [
-          "logind"
-          "processes"
-          "systemd"
-        ];
-      };
-
-      nginx = {
-        enable = true;
-        sslVerify = false;
-        constLabels = [ "host=whitby" ];
-      };
-    };
-
-    scrapeConfigs = [{
-      job_name = "node";
-      scrape_interval = "5s";
-      static_configs = [{
-        targets = [ "localhost:${toString config.services.prometheus.exporters.node.port}" ];
-      }];
-    }
-      {
-        job_name = "nginx";
-        scrape_interval = "5s";
-        static_configs = [{
-          targets = [ "localhost:${toString config.services.prometheus.exporters.nginx.port}" ];
-        }];
-      }];
-  };
-
-  services.grafana = {
-    enable = true;
-
-    settings = {
-      server = {
-        http_port = 4723; # "graf" on phone keyboard
-        domain = "status.tvl.su";
-        root_url = "https://status.tvl.su";
-      };
-
-      analytics.reporting_enabled = false;
-
-      "auth.generic_oauth" = {
-        enabled = true;
-        client_id = "grafana";
-        scopes = "openid profile email";
-        name = "TVL";
-        email_attribute_path = "mail";
-        login_attribute_path = "sub";
-        name_attribute_path = "displayName";
-        auth_url = "https://auth.tvl.fyi/auth/realms/TVL/protocol/openid-connect/auth";
-        token_url = "https://auth.tvl.fyi/auth/realms/TVL/protocol/openid-connect/token";
-        api_url = "https://auth.tvl.fyi/auth/realms/TVL/protocol/openid-connect/userinfo";
-
-        # Give lukegb, aspen, tazjin "Admin" rights.
-        role_attribute_path = "((sub == 'lukegb' || sub == 'aspen' || sub == 'tazjin') && 'Admin') || 'Editor'";
-
-        # Allow creating new Grafana accounts from OAuth accounts.
-        allow_sign_up = true;
-      };
-
-      "auth.anonymous" = {
-        enabled = true;
-        org_name = "The Virus Lounge";
-        org_role = "Viewer";
-      };
-
-      "auth.basic".enabled = false;
-
-      auth = {
-        oauth_auto_login = true;
-        disable_login_form = true;
-      };
-    };
-
-    provision = {
-      enable = true;
-      datasources.settings.datasources = [{
-        name = "Prometheus";
-        type = "prometheus";
-        url = "http://localhost:9090";
-      }];
-    };
-  };
-
-  # Contains GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET.
-  systemd.services.grafana.serviceConfig.EnvironmentFile = config.age.secretsDir + "/grafana";
-
-  services.keycloak = {
-    enable = true;
-
-    settings = {
-      http-port = 5925; # kycl
-      hostname = "auth.tvl.fyi";
-      http-relative-path = "/auth";
-      proxy-headers = "xforwarded";
-      http-enabled = true;
-    };
-
-    database = {
-      type = "postgresql";
-      passwordFile = config.age.secretsDir + "/keycloak-db";
-      createLocally = false;
-    };
-  };
-
-  # Join TVL Tailscale network at net.tvl.fyi
-  services.tailscale = {
-    enable = true;
-    useRoutingFeatures = "server"; # for exit-node usage
-  };
-
-  # Allow Keycloak access to the LDAP module by forcing in the JVM
-  # configuration
-  systemd.services.keycloak.environment.PREPEND_JAVA_OPTS =
-    "--add-exports=java.naming/com.sun.jndi.ldap=ALL-UNNAMED";
-
-  security.sudo.extraRules = [
-    {
-      groups = [ "wheel" ];
-      commands = [{ command = "ALL"; options = [ "NOPASSWD" ]; }];
-    }
-  ];
-
-  users = {
-    # Set up a user & group for git shenanigans
-    groups.git = { };
-    users.git = {
-      group = "git";
-      isSystemUser = true;
-      createHome = true;
-      home = "/var/lib/git";
-    };
-  };
-
-  zramSwap.enable = true;
-
-  # Use TVL cache locally through the proxy; for cross-builder substitution.
-  tvl.cache.enable = true;
-  tvl.cache.builderball = true;
-
-  system.stateVersion = "20.03";
-}
diff --git a/ops/modules/builderball.nix b/ops/modules/builderball.nix
index d56c695133f2..9c416affc8d0 100644
--- a/ops/modules/builderball.nix
+++ b/ops/modules/builderball.nix
@@ -18,7 +18,6 @@ in
       description = "Public addresses of caches to use";
 
       default = [
-        "whitby.cache.tvl.fyi"
         "nevsky.cache.tvl.fyi"
       ];
     };
diff --git a/ops/modules/known-hosts.nix b/ops/modules/known-hosts.nix
index 9ea689178e3b..93f0ca75ee2f 100644
--- a/ops/modules/known-hosts.nix
+++ b/ops/modules/known-hosts.nix
@@ -3,16 +3,21 @@
 
 {
   programs.ssh.knownHosts = {
-    whitby = {
-      hostNames = [ "whitby.tvl.fyi" "whitby.tvl.su" ];
-      publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILNh/w4BSKov0jdz3gKBc98tpoLta5bb87fQXWBhAl2I";
-    };
-
     sanduny = {
       hostNames = [ "sanduny.tvl.su" ];
       publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOag0XhylaTVhmT6HB8EN2Fv5Ymrc4ZfypOXONUkykTX";
     };
 
+    bugry = {
+      hostNames = [ "bugry.tvl.fyi" ];
+      publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGqG6sITyJ/UsQ/RtYqmmMvTT4r4sppadoQIz5SvA+5J";
+    };
+
+    nevsky = {
+      hostNames = [ "nevsky.tvl.fyi" ];
+      publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHQe7M+G8Id3ZD7j+I07TCUV1o12q1vpsOXHRlcPSEfa";
+    };
+
     github = {
       hostNames = [ "github.com" ];
       publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl";
diff --git a/ops/modules/monitoring.nix b/ops/modules/monitoring.nix
new file mode 100644
index 000000000000..7a186df31f67
--- /dev/null
+++ b/ops/modules/monitoring.nix
@@ -0,0 +1,106 @@
+# Runs the TVL Monitoring setup (currently Grafana + Prometheus).
+{ depot, pkgs, config, lib, ... }:
+
+{
+  # Required for prometheus to be able to scrape stats
+  services.nginx.statusPage = true;
+
+  # Configure Prometheus & Grafana. Exporter configuration for
+  # Prometheus is inside the respective service modules.
+  services.prometheus = {
+    enable = true;
+    retentionTime = "90d";
+
+    exporters = {
+      node = {
+        enable = true;
+
+        enabledCollectors = [
+          "logind"
+          "processes"
+          "systemd"
+        ];
+      };
+
+      nginx = {
+        enable = true;
+        sslVerify = false;
+        constLabels = [ "host=${config.networking.hostName}" ];
+      };
+    };
+
+    scrapeConfigs = [{
+      job_name = "node";
+      scrape_interval = "5s";
+      static_configs = [{
+        targets = [ "localhost:${toString config.services.prometheus.exporters.node.port}" ];
+      }];
+    }
+      {
+        job_name = "nginx";
+        scrape_interval = "5s";
+        static_configs = [{
+          targets = [ "localhost:${toString config.services.prometheus.exporters.nginx.port}" ];
+        }];
+      }];
+  };
+
+  services.grafana = {
+    enable = true;
+
+    settings = {
+      server = {
+        http_port = 4723; # "graf" on phone keyboard
+        domain = "status.tvl.su";
+        root_url = "https://status.tvl.su";
+      };
+
+      analytics.reporting_enabled = false;
+
+      "auth.generic_oauth" = {
+        enabled = true;
+        client_id = "grafana";
+        scopes = "openid profile email";
+        name = "TVL";
+        email_attribute_path = "mail";
+        login_attribute_path = "sub";
+        name_attribute_path = "displayName";
+        auth_url = "https://auth.tvl.fyi/auth/realms/TVL/protocol/openid-connect/auth";
+        token_url = "https://auth.tvl.fyi/auth/realms/TVL/protocol/openid-connect/token";
+        api_url = "https://auth.tvl.fyi/auth/realms/TVL/protocol/openid-connect/userinfo";
+
+        # Give lukegb, aspen, tazjin "Admin" rights.
+        role_attribute_path = "((sub == 'lukegb' || sub == 'aspen' || sub == 'tazjin') && 'Admin') || 'Editor'";
+
+        # Allow creating new Grafana accounts from OAuth accounts.
+        allow_sign_up = true;
+      };
+
+      "auth.anonymous" = {
+        enabled = true;
+        org_name = "The Virus Lounge";
+        org_role = "Viewer";
+      };
+
+      "auth.basic".enabled = false;
+
+      auth = {
+        oauth_auto_login = true;
+        disable_login_form = true;
+      };
+    };
+
+    provision = {
+      enable = true;
+      datasources.settings.datasources = [{
+        name = "Prometheus";
+        type = "prometheus";
+        url = "http://localhost:9090";
+      }];
+    };
+  };
+
+  # Contains GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET.
+  systemd.services.grafana.serviceConfig.EnvironmentFile = config.age.secretsDir + "/grafana";
+}
+
diff --git a/ops/modules/monorepo-gerrit.nix b/ops/modules/monorepo-gerrit.nix
index dd57a57b8665..5c8c8e84115c 100644
--- a/ops/modules/monorepo-gerrit.nix
+++ b/ops/modules/monorepo-gerrit.nix
@@ -4,7 +4,7 @@
 let
   cfg = config.services.gerrit;
 
-  besadiiWithConfig = name: pkgs.writeShellScript "besadii-whitby" ''
+  besadiiWithConfig = name: pkgs.writeShellScript "besadii-hook" ''
     export BESADII_CONFIG=/run/agenix/gerrit-besadii-config
     exec -a ${name} ${depot.ops.besadii}/bin/besadii "$@"
   '';
diff --git a/ops/modules/restic.nix b/ops/modules/restic.nix
index 869539603578..06e470bb559a 100644
--- a/ops/modules/restic.nix
+++ b/ops/modules/restic.nix
@@ -1,15 +1,13 @@
 # Configure restic backups to S3-compatible storage, in our case
-# GleSYS object storage.
+# Yandex Cloud Storage.
 #
-# Conventions:
-# - restic's cache lives in /var/backup/restic/cache
-# - repository password lives in /var/backup/restic/secret
-# - object storage credentials in /var/backup/restic/glesys-key
-{ config, lib, pkgs, ... }:
+# When adding a new machine, the repository has to be initialised once. Refer to
+# the Restic documentation for details on this process.
+{ config, depot, lib, pkgs, ... }:
 
 let
   cfg = config.services.depot.restic;
-  description = "Restic backups to GleSYS";
+  description = "Restic backups to Yandex Cloud";
   mkStringOption = default: lib.mkOption {
     inherit default;
     type = lib.types.str;
@@ -18,9 +16,9 @@ in
 {
   options.services.depot.restic = {
     enable = lib.mkEnableOption description;
-    bucketEndpoint = mkStringOption "objects.dc-sto1.glesys.net";
-    bucketName = mkStringOption "aged-resonance";
-    bucketCredentials = mkStringOption "/var/backup/restic/glesys-key";
+    bucketEndpoint = mkStringOption "storage.yandexcloud.net";
+    bucketName = mkStringOption "tvl-backups";
+    bucketCredentials = mkStringOption "/run/agenix/yc-restic";
     repository = mkStringOption config.networking.hostName;
     interval = mkStringOption "hourly";
 
@@ -36,15 +34,20 @@ in
   };
 
   config = lib.mkIf cfg.enable {
+    age.secrets = {
+      restic-password.file = depot.ops.secrets."restic-${config.networking.hostName}.age";
+      yc-restic.file = depot.ops.secrets."yc-restic.age";
+    };
+
     systemd.services.restic = {
-      description = "Backups to GleSYS";
+      description = "Backups to Yandex Cloud";
 
       script = "${pkgs.restic}/bin/restic backup ${lib.concatStringsSep " " cfg.paths}";
 
       environment = {
         RESTIC_REPOSITORY = "s3:${cfg.bucketEndpoint}/${cfg.bucketName}/${cfg.repository}";
         AWS_SHARED_CREDENTIALS_FILE = cfg.bucketCredentials;
-        RESTIC_PASSWORD_FILE = "/var/backup/restic/secret";
+        RESTIC_PASSWORD_FILE = "/run/agenix/restic-password";
         RESTIC_CACHE_DIR = "/var/backup/restic/cache";
 
         RESTIC_EXCLUDE_FILE =
diff --git a/ops/modules/teleirc.nix b/ops/modules/teleirc.nix
index 9f9ac059ce38..6b076a2dd28d 100644
--- a/ops/modules/teleirc.nix
+++ b/ops/modules/teleirc.nix
@@ -5,7 +5,7 @@
 { depot, config, lib, pkgs, ... }:
 
 let
-  cfg = config.services.depot.owothia;
+  cfg = config.services.depot.teleirc;
   description = "IRC<>Telegram sync for Volga Sprint channel";
   configFile = builtins.toFile "teleirc.env" ''
     # connect through tvlbot's ZNC bouncer
diff --git a/ops/modules/tvl-buildkite.nix b/ops/modules/tvl-buildkite.nix
index d9d79cd52782..003a36fc6a5c 100644
--- a/ops/modules/tvl-buildkite.nix
+++ b/ops/modules/tvl-buildkite.nix
@@ -27,10 +27,17 @@ in
 {
   options.services.depot.buildkite = {
     enable = lib.mkEnableOption description;
+
     agentCount = lib.mkOption {
       type = lib.types.int;
       description = "Number of Buildkite agents to launch";
     };
+
+    largeSlots = lib.mkOption {
+      type = lib.types.int;
+      default = cfg.agentCount;
+      description = "Number of agents with 'large=true'";
+    };
   };
 
   config = lib.mkIf cfg.enable {
@@ -50,6 +57,9 @@ in
 
           tags.hostname = hostname;
 
+          # all agents support small jobs
+          tags.small = "true";
+
           runtimePackages = with pkgs; [
             bash
             coreutils
@@ -61,7 +71,9 @@ in
             jq
             nix
           ];
-        };
+        } // (lib.optionalAttrs (n <= cfg.largeSlots) {
+          tags.large = "true";
+        });
       })
       agents);
 
diff --git a/ops/modules/www/cache.tvl.fyi.nix b/ops/modules/www/cache.tvl.fyi.nix
index b0c90267ace6..88f8131c4f1c 100644
--- a/ops/modules/www/cache.tvl.fyi.nix
+++ b/ops/modules/www/cache.tvl.fyi.nix
@@ -6,6 +6,9 @@ let
   # This attrset forms a linked list of hosts, which delegate ACME fallbacks to
   # each other. These *must* form a circle, otherwise we may end up walking only
   # part of the ring.
+  #
+  # TODO: remove whitby from here, it is gone; leaving this code for now for
+  # easier discovery when reconfiguring this.
   acmeFallback = host: ({
     whitby = "nevsky.cache.tvl.fyi";
     nevsky = "whitby.cache.tvl.fyi"; # GOTO 1
@@ -26,7 +29,9 @@ in
       # hosts. This config is kind of messy; it would be nice to generate a
       # correct ring from the depot fixpoint, but this may be impossible due to
       # infinite recursion. Please read the comment on `acmeFallback` above.
-      acmeFallbackHost = acmeFallback config.networking.hostName;
+      #
+      # TODO: whitby is gone, this is not needed at the moment
+      # acmeFallbackHost = acmeFallback config.networking.hostName;
 
       extraConfig = ''
         location = /cache-key.pub {
diff --git a/ops/mq_cli/Cargo.toml b/ops/mq_cli/Cargo.toml
index 816a37075977..8f34bd8e9d3c 100644
--- a/ops/mq_cli/Cargo.toml
+++ b/ops/mq_cli/Cargo.toml
@@ -4,7 +4,7 @@ description = "CLI tool for accessing POSIX message queues (mq_overview(7))"
 license = "MIT"
 version = "3773.0.0"
 authors = ["Vincent Ambo <tazjin@tvl.su>"]
-homepage = "https://cs.tvl.fyi/depot/-/tree/ops/mq_cli"
+homepage = "https://code.tvl.fyi/tree/ops/mq_cli"
 repository = "https://code.tvl.fyi/depot.git:/ops/mq_cli.git"
 
 [dependencies]
diff --git a/ops/mq_cli/README.md b/ops/mq_cli/README.md
index 1045de896b02..f45cd2128557 100644
--- a/ops/mq_cli/README.md
+++ b/ops/mq_cli/README.md
@@ -30,7 +30,7 @@ SUBCOMMANDS:
 ## Development
 
 Development happens in the [TVL
-monorepo](https://cs.tvl.fyi/depot/-/tree/ops/mq_cli).
+monorepo](https://code.tvl.fyi/tree/ops/mq_cli).
 
 Starting from version `3773.0.0`, the version numbers correspond to
 _revisions_ of the TVL repository, available as git refs (e.g.
diff --git a/ops/nixos.nix b/ops/nixos.nix
index b75b5efacb9f..de649711fa41 100644
--- a/ops/nixos.nix
+++ b/ops/nixos.nix
@@ -60,9 +60,8 @@ in rec {
   '';
 
   # Systems that should be built in CI
-  whitbySystem = (nixosFor depot.ops.machines.whitby).system;
   sandunySystem = (nixosFor depot.ops.machines.sanduny).system;
   bugrySystem = (nixosFor depot.ops.machines.bugry).system;
   nevskySystem = (nixosFor depot.ops.machines.nevsky).system;
-  meta.ci.targets = [ "sandunySystem" "whitbySystem" "bugrySystem" "nevskySystem" ];
+  meta.ci.targets = [ "sandunySystem" "bugrySystem" "nevskySystem" ];
 }
diff --git a/ops/pipelines/depot.nix b/ops/pipelines/depot.nix
index 05e3ca0d8e9d..f88250360cef 100644
--- a/ops/pipelines/depot.nix
+++ b/ops/pipelines/depot.nix
@@ -28,10 +28,10 @@ let
           nix-build -A ci.gcroot --out-link /nix/var/nix/gcroots/depot/canon
         '';
 
-        # Ensure that anchoring happens on whitby, so that cache.tvl.su always
+        # Ensure that anchoring happens on nevsky, so that cache.tvl.su always
         # has the full cache. Unanchored machines may garbage collect live
         # paths.
-        agents.hostname = "whitby"; # TODO(tazjin): b/433
+        agents.hostname = "nevsky";
       }
     ];
   };
diff --git a/ops/pipelines/static-pipeline.yaml b/ops/pipelines/static-pipeline.yaml
index 090518423eb3..dc57c4e46900 100644
--- a/ops/pipelines/static-pipeline.yaml
+++ b/ops/pipelines/static-pipeline.yaml
@@ -50,7 +50,8 @@ steps:
   - label: ":llama:"
     key: "pipeline-gen"
     concurrency_group: 'depot-nix-eval'
-    concurrency: 3 # much more than this and whitby will OOM
+    concurrency: 4 # TODO: limit per builder host?
+    priority: 1
     command: |
       set -ue
 
diff --git a/ops/posix_mq.rs/Cargo.toml b/ops/posix_mq.rs/Cargo.toml
index 8390b80b86f0..3495f9461489 100644
--- a/ops/posix_mq.rs/Cargo.toml
+++ b/ops/posix_mq.rs/Cargo.toml
@@ -4,7 +4,7 @@ version = "3771.0.0"
 authors = ["Vincent Ambo <tazjin@tvl.su>"]
 description = "(Higher-level) Rust bindings to POSIX message queues"
 license = "MIT"
-homepage = "https://cs.tvl.fyi/depot/-/tree/ops/posix_mq.rs"
+homepage = "https://code.tvl.fyi/tree/ops/posix_mq.rs"
 repository = "https://code.tvl.fyi/depot.git:/ops/posix_mq.rs.git"
 
 [dependencies]
diff --git a/ops/posix_mq.rs/README.md b/ops/posix_mq.rs/README.md
index 800d2221e492..91e46b7dc06d 100644
--- a/ops/posix_mq.rs/README.md
+++ b/ops/posix_mq.rs/README.md
@@ -31,7 +31,7 @@ let result = queue.receive().expect("message receiving failed");
 ## Development
 
 Development happens in the [TVL
-monorepo](https://cs.tvl.fyi/depot/-/tree/ops/posix_mq.rs).
+monorepo](https://code.tvl.fyi/tree/ops/posix_mq.rs).
 
 Starting from version `3771.0.0`, the version numbers correspond to
 _revisions_ of the TVL repository, available as git refs (e.g.
diff --git a/ops/secrets/besadii.age b/ops/secrets/besadii.age
index 1b8ef6758c38..f52f82449011 100644
--- a/ops/secrets/besadii.age
+++ b/ops/secrets/besadii.age
Binary files differdiff --git a/ops/secrets/buildkite-agent-token.age b/ops/secrets/buildkite-agent-token.age
index 48b6d7a169dc..d6b864066784 100644
--- a/ops/secrets/buildkite-agent-token.age
+++ b/ops/secrets/buildkite-agent-token.age
Binary files differdiff --git a/ops/secrets/buildkite-graphql-token.age b/ops/secrets/buildkite-graphql-token.age
index 2b3c2fc43ba4..dc2a9b7de9b0 100644
--- a/ops/secrets/buildkite-graphql-token.age
+++ b/ops/secrets/buildkite-graphql-token.age
Binary files differdiff --git a/ops/secrets/buildkite-ssh-private-key.age b/ops/secrets/buildkite-ssh-private-key.age
index c8ce1a1546be..2ebb315ffba5 100644
--- a/ops/secrets/buildkite-ssh-private-key.age
+++ b/ops/secrets/buildkite-ssh-private-key.age
Binary files differdiff --git a/ops/secrets/clbot-ssh.age b/ops/secrets/clbot-ssh.age
index c24f8f45d3da..9c7038972816 100644
--- a/ops/secrets/clbot-ssh.age
+++ b/ops/secrets/clbot-ssh.age
Binary files differdiff --git a/ops/secrets/clbot.age b/ops/secrets/clbot.age
index 2cec1f7f36c7..f36387192f63 100644
--- a/ops/secrets/clbot.age
+++ b/ops/secrets/clbot.age
Binary files differdiff --git a/ops/secrets/depot-inbox-imap.age b/ops/secrets/depot-inbox-imap.age
index 9bce1845cb88..8104b12d29eb 100644
--- a/ops/secrets/depot-inbox-imap.age
+++ b/ops/secrets/depot-inbox-imap.age
@@ -1,15 +1,17 @@
 age-encryption.org/v1
--> ssh-ed25519 dcsaLw cpeIOVtFcfaHZpIAp495fkQLJoT++h1v6p0crBeuzFM
-+zomKCg7UVNl/FlfcZflVPbo48C45uGoGoR1tbetEdk
--> ssh-ed25519 zcCuhA loSmQUCnO0EBaGg+wFYYkXOdLBQ6Z+pPl4Y3oGx6xzw
-+RdXNYYtIDDXGr1Z0Mh28psvF9gzg12M3EJTUqmdFtU
--> ssh-ed25519 CpJBgQ 0W0LWu8WW6pQzUhK21CeNDUtW0srwR5gNCRjwTy94B4
-A02F+AyP+DajnVTJakx+0jynYRDix9I/9uZUDPjXpis
--> ssh-ed25519 aXKGcg SVBo2urAYGSYrlj3ieoi9nkrffcZ9ZroCn86pZkn4nI
-xQRrLNeNcI9cpQY+X2xfLDoBqLNQixGjaYtMDWtHio4
--> ssh-ed25519 BXptmQ UKNJPPjIiqPQndZ6/yASSg+5PQIn2N9nUy2hQMREq1Y
-X9zM/ji9R3jLOEDGLpIVESjU13VU0e3cTAR1xEMhY5I
--> B-grease Y
-vUOYknqY0okoUOKZD/8MpnpwkOU31sszuUZfeSVsuVyUMPEbFjWQT74
---- ymKMaoUQXFPRc9U0ZvULBEC0Az0ew2oEyHwH/kR9ETI
-Eu	xe_)zPhsGBLQ
\ No newline at end of file
+-> ssh-ed25519 BXptmQ Vs02ZiJLNF5EFwROHDRmK6c63B+i34O4iUe5px+ylVI
+oAlTA+SCuWdg9GDRRIAzZ8dzm1CeJ32v40i2uuCUBC4
+-> ssh-ed25519 dcsaLw 60SJdc9bFol7lRKarzH/0SSHTdvOafJw7LM2Ryg9ORs
+nwwIlne48VJ1Pf8fen3Nw4Z39d/4aU0HvlGoCtiKhWk
+-> ssh-ed25519 zcCuhA sZSaSac/2iB2RoNKkD1IRDHW8efafmfWzHg5zp/680E
+HndqDG6ErSmrlpY08HoJ/2O+xeNRTqhdBVP1ZwfokfM
+-> ssh-ed25519 1SxhRA 9AjHrUjAr3O02Hsv0Opx9ge5bx8qA/Kvra95Kz9augo
+GZOL8dR+36ObR+fPAOzp/1jyuVlgcakQhQ7ewbCo3O0
+-> ssh-ed25519 ch/9tw Qjlt8WTWe77gz37/oIK5pwpSL8rOic8vZ5cFFeIaqng
+h7DbM8R/hQzaVgYx+PS7p4RHYtA0GTpF/6/Y7gdS9EM
+-> ssh-ed25519 CpJBgQ RIQKivyWL+MG7E/IgmjOyU4NEWqI6cxD+F1tZ62fcgw
+Lz/XRQ2UHT1RGIZ2HS/IR/rYdR+AynaKIkhml/RPRbA
+-> ssh-ed25519 aXKGcg pMzqW01tUgywYyKTeiI0zmlM961kAf4R4OQdjOlmKA8
+P//iqR6HJ0eQodv4F/4kVDzVUwJztsbfrxqonJa1aQQ
+--- /vmQh4qM0gBaIDcZGNKwsHIKZYJanwpqowpjuke1Q1E
+˧|H$^8&z.Dj	E/nA2yl%<6
\ No newline at end of file
diff --git a/ops/secrets/depot-replica-key.age b/ops/secrets/depot-replica-key.age
index 5e8ce94d5d61..08d0ba3b7c69 100644
--- a/ops/secrets/depot-replica-key.age
+++ b/ops/secrets/depot-replica-key.age
Binary files differdiff --git a/ops/secrets/gerrit-autosubmit.age b/ops/secrets/gerrit-autosubmit.age
index 2e04be952d55..344806035b7b 100644
--- a/ops/secrets/gerrit-autosubmit.age
+++ b/ops/secrets/gerrit-autosubmit.age
Binary files differdiff --git a/ops/secrets/gerrit-secrets.age b/ops/secrets/gerrit-secrets.age
index 9ad123d578d4..96434ba3a042 100644
--- a/ops/secrets/gerrit-secrets.age
+++ b/ops/secrets/gerrit-secrets.age
Binary files differdiff --git a/ops/secrets/grafana.age b/ops/secrets/grafana.age
index eef349d64c09..d69f61ce5395 100644
--- a/ops/secrets/grafana.age
+++ b/ops/secrets/grafana.age
Binary files differdiff --git a/ops/secrets/irccat.age b/ops/secrets/irccat.age
index 2002b15c4957..43b73f9b9f00 100644
--- a/ops/secrets/irccat.age
+++ b/ops/secrets/irccat.age
Binary files differdiff --git a/ops/secrets/journaldriver.age b/ops/secrets/journaldriver.age
index c58773f36b21..16f00ed8e545 100644
--- a/ops/secrets/journaldriver.age
+++ b/ops/secrets/journaldriver.age
Binary files differdiff --git a/ops/secrets/keycloak-db.age b/ops/secrets/keycloak-db.age
index 54194df18383..a2fe655008c2 100644
--- a/ops/secrets/keycloak-db.age
+++ b/ops/secrets/keycloak-db.age
@@ -1,15 +1,19 @@
 age-encryption.org/v1
--> ssh-ed25519 dcsaLw tWBrwZf6FNYAHRjoVV9/X6gJCXPqxZSoA01dvIrIOzg
-6W2A3smrrosM3sJgl5CT9vkCWqVKR3SaSxWS2nnwKJU
--> ssh-ed25519 zcCuhA IS0OcHfEfb01xe+FJUe1poruK+uuP0MaJpeoGYyVAFY
-eEzcEYcW4KoKZZUEH/ha1nn9NudeK9HgPRgmrCWMjug
--> ssh-ed25519 CpJBgQ 4mjCHMHfnGu2bhANPBNmcrZQrKBcPgZU+ll8opmvGCk
-0+Vd6pRPovUcKa9i37JVU/DUeYAmJ9D88MR4flA8gY8
--> ssh-ed25519 aXKGcg WGCgCoViKLqndC35OTaExqZlPBDRwXRBJFuS7fw8n3Q
-kUHunOUgIsxXmOzMCwUFF/0dYiae8YZGmgZaz8gXPJo
--> ssh-ed25519 OkGqLg LLIDJkImcqMjwRitnGevcav5YjDwYsQ//elx7fgbCQ4
-EnYTppSr/GKug9T+bFLGxrxUnNiXD5ODhB75OcH/h24
--> j@-grease @:arA
-8EFNz7i8N3gbZEMaQw
---- RkHJIg9pif/R47lgqrZD/XgkTETxXWkwW9QnFFsmfOA
-o]~6+jn]l+K=ʽ	Zp9RzVg u2_
\ No newline at end of file
+-> ssh-ed25519 OkGqLg 85hbcQ9r29CC95B1CXO+uftm7ywhTeWCpklX4hOc2gU
+7EO8O5/eg1noB8nbl9XL+m8WAvLp6QnA25CiTsp5jfY
+-> ssh-ed25519 xR+E/Q Hefp9fWCq9sWdgyKp3gNEO1p9yWFK4sYX8xMxkyy9G4
+JXofip2LGkJFDBb+6DegoFGDPjk8FGF+AqaAy5FPqwk
+-> ssh-ed25519 dcsaLw IUoPTD1SfnY/wXXFcIc6h47fea6ukWAurUmfqwTQOAs
+G/YeKUk8IQXBQ1q8338HxUg2vXqmh8LOIHSX4Qn1CFo
+-> ssh-ed25519 zcCuhA 2LrAbe+Jpsg6gFzbnx3ppDesbQSWqzHs2uOv9szb80U
+idJNMv6Lf0k2NsfOcm7it8LwPYxjdq7+LS7PUzQ89Qg
+-> ssh-ed25519 1SxhRA idcz/kk9WyIA4I2NwzzPiMX0AmXkV3FTHxoE12n2eWQ
+e+4am77QT0fDv9Xgci4L+VsgFyKT4ZHjB0FWe76hV3g
+-> ssh-ed25519 ch/9tw RNZWeD7W18wpcpBksipmib6vhHmaCP5iQeK4uLHU604
+bH/PJprw6+jEktmPnS3OrGMtJ/XHYVZQoQRdReLkLYM
+-> ssh-ed25519 CpJBgQ w9gTapqMBoJl+C4sWIGIDCZpemRCEu1iDUUWFt2rW0A
+1nYU4UiHYT9vPASYHwunK2Td+acAmjzRpFpLioNneJc
+-> ssh-ed25519 aXKGcg evsnA8cq5xz+0GdKT7cBZWckBpX+w05yLOOaOL4+0BM
+LigkUyewAl+O0KBKuykbwKzFTCY5n6lnCcarl2Vu0NE
+--- KhA9LmsAYYPMrJrsJYZyEq04LvrMZkJaCL5Bt5ruYD0
+VO{$[nG7
/g0qCn9í(g􍨮b@
\ No newline at end of file
diff --git a/ops/secrets/litestream-glesys b/ops/secrets/litestream-glesys
new file mode 100644
index 000000000000..27483986b397
--- /dev/null
+++ b/ops/secrets/litestream-glesys
@@ -0,0 +1,14 @@
+age-encryption.org/v1
+-> ssh-ed25519 dcsaLw 1vQZwlLz6KEyzNB7mtPpw/V3587IfMfyzTbo415W8l4
+eHrGv8UAlPHGrz95qerbeKALKdE3WAsgaG0iApapw2s
+-> ssh-ed25519 CpJBgQ OM8rXUX7/e+OUMzeg5l0/4iDpN83E0bizA0sSEQ1Bik
+Rv1dgo2nWNFp1RtxJzd1Bs/rSVJlQuuRRcfabneW54U
+-> ssh-ed25519 aXKGcg Y5jY0MG1AkE3QnUSbVgpo03ZmjisTEaE092001svumY
+yEfLoBPkq3c8svnRSSRynvePXel3f0ExxWiMlZOQL5E
+-> ssh-ed25519 OkGqLg 1MKnCM9FC54nDkjKvOyrbv5PajZILWMGyZn3etmvHm0
+ZZKJ3B4dVK+zs05o1TWdnG3nvsgWyCncblVq1jB9OsU
+-> tTdCE`G-grease V<"wt`:| V^yWF$>a ]0K Z)k|}v
+ZpwiZsQkV71PhB/NRKrwFxu3HlJkerPtAjB5TintCRjogQlfB1DQTv47jnsui4hJ
+
+--- v9cVC9zi/w4pqGPUtc3jrAg8sMHtlPGuXyDIimEQpok
+Oϔdmn2|[u#I0^#\2!*jɤC\)Qi2å|ku(a0"t=5bpUfC{jHr&M/k8KpFh:+ 0ΣA8wńD7] p$.5
\ No newline at end of file
diff --git a/ops/secrets/nix-cache-priv.age b/ops/secrets/nix-cache-priv.age
index 47d185b9f042..21e4be4c521d 100644
--- a/ops/secrets/nix-cache-priv.age
+++ b/ops/secrets/nix-cache-priv.age
Binary files differdiff --git a/ops/secrets/nix-cache-pub.age b/ops/secrets/nix-cache-pub.age
index 97a09f1ebae6..fa63dea94cb6 100644
--- a/ops/secrets/nix-cache-pub.age
+++ b/ops/secrets/nix-cache-pub.age
@@ -1,19 +1,19 @@
 age-encryption.org/v1
--> ssh-ed25519 dcsaLw ZBYqyCd+eJH8b6nuG3Off01ZRz+C8wBlXzXsHtKrPA8
-6xsUZDVJ+gsKW2XdEdRUlQv6enO3lSy7pfydhAhA2UM
--> ssh-ed25519 zcCuhA aYLfg5xvfDAL2fRCd/cKaNAf3nuMUKqkqtLQyPN6elE
-vfVIu+7QKOzrmZ08drUdBYTksaT+kHbj7kVxl5QPb9U
--> ssh-ed25519 1SxhRA x9YVX3XS0BNy6uWPACM+Q6dNY2/Grn4gBAZt7ZCc5GQ
-m7KFpWpsM/5tNeFgPQb6VosYJv/IJES79H3E5epvvgE
--> ssh-ed25519 ch/9tw MtZL+fIC9PeF4j4mJY+oF3KurgBtIrjP2Cnga6VV/Uk
-wGMsl48+SDfskXjtsMRheWvelDON6pMR288GAKhY2PU
--> ssh-ed25519 CpJBgQ ICy5pQo+1pEXDvvvCHJahEnt8P0Ws/KSLg5eruNNS1Y
-JBds2McxDga23lojtVlm3QFav9D/SnfO14RCkz/vy3o
--> ssh-ed25519 aXKGcg sO0sT+XRpZ05yn49HlPYHQi3/wrJ7dpy+S7L5HJjCVY
-ZDMWrcYhie2tzad5qPuAU1E978LVLTkQGb1rrjWsxeo
--> ssh-ed25519 OkGqLg rl4dVxI+gUNyjdrQpRpAV/7HHrcY6sT8a/mxBWidmCM
-HCF9eR6GstX9FOHkTpTU8oulphwu+LCbsr1NyWktWPQ
--> ssh-ed25519 xR+E/Q lhTKIL2kGhR/de7kRShGCHMRsZVPlXfGxaMX3Q1Op1M
-fYiPRboq/bAsbtZQfbS1zlV7HjxeOKwFcafZSDETpdI
---- /UN5QN0v3yyH0Vh9tv1u8GXnBX9j8nTkzezYVIXK+ds
-LtYS̰۲2EqnH`-(0}۱ʬ&ٯCL#.yMywy9mFQhLu
\ No newline at end of file
+-> ssh-ed25519 OkGqLg +GawUpoCoveZOVr8oFF5Cx87JrHB/DLk8+ctBYy3mGs
+14pGg24B55KpO0m0Y8h7WaXswuXN3fYOklYJpUNlO+Q
+-> ssh-ed25519 xR+E/Q PamJ1jmdaXA69yen2yaiEYBSOzemjMK7CJtvqHIF+l8
+4fm0atyNq7lGXKBJBe+qj04hDZyMv0aLAYB5do04p9Y
+-> ssh-ed25519 dcsaLw 2spxBNvNgrfRRFmw4+3qOXJRyOSpqIM5LjWwxw3nKXQ
+bkUj+mwZIGH8ollRJ4Fo0m/d2SjYHvtJ+XQZ1UyYoJM
+-> ssh-ed25519 zcCuhA b0thXNRODt5ex8V8nhnsRkTV0tJIKYLTOstdla4hLSI
+BRqHrvCRVua/GeAm//7lTCcvUd5rnfUjp3y7rlVYlck
+-> ssh-ed25519 1SxhRA JMqW8QVkIYI3EtOacMpdgVJ6bLyy6OmVCsTpN3DlpyY
+GbIpKf+cISO6oOVEZPvv1pcvHWsEb/N1Xi+Ir4EGDJc
+-> ssh-ed25519 ch/9tw +ysMVMAXfw1cL0a5JQMEoKA0qc3YvAnk+/OzL4ObCiw
+eBpIZy1M2jvxfZQcxiQj3xUSd2xRISjp/EX5v2Opoac
+-> ssh-ed25519 CpJBgQ oII0q9KXaP2qbQ4uvDHCwNURojZVV9XTuR/oh33pPT8
+lv5XPdZ6Jrk2+RQKgq585fLN88Fy5daslIzrLX74VR8
+-> ssh-ed25519 aXKGcg fkMoxXoGVVBb9Hw1hpq42cgEimgitgdm2MeLu4zPlFA
+KV3ZcS87HMYikFsDZMLYfZn3oANuhziTB/WQOS7BZZo
+--- yQHOSIohfnwePFQjAJjRAPetIbhhdHlGEdfVZ1TKmso
+Ay~}}F\?Qo슴<)/O\5}`C"OʺN.(=oEPp>сmwr
\ No newline at end of file
diff --git a/ops/secrets/owothia.age b/ops/secrets/owothia.age
index 177ee61383c9..409b5a04222d 100644
--- a/ops/secrets/owothia.age
+++ b/ops/secrets/owothia.age
@@ -1,16 +1,20 @@
 age-encryption.org/v1
--> ssh-ed25519 dcsaLw 8XtdgZ++/ZqmK4j8CO8oiuskTxjvKhWDK7fet5hbqiM
-Fs4O1vFtQL1JamnuCMPLzfzRPb90nxfXB6OXkyCMoHo
--> ssh-ed25519 zcCuhA 6PNsPMdRXM77ci+mBQNRxr1oMGDNdlQilpUB0Q5es28
-APw2L/0htM9U0fJ1IUthdkoem/UTM/6NNQrgn4Vmpcs
--> ssh-ed25519 CpJBgQ ed00il0q23M+3KH6hf5fFPaXGUKcz03Bn01jSoKiB1U
-jEN0Dk2edJBQreAlNE11sx0cI5u1mfFDT11Ev0KJ+gs
--> ssh-ed25519 aXKGcg NocBhG6QGlWDZhjsA6Sxvjv9Gs+3Pq5gcOqnVdiefBg
-HYnqBv0pdPz8bqgZ98VDfYFeKcFNeuJrlOsyWt551Sg
--> ssh-ed25519 OkGqLg e0081m/IkQafXh1gAWUZ2glYG7bklCG/LaUy63rK6gc
-G2RNMxCxRnqocYhiq142T8EPZQD8cRHHs7AHKFrMLaU
--> +J}@hPk-grease
-406BMfqUt/KjayTopj4dNa4owPZphR6AsBXPurJwU/zV9ipirfW3oEeaprdh4uLg
-RHO0bSZQV1uu1YmbXkuwMaVj1cVn2vsDPEv3xG2SRzMoEpAAKaFCBba8
---- 5ncLI9pS25vz5CebIZjPPDQ5cHISlyRFF55rGgFQnnM
-$"PK&C\(G[(
DlǺ84P)BԼc\U:(
\ No newline at end of file
+-> ssh-ed25519 OkGqLg V7q6p9/JpvhDiSZelm6WUm7K8k1JPiG881M/CcD61j0
+CyWBMz5f2rOS3nyASYoNfRUyGdk4z+azqWca5Sm+Rn8
+-> ssh-ed25519 xR+E/Q m5zf52PK6k9d1slMbFi1kLHzjcwPTvS/pxpLxFkWEh8
+hgBAxWxRSoVfL5+RUcMW3+H09HpZRK9UYKexgwqCJVM
+-> ssh-ed25519 dcsaLw eoA43fKH9hP/rdX7G3Kk4nBeqZsqIZK5WJ8fOFz93Hc
+NaxeAjxHL7UnoWEYpCWnroe0VQVz+TdYxFhzgEJvCO8
+-> ssh-ed25519 zcCuhA WKauLNBLl2IazpVCfYSIdR7IHouKrUUPRNbso0f5dG0
+ixod/zrotKIrVKTWAvo0bebJRuIeKbAkrjM2sF14R2c
+-> ssh-ed25519 1SxhRA uhklukoJL+Un1OLTjzu4/tW5FlnI5PxHmqkPEjqqbBg
+DPiA5zqTUlTdagC6gaz/vlEWP71DCEVWB5DWw1s61GE
+-> ssh-ed25519 ch/9tw Oml7do+MW+p8DYOyEazBjbdKNSSUUTAMPsr44xr5Zyk
+CrIGkD6qJYKcYLaV2yOqaTzlPjGUZ5dTjOQRyeDJ+C8
+-> ssh-ed25519 CpJBgQ fVac72oIPKjTYdnWD+g0AmpioPwtCo7AH94DNroyB38
+1Y1CBtJGgqYhXWRst0vUlcUhV3wQ8ONgJd8P3JbcOLU
+-> ssh-ed25519 aXKGcg G6ic4O1dPsnWSntXoK/85BdyMkeRb9sp9eJwuBShJAc
+AyXRzW7Mn3zB96SiUpaX/gnnbbO/2AszySviul96xNg
+--- gMS+evsP3XoJC1Zo8AWqNoThdm6KQ2ZiU/+/DWfB5/w
+/bUNy݃)`a9sD#tЫ]	7k1C"=7\
+C%$a
\ No newline at end of file
diff --git a/ops/secrets/panettone.age b/ops/secrets/panettone.age
index 0be42dc0a779..7fa47bf39f95 100644
--- a/ops/secrets/panettone.age
+++ b/ops/secrets/panettone.age
@@ -1,15 +1,19 @@
 age-encryption.org/v1
--> ssh-ed25519 dcsaLw zzUe0JqhICtd/kgZnXFpwaQ1Ma6nqy/hMWaOJpRHmDs
-4cR+OnWShG6MpB/u0yfsSxplEch7x7DbygfBiJGxOOs
--> ssh-ed25519 zcCuhA 0RZEYC9IuazO9fROalwoOCIgc0j+rNBP3gw7SKG0yEw
-mPRhN0hvccEr1A9ihWAFMH4/24vpBKpxBVq4BKBMmYM
--> ssh-ed25519 CpJBgQ VrmfTtTVxuQmpUxMxtXtCnr8pFyqwtdyLHdbzYrlKlM
-kHgEdPmoIOLnGuMF5F5Ol1yZWcactSE4OZI0BSmDN+g
--> ssh-ed25519 aXKGcg On4jwgsH504ZjYRwfw5oAfIDk3wU0+xgd43ryAn9H0I
-fayzht1ZPPiFCjuYTdwVtJu2nOUg4wtp5IipOR4oJm8
--> ssh-ed25519 OkGqLg mubp0xI0fvsKOAUaNaftFkHJ+bxgFHbgjn+A7sR8XVs
-X68Zr8HvC4/XPC0AFIA5f1SKu7NSR/23oeX8cW1qfis
--> ?`-grease
-hOy2Rwvk6+vXpHWWA49Wp10wKbw9TfsLXw
---- 9MLGx6BVm40C0CSV3bq6dnXrpy3QunBlh2/uO5OisUU
-dzG<YAVs/-%g.e@,ZFW收&<Oq@>w̛Q>-gǓ'`XҟP8x<RNv9#'/)gm2v<,7邢qvQAO-ژ+gc#޵*e -) ;
\ No newline at end of file
+-> ssh-ed25519 OkGqLg BEro34+d66EFK/Pt2zxpaT51YTaLeOPw6lhNIIZagz8
+Bx6cUI3Ga45MvZtTCSbpoXAaQL/gi7zQp/4vyTtToFk
+-> ssh-ed25519 xR+E/Q 7/gSLPTDl4F3LINdadlCa5b8MQC4y+p3ZYNlflxrdDw
+VK3WOVkKjola4munAfp0JMKYmnoLLIv9OHfZh9ysbkE
+-> ssh-ed25519 dcsaLw Ln1sLkvM+qcEkEhO7u+lYahwmNA31wb8/uxJJ9AVWDc
+aYTOrKKROC3giyyK+3oB2weL1OU0fognHy3KEMKv1Q0
+-> ssh-ed25519 zcCuhA c8s6YX+iduL0LROMQzOrIlyyMVB0glpO9fadGtnBtRM
+xKS+rami2JqtA3358i9ZmUald/l6RfZO3oYCXMGsaQs
+-> ssh-ed25519 1SxhRA QQhuhBCDNNRDjMwLXmdENnyQ8FLMGPPslz/n8HJskwg
+UFYbOrYp4Iv5bFGva60DoDnili4pu3ddQwkc6D7McWI
+-> ssh-ed25519 ch/9tw qbpidc793ukjbneLp9APflMGwUv1uz396OQHWDo7Ezs
+vqWqCraCcf7JfVUHXipXF4MIsWZJ8ctdIqlMQWTFVbw
+-> ssh-ed25519 CpJBgQ KUTLbnm2fGlMTBReyTkZ4vH+17rBbJEvNKMXEeKGcy4
+LyAz0fKXJwBleg078S4SX445hG9s/Wpowecm/dMVG24
+-> ssh-ed25519 aXKGcg /e2fcowJ2RNt70e2RuwSe0aTCTR7zX2m6EGWyizdvEk
+JWkvonXii+mquOF88RLyYTf/E/UDfvHrc8B6gptWkzo
+--- VJw7GLwGofsvJj+nlHgWDOnCud/Qjmjy9oeN15npnpw
+w{Lx-]d
X@,.1Ν%IEp2:RXNU<>nl?@*Cߩh4U@InāJ%-IH뇊.^I]=Pg:xSсKņI(5<%HbhE{86N</%#g`	[Y
\ No newline at end of file
diff --git a/ops/secrets/restic-bugry.age b/ops/secrets/restic-bugry.age
new file mode 100644
index 000000000000..2932033115f7
--- /dev/null
+++ b/ops/secrets/restic-bugry.age
@@ -0,0 +1,17 @@
+age-encryption.org/v1
+-> ssh-ed25519 wI5oAA TDjaldqySaCEFAPuoUBVMR342403nhkawwtXbsJJenQ
+eoeL2v5mCLksay/24miqYkWLJLLhrUIny4p1/e3/iTY
+-> ssh-ed25519 dcsaLw /KSRH3XUGU7P+Ckpk86PFl8oRfPP/dlLb6zLUW04iH8
+e2nXDvjkd5lzmXflhd820XmGvo/agSxDtfejxM45nhY
+-> ssh-ed25519 zcCuhA pIxJxTWsOyH6Zqunv427jdy1G7BV7Dpjpp2l+HEe/3s
+rxyoDZTQmsGwNB0nCTXNHhc7VCsb11/ynManfsbf5Ss
+-> ssh-ed25519 1SxhRA K8DkqAk5gPfsjTQiTjLGRNR+63uG9ogacsrH69/afGs
+LAt97AuWaPEYG7IlFiIOll9s02cQ+qhrpr0GVXX+e/o
+-> ssh-ed25519 ch/9tw 6eG9psphjjfW6TRTYxqozX9WLhQgC9u2ngR35rpXiH4
+9dFgdqSDKRXAotKKR19l9gqWlTNxuv9r/IcaMZeO9Oc
+-> ssh-ed25519 CpJBgQ /t2M57kxjKDq/UMoh9UnmQvlETqiwqClt0Lg6quqKRk
+oDblqLXxyJ7gTtZzhbStHep62oZK0iXikJ6fi6EW0gM
+-> ssh-ed25519 aXKGcg DVn6XZGaBHAeL4pGMaolO8cSOIKRIhmuDycV65pfxhs
+M6XVDk1Z9BdCoCvK30NDJsKKnURk/XUcRP4t5pZ7JFk
+--- H3D9jfLkrsDOgWfNhUJHZcVGa9dPqr4EuuBU40iJbJs
+{:jІpVFx'`5Lz#
y|"/>"QXJe
W*?
\ No newline at end of file
diff --git a/ops/secrets/restic-nevsky.age b/ops/secrets/restic-nevsky.age
new file mode 100644
index 000000000000..f06347b3871f
--- /dev/null
+++ b/ops/secrets/restic-nevsky.age
@@ -0,0 +1,17 @@
+age-encryption.org/v1
+-> ssh-ed25519 xR+E/Q iVPpAC04Up8hrFvnh2RsAXgfrFv2QNk0kwydlGrVslg
+2McWSNxxnPypGs9HKMNCjpHe+g2kxA86G6Drt2HWOeU
+-> ssh-ed25519 dcsaLw Xuw5V21UrJcIwWEoRyI+h60RaoJUdBAJJPqN12TY93U
+X4Wxo2qdBgtzQ8ct2UySnvXr9x0EzqBzSoHTBq9jQ9A
+-> ssh-ed25519 zcCuhA GPMgbaoLctcsQxVtoIPvXUvpfTZEUA2QnvgTXDUiJRI
+wnzHlJC8F45s/VzBjy9xfvDujtH+9uBmoX5OrzXapBA
+-> ssh-ed25519 1SxhRA 3GuXyDOYy6tur+nThpBLKMCvk/2c44XeR+NrLKj3G1Q
+LoVYepF0BiZ4E29ZMzXgOAyloK+UhX+FqiM9pPgngZ4
+-> ssh-ed25519 ch/9tw ihNjsBfasDmfW3Kcg8vQ1tpym9HKIL/qEzwpO7ye0Cg
+brnJzK7V4OV5jLfCFYqNue1oLSpJ88rRNN19KDcMdeM
+-> ssh-ed25519 CpJBgQ SvLMx+bG59LPZNI4EctDnFutMXoh4Otk2yFd17dXVQ4
++LO4a5ARK1mpYaenS1P13ajhpNtxndFvin2Po1h0cwM
+-> ssh-ed25519 aXKGcg VdaJIfDpeet7fzesJ3FGwZhQiAKNzEJMVUXNtbwm8UU
+rMqLrCdx55rzkuqJ3/9SrY6BKdSgHCLgAx8E0rrYVfY
+--- jNvJTcOvsKU6YkgEDBiOI27GBEzNlEg4JymqeKYa/fA
+ؽV(idTL\'HGgD^vܽ11c`}V=zK&
\ No newline at end of file
diff --git a/ops/secrets/restic-sanduny.age b/ops/secrets/restic-sanduny.age
new file mode 100644
index 000000000000..578871ff117f
--- /dev/null
+++ b/ops/secrets/restic-sanduny.age
Binary files differdiff --git a/ops/secrets/secrets.nix b/ops/secrets/secrets.nix
index bbebb17d3ba4..273f00d626f9 100644
--- a/ops/secrets/secrets.nix
+++ b/ops/secrets/secrets.nix
@@ -1,8 +1,4 @@
 let
-  flokli = [
-    "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPTVTXOutUZZjXLB0lUSgeKcSY/8mxKkC0ingGK1whD2 flokli"
-  ];
-
   tazjin = [
     # tverskoy
     "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIM1fGWz/gsq+ZeZXjvUrV+pBlanw1c3zJ9kLTax9FWQy"
@@ -25,45 +21,47 @@ let
     "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJk+KvgvI2oJTppMASNUfMcMkA2G5ZNt+HnWDzaXKLlo"
   ];
 
+  flokli = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPTVTXOutUZZjXLB0lUSgeKcSY/8mxKkC0ingGK1whD2 flokli";
+
   sanduny = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOag0XhylaTVhmT6HB8EN2Fv5Ymrc4ZfypOXONUkykTX";
-  whitby = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILNh/w4BSKov0jdz3gKBc98tpoLta5bb87fQXWBhAl2I";
   nevsky = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHQe7M+G8Id3ZD7j+I07TCUV1o12q1vpsOXHRlcPSEfa";
   bugry = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGqG6sITyJ/UsQ/RtYqmmMvTT4r4sppadoQIz5SvA+5J";
 
   admins = tazjin ++ aspen ++ sterni;
-  terraform.publicKeys = tazjin ++ aspen ++ sterni ++ flokli;
-  whitbyDefault.publicKeys = admins ++ [ whitby ];
-  allDefault.publicKeys = admins ++ [ sanduny whitby ];
-  sandunyDefault.publicKeys = admins ++ [ sanduny ];
-  bugryDefault.publicKeys = admins ++ [ bugry ];
-  nevskyDefault.publicKeys = admins ++ [ nevsky ];
-  cacheDefault.publicKeys = whitbyDefault.publicKeys ++ [ nevsky ];
+  allHosts = [ sanduny nevsky bugry ];
+  for = hosts: {
+    publicKeys = hosts ++ admins;
+  };
 in
 {
-  "besadii.age" = cacheDefault;
-  "buildkite-agent-token.age" = cacheDefault;
-  "buildkite-graphql-token.age" = cacheDefault;
-  "buildkite-ssh-private-key.age" = cacheDefault;
-  "clbot-ssh.age" = whitbyDefault;
-  "clbot.age" = whitbyDefault;
-  "depot-inbox-imap.age" = sandunyDefault;
-  "depot-replica-key.age" = whitbyDefault;
-  "gerrit-autosubmit.age" = whitbyDefault;
-  "gerrit-secrets.age" = whitbyDefault;
-  "grafana.age" = whitbyDefault;
-  "irccat.age" = whitbyDefault;
-  "journaldriver.age" = allDefault;
-  "keycloak-db.age" = whitbyDefault;
-  "nix-cache-priv.age" = cacheDefault;
-  "nix-cache-pub.age" = cacheDefault;
-  "owothia.age" = whitbyDefault;
-  "panettone.age" = whitbyDefault;
-  "smtprelay.age" = whitbyDefault;
-  "teleirc.age" = whitbyDefault;
-  "tf-buildkite.age" = terraform;
-  "tf-glesys.age" = terraform;
-  "tf-keycloak.age" = terraform;
-  "tvl-alerts-bot-telegram-token.age" = whitbyDefault;
-  "wg-bugry.age" = bugryDefault;
-  "wg-nevsky.age" = nevskyDefault;
+  "besadii.age" = for [ nevsky ];
+  "buildkite-agent-token.age" = for [ nevsky ];
+  "buildkite-graphql-token.age" = for [ nevsky ];
+  "buildkite-ssh-private-key.age" = for [ nevsky ];
+  "clbot-ssh.age" = for [ nevsky ];
+  "clbot.age" = for [ nevsky ];
+  "depot-inbox-imap.age" = for [ sanduny ];
+  "depot-replica-key.age" = for [ nevsky ];
+  "gerrit-autosubmit.age" = for [ nevsky ];
+  "gerrit-secrets.age" = for [ nevsky ];
+  "grafana.age" = for [ nevsky ];
+  "irccat.age" = for [ nevsky ];
+  "journaldriver.age" = for allHosts;
+  "keycloak-db.age" = for [ nevsky ];
+  "nix-cache-priv.age" = for [ nevsky ];
+  "nix-cache-pub.age" = for [ nevsky ];
+  "owothia.age" = for [ nevsky ];
+  "panettone.age" = for [ nevsky ];
+  "restic-bugry.age" = for [ bugry ];
+  "restic-nevsky.age" = for [ nevsky ];
+  "restic-sanduny.age" = for [ sanduny ];
+  "smtprelay.age" = for [ nevsky ];
+  "teleirc.age" = for [ nevsky ];
+  "tf-buildkite.age" = for [ /* humans only */ ];
+  "tf-glesys.age" = for [ /* humans only */ ];
+  "tf-keycloak.age" = for [ flokli ];
+  "tvl-alerts-bot-telegram-token.age" = for [ nevsky ];
+  "wg-bugry.age" = for [ bugry ];
+  "wg-nevsky.age" = for [ nevsky ];
+  "yc-restic.age" = for [ nevsky sanduny bugry ];
 }
diff --git a/ops/secrets/smtprelay.age b/ops/secrets/smtprelay.age
index 62fbaffadf6c..d183b76336bb 100644
--- a/ops/secrets/smtprelay.age
+++ b/ops/secrets/smtprelay.age
@@ -1,16 +1,20 @@
 age-encryption.org/v1
--> ssh-ed25519 dcsaLw CW2Lgm0tSWUDwKSNSX/aLkVzQ/QeEeQgU3NITpz2D0M
-F7dA+zWdCz21s443bj9zCz6lBsRlFIxiG+l8CdbuPFk
--> ssh-ed25519 zcCuhA l8rsBoYDwhUB5stbeGXYTQ4Fz745ywXFCOQZn2cMBW0
-TycVcUZjR2TDv5DPC54+RwoU6Fj4QpRUJj1j0HM/JCE
--> ssh-ed25519 CpJBgQ CbwZO5LmSxd0HRYkf+lV+ymFcXSn/49GAPHG4l1I7gw
-xSmab5+BnAZF/B0n32xX1qZPdHgfoEMGIuZqlpnISjc
--> ssh-ed25519 aXKGcg Tr+odf9p1RBrQK1guR6ToeN4wG1KLA3jwiPIkgyEjws
-TaeCnjiRp8VZoMS5qs+OfVbBc6zudayD693h/eGvVOo
--> ssh-ed25519 OkGqLg Dmnsqz6PKzMd6w4t+l6+EWuia+stPwSEtu00KVuAojo
-rZ/i1WJhrCM/ZQTAroRRSjzUVJw2UJlPUe1uHYqSscw
--> w!^Z-grease i86O2 i0.Rch
-/zsRadAGYzAY6F/J5m6lMjmojkN7NbY3TbfQbA
---- /rQgwuY9SVGLKeUzY5P6c+sGQ1I1aw5cQxmO46QKDSQ
-(`U ,c|ґP畠9@&	gMߒ
-CH3ik3#|gMAgAnZYt2K2ޘY
\ No newline at end of file
+-> ssh-ed25519 OkGqLg 7zaZRWxX/e7RaqYsQkiG8tm2V8rIZi1bpuYj+ZF+ix8
+H3etDuPK8PPghves5bnasQ01WTqvBnqnvVDGAd2SpO0
+-> ssh-ed25519 xR+E/Q MGbPr/UpqvzxoCsfyXrWhpiB+IGk2qaprlDnvQAdHiE
+n9ikSISxTS3etvJxudA2sNgGkm0ZH8SuyuDxjc0ts2Q
+-> ssh-ed25519 dcsaLw bHbnaG2LHkdARhDRUqCZD0FCoB6TakuSFDrXskAz0wg
+hav1GWBSzhXPvOQN7Ta3nJhPe4LU1arrZmhFGnDhQek
+-> ssh-ed25519 zcCuhA wV0ejBHKzTn1kQTm6apJy9GmiycPxiW+OO7VM5zjnGY
+lBpcnbmSeqgAolJ8LWlr+ZuUEM7Pn8yLbptahmuSWRg
+-> ssh-ed25519 1SxhRA Yz9ewxHm0cAc7t5Htm5eoYjXaGeYE35PPIWL5d1awgA
+5jbHeDlD1ttxzts1+7ZFczHo/Jc1gxZ6/j2IauPFV0g
+-> ssh-ed25519 ch/9tw tE5DuYHdqoiHrQlEfMcql1EXa6IWS9OSb3YE/hJaYCo
+ovcxm/RHfY5JMQ4Gy7sjLWw3kPNo9roLeaZKGe7GYLQ
+-> ssh-ed25519 CpJBgQ 6YQWpxreZnaZQzB5nnE6BIY3mzKh/jyGfo4d1DIZMW4
+ZAkw1azFo06HCc4kr6tETekIYde8fZmqTB50EpxYqFY
+-> ssh-ed25519 aXKGcg uPId6FHvRb0G//LQsZydlL8V5qaVVyR3uMa4NtUtqwI
+165tSBFCGp6kQSXtmtT61r5v6v4zDzNGEh8hXNPu250
+--- A5ibslMc4EiRcYPX2he5YSB/u6BrHF7+2Eh+yQzv5BU
+#˄֨
+Pf|H+ 
VkAe$FbY?A(~n*N?I#\.P"½b)I%e6>te
g 
\ No newline at end of file
diff --git a/ops/secrets/teleirc.age b/ops/secrets/teleirc.age
index ebc88fc9ef1d..1bcf3b94b87c 100644
--- a/ops/secrets/teleirc.age
+++ b/ops/secrets/teleirc.age
Binary files differdiff --git a/ops/secrets/tf-buildkite.age b/ops/secrets/tf-buildkite.age
index 0cf6066fa604..6f7ed8c90c51 100644
--- a/ops/secrets/tf-buildkite.age
+++ b/ops/secrets/tf-buildkite.age
Binary files differdiff --git a/ops/secrets/tf-glesys.age b/ops/secrets/tf-glesys.age
index 4e50454b6214..82895a62b289 100644
--- a/ops/secrets/tf-glesys.age
+++ b/ops/secrets/tf-glesys.age
Binary files differdiff --git a/ops/secrets/tf-keycloak.age b/ops/secrets/tf-keycloak.age
index 7d470a6a304e..87a1d14f5dd3 100644
--- a/ops/secrets/tf-keycloak.age
+++ b/ops/secrets/tf-keycloak.age
Binary files differdiff --git a/ops/secrets/tf-yandex.age b/ops/secrets/tf-yandex.age
new file mode 100644
index 000000000000..465297c0daa3
--- /dev/null
+++ b/ops/secrets/tf-yandex.age
@@ -0,0 +1,17 @@
+age-encryption.org/v1
+-> ssh-ed25519 dcsaLw M/Q/SPfYHbP1Fu58r9+YzPemEVwycadHiwpsT0EgG0A
+YRwnS7LID5jRppBKONHTnYAG9yL7iGzqE5Kb5We/YVA
+-> ssh-ed25519 zcCuhA 2E4mTf1KRjknhvfNQsvJ3n2PxI0H8PwJ42yAJd15BCw
+sunGwSgkNJUBjqgouuCfbC2jVgRLCxah1pyJBsnxs20
+-> ssh-ed25519 CpJBgQ hxMK7R7fcZhy2JAKjIgVVoCDFOyJcRT9EVPD5HQ7/W8
+dS3dwz9nyfGKbmG/MxKN5yhtsoFjhxu4ODUQBd2SnXE
+-> ssh-ed25519 aXKGcg XX5nMPWQvaazgGpuRyCpdnUit0EwYUc5ZfU/Y4PfzDA
+Avqf9E83/z5RTJy85IP5gFuw+HYdNCzGlvfUaQyU4c0
+-> ssh-ed25519 C2zWnA JwQkckkpIBznH8d+xqbH/BQ542lJfhOEeC2Zy35lmlU
+unCT8sZn9es9lZb9NzXZvk4gu/kM2dlmeGzYfvA6Plo
+-> Jg6zP>5r-grease xyn
+HbAOtgdTIPa25802PNNPfTvtpiZSTzonaFO87U/KV+1LTRhI560rGjckMLaf2MzC
+xWW7qwSg0gA8uVec99KugA596W8x
+--- W60cYV6jeVgGngYnbG8jLUUQ5O/UTgjdpqYFGZxxDyY
+=^4+nLo=Me2W/}i$+[eoAMNy5!t)w 4UM'@Fm A\
+w)iazzb;ᶷ^s^,nQ4
{V@lӣRiJPV
/k|w
\ No newline at end of file
diff --git a/ops/secrets/tvl-alerts-bot-telegram-token.age b/ops/secrets/tvl-alerts-bot-telegram-token.age
index e897fedc03f5..c3c29bea3baf 100644
--- a/ops/secrets/tvl-alerts-bot-telegram-token.age
+++ b/ops/secrets/tvl-alerts-bot-telegram-token.age
@@ -1,15 +1,19 @@
 age-encryption.org/v1
--> ssh-ed25519 dcsaLw JGXCnhez0LnlUV8eOitxizmxw/gV+1taBRhNvwvVcms
-qsRTOpifnoc0eorFjd4UlP7O3hkRR3KjDUcImASK0jY
--> ssh-ed25519 zcCuhA KUcyaHcmuqCGtJBzvc2UK17gRrjzuzIxll+TS9Q4nWs
-CAJ19ClA9Tqj1fcYySq+K9gdZe6Uv0toZLnhlovr3tM
--> ssh-ed25519 CpJBgQ OAE+u9JuC6KoefjCOTj4NkQElZRe6/EEIAGBN/XelnU
-M9MHlKxbEBJ+gACo2FiYqmm1cAoYW31+nP16qnVZ7Zw
--> ssh-ed25519 aXKGcg Ll6v6v5HpUIEuOzjpVsPMmPQMnNkmyB4fz/YwNXfCHU
-MmFQy2WkKn5SM0bhe4NNe/lMnneKoOF+Ufq0t0QjNbw
--> ssh-ed25519 OkGqLg PS6KLwat1z2BSQ9sIKDaryVU39EJR+iiAaKSP/KSPk0
-qUQP2f4MFk83zQ9edlSNC8jwpJvmp2xhOysd8rnYzW4
--> >NI-grease @mOcHT z|%,s- mw^c *
-zu0M2pS6v3zehnLg
---- jltBYy9brAtpkEIqPoGmIVe3s5XnWtpa9EmuXlAf91c
-tdX2-"#1n'\'{Dlw;Pִ@{B	!y+xWB:wtqph
\ No newline at end of file
+-> ssh-ed25519 OkGqLg FOAaUDj6nO1t5hnf0aGzWpmQkhqU9VP+SRUompxV9GE
+JK4da9hBvI7NN3gnCUI/tmhUFEtt5KUuBoLfRCoFhqw
+-> ssh-ed25519 xR+E/Q wJGkb4gj0iz3E+W5mIbTAeGFVdlznevKH4EEibecDF8
+WUAFLhSrjQgUTkZ3xzVuT7HHwAc2N1HKrIdGRIEutD8
+-> ssh-ed25519 dcsaLw QkXSrs57caaESWsgGx2oIpbZd7eNL5UH6bU0g+hFxEI
+zbNePgbWmX+87aIqGvY0HEpvxxUQB3b4qoGImH28m38
+-> ssh-ed25519 zcCuhA FNZlnMpL4AhOu9PWTDNHbWhOGcJYPAdcZA8YNmgGTR4
+rbE9zXLbKEANF1jc455/2G9wXbvaeRwbw1JdfceQo8Q
+-> ssh-ed25519 1SxhRA rii+s4GOfeBz7n7aRVTkT97vORRvdsR1mX0Bbgri434
+dmMbDxVKk6zBro9hZ53JYZNlUa1et0ZYvvf3ko+QbAQ
+-> ssh-ed25519 ch/9tw ACKJ0RJknUewijCbuOaBv4qNleB3gXYnPo/cnjnoWkk
+GKEZVXPUZkwQ++quIUWxJS1MCo1Bg+naHiEhzMiB3kc
+-> ssh-ed25519 CpJBgQ d8Dewm0HC+bMan6QB8EPL+tQGoem0Vx5af9UehAq7UA
+Dcf4qudBi1z5PAxxhm82nBQFQx9TFeHLfcsV+XcdwQY
+-> ssh-ed25519 aXKGcg Icrf3Vs4SyRWqbnvfAJURuaWEORyGqOxONcdCakWfwg
+wVdLjQuvuTc/f/wDZIv32udqpVNdlLWZ4mpzT6Pur8A
+--- mk6kDLN1EEhHZgUbS/RRqardbjWFBXvQZJV5ikc7vu0
+''c3Qt/䰺-_[pڅt,%Ѩ{OaYص"WʥO(0
\ No newline at end of file
diff --git a/ops/secrets/wg-bugry.age b/ops/secrets/wg-bugry.age
index c2b0a68e6f9d..2ce0de6a9d71 100644
--- a/ops/secrets/wg-bugry.age
+++ b/ops/secrets/wg-bugry.age
Binary files differdiff --git a/ops/secrets/wg-nevsky.age b/ops/secrets/wg-nevsky.age
index a5011004ee53..93b133ce361a 100644
--- a/ops/secrets/wg-nevsky.age
+++ b/ops/secrets/wg-nevsky.age
@@ -1,17 +1,17 @@
 age-encryption.org/v1
--> ssh-ed25519 dcsaLw fAd2MnJBU3OG7KpHvd6rhRVQuMl5pGUOlx6zQ1HVpTU
-hwoKpHUvpHp/gLFhtwTOyJLBeUyryrZAf8TzDsaoMUg
--> ssh-ed25519 zcCuhA B2ZIcHgTjg69iprbGkKPyGGExK+kP1l6MMYX4czpOVM
-xomAnf6WhEM78GWvtAtCS/yw4UfeCT3Ph3evbLp0yQk
--> ssh-ed25519 1SxhRA uJNHTJFigivTGSKNzd4oqEhEIFF/aWwWQzovxwiVSHo
-VAzriez/W6hZKicze7rOYs7YL8vxPxVoWzMe9yawyqA
--> ssh-ed25519 ch/9tw nBm9P9qvUkZSYI+CKN0kjXzSuD6sg+uMvTux9yTD7V0
-Kt+R1s9tEPk+e5ZeskmZtBzEvm25B33KCQwmjnfuVNM
--> ssh-ed25519 CpJBgQ 6g8GbJ/zZkAb1pBpqA5Jm929aIAJlepe1sPNqhAuAWM
-gYCkgAQw2nF0wcPMZruvhBqkC4a2BxYK8kWo+R9ll44
--> ssh-ed25519 aXKGcg rfGH2EO9/soo/duaZlt4hBic4KxMDR+tw8JJ1Un+u1U
-FzyiK9NT7NUM+oQph/EB26PfuLsLQVYsKwqeBHGaRI8
--> ssh-ed25519 xR+E/Q 3w7vMdS+Iragj8garW5/F0ZL28orsyewbvp4i8szNl4
-zuEEaHd2rTfMYuLvQ19TuHOX5UMmSZABD3grJjEnsG8
---- +e2kcaRvPwsUH/XG+ChROPjyZHLv4mfpSBmmJCr/4UM
->S1	:Ԍu5ܘNj@t)OQ7n^Y,FMͤ6^>eǔ+~]9.Z
\ No newline at end of file
+-> ssh-ed25519 xR+E/Q pAv2Rm0oj9HJu8LAIRbT+bvNOufRcDTLlLfanvM84y0
+eTOICFyxEt3b6Kh9NbKMmt9i3+GFsgk4K+jBuR8LjUs
+-> ssh-ed25519 dcsaLw cYYa3+xqONMvU4y4LsWZ5VZBrQoMdoRYbII70H0x7hw
+w7XolSOTiX5WdrnURn/PtAGriMz4n0rBUAulOU4pP3E
+-> ssh-ed25519 zcCuhA xwUsUilN81ZHuqE6gCzmUddjD+gLd6bkDclSb73K+08
+H2uNajL/IDn+hXJyehDG22Zu5k7RZmjWyWtJnzCxAEw
+-> ssh-ed25519 1SxhRA rkPyrom+2W0BWU6S9Vy+h5ggrdjEQdVcFd6onYENNmE
+AuonnG8d2RwpLUR+FAgf4TrWCmB3dxnO3OFLM4+EVH8
+-> ssh-ed25519 ch/9tw DJs3TcbTmAx0HqTWoyvugqfqxdZ13kqerOlaJKADljA
+bxyxi0/J7MBm+Hlq6CUM4s9+j4M3E9f55lUgMKx+ABc
+-> ssh-ed25519 CpJBgQ ralv1E55uSriSrM8X+rOr/h70dbEOVOfux7U20cky0k
+lflA+jocbQn7dricKpH6iBQ3P2K+g8ZDvyuRkyCUL7c
+-> ssh-ed25519 aXKGcg Fb5vBSvT0RaO5yXhd/b/75QdC6IPSDpntUHhtdhhFGw
+UASa/ristknh342EyYO24qAT+rAaWI5ks00mSTjPOQY
+--- e8mOir6/NeozcVmD17lJkrFVIffhOAXR3kKq5OgqbRw
+%ȇlAظ>5.48}@D*uGרy|S-F*&La
,XY='H
\ No newline at end of file
diff --git a/ops/secrets/yc-restic.age b/ops/secrets/yc-restic.age
new file mode 100644
index 000000000000..7ba554f3a269
--- /dev/null
+++ b/ops/secrets/yc-restic.age
Binary files differdiff --git a/ops/yandex-cloud-rs/Cargo.toml b/ops/yandex-cloud-rs/Cargo.toml
index a72d11d59ac4..896c6e034fc0 100644
--- a/ops/yandex-cloud-rs/Cargo.toml
+++ b/ops/yandex-cloud-rs/Cargo.toml
@@ -4,7 +4,7 @@ description = "Generated gRPC clients for the Yandex Cloud API"
 license = "MIT"
 version = "2023.9.4"
 edition = "2021"
-homepage = "https://cs.tvl.fyi/depot/-/tree/ops/yandex-cloud-rs"
+homepage = "https://code.tvl.fyi/tree/ops/yandex-cloud-rs"
 repository = "https://code.tvl.fyi/depot.git:/ops/yandex-cloud-rs.git"
 include = [ "/src", "README.md" ]
 
diff --git a/ops/yandex-cloud-rs/README.md b/ops/yandex-cloud-rs/README.md
index a80fa831637b..463bde5c292e 100644
--- a/ops/yandex-cloud-rs/README.md
+++ b/ops/yandex-cloud-rs/README.md
@@ -46,4 +46,4 @@ cargo publish --allow-dirty
 
 [repo]: https://github.com/yandex-cloud/cloudapi
 [docs]: https://docs.rs/yandex-cloud/latest/yandex_cloud/
-[code]: https://cs.tvl.fyi/depot/-/tree/ops/yandex-cloud-rs
+[code]: https://code.tvl.fyi/tree/ops/yandex-cloud-rs
diff --git a/third_party/bqn-libs/default.nix b/third_party/bqn-libs/default.nix
new file mode 100644
index 000000000000..d76826d389b8
--- /dev/null
+++ b/third_party/bqn-libs/default.nix
@@ -0,0 +1,39 @@
+# - Standalone, importable files are installed to $out/lib/*.bqn.
+#   They have no external dependencies, but do import each other (via relative paths).
+# - Documentation to $out/share/doc/bqn-libs.
+#
+# Note: This packaging is ad hoc and tentative. No way to handle BQN dependencies
+# for depot (or Nix, for that matter) has been proposed yet. If you have ideas /
+# want to work on this, talk to sterni.
+# TODO(sterni): Find out whether any work towards a BQN package manager exists
+#
+# The problem is that BQN is sort of like Nix: It only has the notion of direct
+# file imports. Unlike Nix, however, it doesn't even have a builtin notion of a
+# search path, so the design space is unconstrained. The most obvious solution
+# would be to implement some kind of search part ourselves. Unfortunately, there
+# is no portable way to access environment variables in BQN at the moment.
+{ depot, pkgs, lib, ... }:
+
+let
+  src = pkgs.fetchFromGitHub {
+    inherit (depot.third_party.sources.bqn-libs)
+      repo
+      owner
+      sha256
+      rev
+      ;
+  };
+in
+
+pkgs.runCommandNoCC "bqn-libs-${builtins.substring 0 7 src.rev}"
+{
+  nativeBuildInputs = [
+    pkgs.cbqn
+  ];
+  meta.license = lib.licenses.bsd0;
+} ''
+  BQN "${src}/test/main.bqn"
+
+  install -Dm644 "${src}/"*.bqn -t "$out/lib"
+  install -Dm644 "${src}/LICENSE" -t "$out/share/doc/bqn-libs"
+''
diff --git a/third_party/smtprelay/default.nix b/third_party/smtprelay/default.nix
index 1a68245e9243..b46e02076e62 100644
--- a/third_party/smtprelay/default.nix
+++ b/third_party/smtprelay/default.nix
@@ -15,7 +15,7 @@ pkgs.buildGoModule rec {
 
   meta = with lib; {
     description = "Simple Golang SMTP relay/proxy server";
-    homepage = https://github.com/decke/smtprelay;
+    homepage = "https://github.com/decke/smtprelay";
     license = licenses.mit;
   };
 }
diff --git a/third_party/sources/sources.json b/third_party/sources/sources.json
index 3c6d6d12944d..887617da407c 100644
--- a/third_party/sources/sources.json
+++ b/third_party/sources/sources.json
@@ -5,10 +5,22 @@
         "homepage": "https://matrix.to/#/#agenix:nixos.org",
         "owner": "ryantm",
         "repo": "agenix",
-        "rev": "f6291c5935fdc4e0bef208cfc0dcab7e3f7a1c41",
-        "sha256": "1x8nd8hvsq6mvzig122vprwigsr3z2skanig65haqswn7z7amsvg",
+        "rev": "e600439ec4c273cf11e06fe4d9d906fb98fa097c",
+        "sha256": "006ngydiykjgqs85cl19h9klq8kaqm5zs0ng51dnwy7nzgqxzsdr",
         "type": "tarball",
-        "url": "https://github.com/ryantm/agenix/archive/f6291c5935fdc4e0bef208cfc0dcab7e3f7a1c41.tar.gz",
+        "url": "https://github.com/ryantm/agenix/archive/e600439ec4c273cf11e06fe4d9d906fb98fa097c.tar.gz",
+        "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
+    },
+    "bqn-libs": {
+        "branch": "master",
+        "description": "Informal collection of BQN utilities",
+        "homepage": "",
+        "owner": "mlochbaum",
+        "repo": "bqn-libs",
+        "rev": "405644fe7aeca7cd31304c05b95de1a6c197fff6",
+        "sha256": "0wxa3k9kyqr4xlvjdrhza00gk3al9f3gjbfqws1vppx5m7cq97xq",
+        "type": "tarball",
+        "url": "https://github.com/mlochbaum/bqn-libs/archive/405644fe7aeca7cd31304c05b95de1a6c197fff6.tar.gz",
         "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
     },
     "gitignore.nix": {
@@ -31,10 +43,10 @@
         "homepage": "https://nix-community.github.io/home-manager/",
         "owner": "nix-community",
         "repo": "home-manager",
-        "rev": "2532b500c3ed2b8940e831039dcec5a5ea093afc",
-        "sha256": "0kzk59wh1gnvk31dagfyf41a12wqldm8l5vnkzcix74nmz0qdrk4",
+        "rev": "18fa9f323d8adbb0b7b8b98a8488db308210ed93",
+        "sha256": "0j56s38y0yzy3pw7qia1n9zkmmn9nkb9mpklj2mc30k5l11fs170",
         "type": "tarball",
-        "url": "https://github.com/nix-community/home-manager/archive/2532b500c3ed2b8940e831039dcec5a5ea093afc.tar.gz",
+        "url": "https://github.com/nix-community/home-manager/archive/18fa9f323d8adbb0b7b8b98a8488db308210ed93.tar.gz",
         "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
     },
     "impermanence": {
@@ -43,10 +55,10 @@
         "homepage": "",
         "owner": "nix-community",
         "repo": "impermanence",
-        "rev": "c64bed13b562fc3bb454b48773d4155023ac31b7",
-        "sha256": "0gc7w24hyl2nfl6jpmffb121cvnmdifgb2cli5adzpvhm32pv6fm",
+        "rev": "4b3e914cdf97a5b536a889e939fb2fd2b043a170",
+        "sha256": "04l16szln2x0ajq2x799krb53ykvc6vm44x86ppy1jg9fr82161c",
         "type": "tarball",
-        "url": "https://github.com/nix-community/impermanence/archive/c64bed13b562fc3bb454b48773d4155023ac31b7.tar.gz",
+        "url": "https://github.com/nix-community/impermanence/archive/4b3e914cdf97a5b536a889e939fb2fd2b043a170.tar.gz",
         "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
     },
     "naersk": {
@@ -80,10 +92,10 @@
         "homepage": "",
         "owner": "NixOS",
         "repo": "nixpkgs",
-        "rev": "2f9e2f85cb14a46410a1399aa9ea7ecf433e422e",
-        "sha256": "0dh9xf3nkbaci00m7yy2xyksdnj1mpx98jnq0l85klp99hqlys8m",
+        "rev": "6eec6bbb933a6dad6cf6afe3d51329f31d22e974",
+        "sha256": "0qmqw1ilzcjc3ivc7s05hf3iakn2b457d41v3fzdm28lqpf70skx",
         "type": "tarball",
-        "url": "https://github.com/NixOS/nixpkgs/archive/2f9e2f85cb14a46410a1399aa9ea7ecf433e422e.tar.gz",
+        "url": "https://github.com/NixOS/nixpkgs/archive/6eec6bbb933a6dad6cf6afe3d51329f31d22e974.tar.gz",
         "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
     },
     "nixpkgs-stable": {
@@ -106,10 +118,10 @@
         "homepage": "",
         "owner": "oxalica",
         "repo": "rust-overlay",
-        "rev": "5d1865c0da63b4c949f383d982b6b43519946e8f",
-        "sha256": "0189sk00a6f340zacpqb8nfik02ll9j7faa63hb2gcripwhrc2gn",
+        "rev": "e2bb8c205a069514535f083742c7da8dfb6e02b9",
+        "sha256": "1x2ip7ap91c42wc7pjnsjwyj8v689x53177j5r01v4k94jk0k57v",
         "type": "tarball",
-        "url": "https://github.com/oxalica/rust-overlay/archive/5d1865c0da63b4c949f383d982b6b43519946e8f.tar.gz",
+        "url": "https://github.com/oxalica/rust-overlay/archive/e2bb8c205a069514535f083742c7da8dfb6e02b9.tar.gz",
         "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
     },
     "rustsec-advisory-db": {
@@ -118,10 +130,10 @@
         "homepage": "https://rustsec.org",
         "owner": "RustSec",
         "repo": "advisory-db",
-        "rev": "63a2f39924f66ca89cf5761f299a8a244fe02543",
-        "sha256": "1lvjikihd6kzmxw1wi2amz4arcbdxgi4r4qrfldi18l4xcj6y3a2",
+        "rev": "5248f077160ebbedbc62f32356a7eb08823fc91b",
+        "sha256": "0caga1xxvbdh2gmn0gm3vggxwcv55bpvvrlxwbkzmhqhbmwdm0li",
         "type": "tarball",
-        "url": "https://github.com/RustSec/advisory-db/archive/63a2f39924f66ca89cf5761f299a8a244fe02543.tar.gz",
+        "url": "https://github.com/RustSec/advisory-db/archive/5248f077160ebbedbc62f32356a7eb08823fc91b.tar.gz",
         "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
     }
 }
diff --git a/tools/emacs-pkgs/tvl/tvl.el b/tools/emacs-pkgs/tvl/tvl.el
index 8db718a8359d..358a9770c582 100644
--- a/tools/emacs-pkgs/tvl/tvl.el
+++ b/tools/emacs-pkgs/tvl/tvl.el
@@ -1,11 +1,11 @@
 ;;; tvl.el --- description -*- lexical-binding: t; -*-
 ;;
 ;; Copyright (C) 2020 Griffin Smith
-;; Copyright (C) 2020 The TVL Contributors
+;; Copyright (C) 2020-2023, 2025 The TVL Contributors
 ;;
 ;; Author: Griffin Smith <grfn@gws.fyi>
 ;; Version: 0.0.1
-;; Package-Requires: (cl s magit)
+;; Package-Requires: (s magit)
 ;;
 ;; This file is not part of GNU Emacs.
 ;;
@@ -17,7 +17,6 @@
 
 (require 'magit)
 (require 's)
-(require 'cl) ; TODO(tazjin): replace lexical-let* with non-deprecated alternative
 
 (defgroup tvl nil
   "Customisation options for TVL functionality.")
@@ -213,14 +212,14 @@ passes. This is potentially dangerous, use with care."
 
      (interactive (list (read-string "Attribute: ")
                         (yes-or-no-p "Only include dependencies? ")))
-     (lexical-let* ((outbuf (get-buffer-create (format "*depot-out/%s*" attribute)))
-                    (errbuf (get-buffer-create (format "*depot-errors/%s*" attribute)))
-                    (attr-display (if only-deps attribute (format "dependencies of %s" attribute)))
-                    (expression (if only-deps
-                                    (format "let d = import <depot> {}; in d.nix.buildLisp.sbcl.lispWith d.%s.lispDeps"
-                                            attribute)
-                                    (format "(import <depot> {}).%s.repl" attribute)))
-                    (command (list "nix-build" "--no-out-link" "-I" (format "depot=%s" tvl-depot-path) "-E" expression)))
+     (let* ((outbuf (get-buffer-create (format "*depot-out/%s*" attribute)))
+            (errbuf (get-buffer-create (format "*depot-errors/%s*" attribute)))
+            (attr-display (if only-deps attribute (format "dependencies of %s" attribute)))
+            (expression (if only-deps
+                            (format "let d = import <depot> {}; in d.nix.buildLisp.sbcl.lispWith d.%s.lispDeps"
+                                    attribute)
+                          (format "(import <depot> {}).%s.repl" attribute)))
+            (command (list "nix-build" "--no-out-link" "-I" (format "depot=%s" tvl-depot-path) "-E" expression)))
        (message "Acquiring Lisp for <depot>.%s" attr-display)
        (make-process :name (format "depot-nix-build/%s" attribute)
                      :buffer outbuf
diff --git a/tools/nixery/README.md b/tools/nixery/README.md
index a879d030b868..40009b05e500 100644
--- a/tools/nixery/README.md
+++ b/tools/nixery/README.md
@@ -152,5 +152,5 @@ Nix builds.
 [gist]: https://gist.github.com/tazjin/08f3d37073b3590aacac424303e6f745
 [buildLayeredImage]: https://grahamc.com/blog/nix-and-layered-docker-images
 [public]: https://nixery.dev
-[depot-link]: https://cs.tvl.fyi/depot/-/tree/tools/nixery
+[depot-link]: https://code.tvl.fyi/tree/tools/nixery
 [gcs]: https://cloud.google.com/storage/
diff --git a/tools/nixery/web/index.html b/tools/nixery/web/index.html
index 354c4913b272..25136af153f5 100644
--- a/tools/nixery/web/index.html
+++ b/tools/nixery/web/index.html
@@ -131,9 +131,9 @@
   </h3>
 
   <p>
-    Nixery lives in the <a href="https://cs.tvl.fyi/depot/-/tree/tools/nixery">TVL
+    Nixery lives in the <a href="https://code.tvl.fyi/tree/tools/nixery">TVL
       monorepo</a>. All development happens there and follows
-      the <a href="https://cs.tvl.fyi/depot/-/blob/docs/CONTRIBUTING.md">TVL contribution
+      the <a href="https://code.tvl.fyi/about/docs/CONTRIBUTING.md">TVL contribution
       guidelines</a>.
   </p>
 
diff --git a/tvix/README.md b/tvix/README.md
index bb5fe7423517..b66adda2b4d9 100644
--- a/tvix/README.md
+++ b/tvix/README.md
@@ -34,7 +34,7 @@ Contributions to Tvix follow the TVL [review flow][review-docs] and
 
 [post-1]: https://tvl.fyi/blog/rewriting-nix
 [tvl]: https://tvl.fyi
-[tvix-src]: https://cs.tvl.fyi/depot/-/tree/tvix/
+[tvix-src]: https://code.tvl.fyi/tree/tvix/
 [tvix-gerrit]: https://cl.tvl.fyi/q/path:%255Etvix.*
 [b]: https://b.tvl.fyi
 [tvl-getting-in-touch]: https://tvl.fyi/#getting-in-touch
diff --git a/tvix/boot/tests/default.nix b/tvix/boot/tests/default.nix
index 3748f7620246..384144bc0a22 100644
--- a/tvix/boot/tests/default.nix
+++ b/tvix/boot/tests/default.nix
@@ -158,84 +158,90 @@ let
     documentation.enable = lib.mkForce false;
   }).config.system.build.toplevel;
 
+  allTests = depot.nix.readTree.drvTargets {
+    docs-memory = (mkBootTest {
+      path = ../../docs;
+      importPathName = "docs";
+    });
+    docs-persistent = (mkBootTest {
+      blobServiceAddr = "objectstore+file:///build/blobs";
+      directoryServiceAddr = "redb:///build/directories.redb";
+      pathInfoServiceAddr = "redb:///build/pathinfo.redb";
+      path = ../../docs;
+      importPathName = "docs";
+    });
+
+    closure-tvix = (mkBootTest {
+      blobServiceAddr = "objectstore+file:///build/blobs";
+      path = depot.tvix.store;
+      isClosure = true;
+    });
+
+    closure-nixos = (mkBootTest {
+      blobServiceAddr = "objectstore+file:///build/blobs";
+      pathInfoServiceAddr = "redb:///build/pathinfo.redb";
+      directoryServiceAddr = "redb:///build/directories.redb";
+      path = testSystem;
+      isClosure = true;
+      vmCmdline = "init=${testSystem}/init panic=-1"; # reboot immediately on panic
+      assertVMOutput = "Onwards and upwards.";
+    });
+
+    closure-nixos-bigtable = (mkBootTest {
+      blobServiceAddr = "objectstore+file:///build/blobs";
+      directoryServiceAddr = "bigtable://instance-1?project_id=project-1&table_name=directories&family_name=cf1";
+      pathInfoServiceAddr = "bigtable://instance-1?project_id=project-1&table_name=pathinfos&family_name=cf1";
+      path = testSystem;
+      useNarBridge = true;
+      preStart = ''
+        ${pkgs.cbtemulator}/bin/cbtemulator -address $PWD/cbtemulator.sock &
+        timeout 22 sh -c 'until [ -e $PWD/cbtemulator.sock ]; do sleep 1; done'
+
+        export BIGTABLE_EMULATOR_HOST=unix://$PWD/cbtemulator.sock
+        ${pkgs.google-cloud-bigtable-tool}/bin/cbt -instance instance-1 -project project-1 createtable directories
+        ${pkgs.google-cloud-bigtable-tool}/bin/cbt -instance instance-1 -project project-1 createfamily directories cf1
+        ${pkgs.google-cloud-bigtable-tool}/bin/cbt -instance instance-1 -project project-1 createtable pathinfos
+        ${pkgs.google-cloud-bigtable-tool}/bin/cbt -instance instance-1 -project project-1 createfamily pathinfos cf1
+      '';
+      isClosure = true;
+      vmCmdline = "init=${testSystem}/init panic=-1"; # reboot immediately on panic
+      assertVMOutput = "Onwards and upwards.";
+    });
+
+    closure-nixos-s3 = (mkBootTest {
+      blobServiceAddr = "objectstore+s3://mybucket/blobs?aws_access_key_id=myaccesskey&aws_secret_access_key=supersecret&aws_endpoint_url=http%3A%2F%2Flocalhost%3A9000&aws_allow_http=1";
+      # we cannot use s3 here yet without any caching layer, as we don't allow "deeper" access to directories (non-root nodes)
+      # directoryServiceAddr = "objectstore+s3://mybucket/directories?aws_access_key_id=myaccesskey&aws_secret_access_key=supersecret&endpoint=http%3A%2F%2Flocalhost%3A9000&aws_allow_http=1";
+      directoryServiceAddr = "memory://";
+      pathInfoServiceAddr = "memory://";
+      path = testSystem;
+      useNarBridge = true;
+      preStart = ''
+        MINIO_ACCESS_KEY=myaccesskey MINIO_SECRET_KEY=supersecret MINIO_ADDRESS=127.0.0.1:9000 ${pkgs.minio}/bin/minio server $(mktemp -d) &
+        timeout 22 sh -c 'until ${pkgs.netcat}/bin/nc -z $0 $1; do sleep 1; done' localhost 9000
+        mc_config_dir=$(mktemp -d)
+        ${pkgs.minio-client}/bin/mc --config-dir $mc_config_dir alias set 'myminio' 'http://127.0.0.1:9000' 'myaccesskey' 'supersecret'
+        ${pkgs.minio-client}/bin/mc --config-dir $mc_config_dir mb myminio/mybucket
+      '';
+      isClosure = true;
+      vmCmdline = "init=${testSystem}/init panic=-1"; # reboot immediately on panic
+      assertVMOutput = "Onwards and upwards.";
+    });
+
+    closure-nixos-nar-bridge = (mkBootTest {
+      blobServiceAddr = "objectstore+file:///build/blobs";
+      path = testSystem;
+      useNarBridge = true;
+      isClosure = true;
+      vmCmdline = "init=${testSystem}/init panic=-1"; # reboot immediately on panic
+      assertVMOutput = "Onwards and upwards.";
+    });
+  };
 in
-depot.nix.readTree.drvTargets
-{
-  docs-memory = (mkBootTest {
-    path = ../../docs;
-    importPathName = "docs";
-  });
-  docs-persistent = (mkBootTest {
-    blobServiceAddr = "objectstore+file:///build/blobs";
-    directoryServiceAddr = "redb:///build/directories.redb";
-    pathInfoServiceAddr = "redb:///build/pathinfo.redb";
-    path = ../../docs;
-    importPathName = "docs";
-  });
-
-  closure-tvix = (mkBootTest {
-    blobServiceAddr = "objectstore+file:///build/blobs";
-    path = depot.tvix.store;
-    isClosure = true;
-  });
-
-  closure-nixos = (mkBootTest {
-    blobServiceAddr = "objectstore+file:///build/blobs";
-    pathInfoServiceAddr = "redb:///build/pathinfo.redb";
-    directoryServiceAddr = "redb:///build/directories.redb";
-    path = testSystem;
-    isClosure = true;
-    vmCmdline = "init=${testSystem}/init panic=-1"; # reboot immediately on panic
-    assertVMOutput = "Onwards and upwards.";
-  });
-
-  closure-nixos-bigtable = (mkBootTest {
-    blobServiceAddr = "objectstore+file:///build/blobs";
-    directoryServiceAddr = "bigtable://instance-1?project_id=project-1&table_name=directories&family_name=cf1";
-    pathInfoServiceAddr = "bigtable://instance-1?project_id=project-1&table_name=pathinfos&family_name=cf1";
-    path = testSystem;
-    useNarBridge = true;
-    preStart = ''
-      ${pkgs.cbtemulator}/bin/cbtemulator -address $PWD/cbtemulator.sock &
-      timeout 22 sh -c 'until [ -e $PWD/cbtemulator.sock ]; do sleep 1; done'
-
-      export BIGTABLE_EMULATOR_HOST=unix://$PWD/cbtemulator.sock
-      ${pkgs.google-cloud-bigtable-tool}/bin/cbt -instance instance-1 -project project-1 createtable directories
-      ${pkgs.google-cloud-bigtable-tool}/bin/cbt -instance instance-1 -project project-1 createfamily directories cf1
-      ${pkgs.google-cloud-bigtable-tool}/bin/cbt -instance instance-1 -project project-1 createtable pathinfos
-      ${pkgs.google-cloud-bigtable-tool}/bin/cbt -instance instance-1 -project project-1 createfamily pathinfos cf1
-    '';
-    isClosure = true;
-    vmCmdline = "init=${testSystem}/init panic=-1"; # reboot immediately on panic
-    assertVMOutput = "Onwards and upwards.";
-  });
-
-  closure-nixos-s3 = (mkBootTest {
-    blobServiceAddr = "objectstore+s3://mybucket/blobs?aws_access_key_id=myaccesskey&aws_secret_access_key=supersecret&aws_endpoint_url=http%3A%2F%2Flocalhost%3A9000&aws_allow_http=1";
-    # we cannot use s3 here yet without any caching layer, as we don't allow "deeper" access to directories (non-root nodes)
-    # directoryServiceAddr = "objectstore+s3://mybucket/directories?aws_access_key_id=myaccesskey&aws_secret_access_key=supersecret&endpoint=http%3A%2F%2Flocalhost%3A9000&aws_allow_http=1";
-    directoryServiceAddr = "memory://";
-    pathInfoServiceAddr = "memory://";
-    path = testSystem;
-    useNarBridge = true;
-    preStart = ''
-      MINIO_ACCESS_KEY=myaccesskey MINIO_SECRET_KEY=supersecret MINIO_ADDRESS=127.0.0.1:9000 ${pkgs.minio}/bin/minio server $(mktemp -d) &
-      timeout 22 sh -c 'until ${pkgs.netcat}/bin/nc -z $0 $1; do sleep 1; done' localhost 9000
-      mc_config_dir=$(mktemp -d)
-      ${pkgs.minio-client}/bin/mc --config-dir $mc_config_dir alias set 'myminio' 'http://127.0.0.1:9000' 'myaccesskey' 'supersecret'
-      ${pkgs.minio-client}/bin/mc --config-dir $mc_config_dir mb myminio/mybucket
-    '';
-    isClosure = true;
-    vmCmdline = "init=${testSystem}/init panic=-1"; # reboot immediately on panic
-    assertVMOutput = "Onwards and upwards.";
-  });
-
-  closure-nixos-nar-bridge = (mkBootTest {
-    blobServiceAddr = "objectstore+file:///build/blobs";
-    path = testSystem;
-    useNarBridge = true;
-    isClosure = true;
-    vmCmdline = "init=${testSystem}/init panic=-1"; # reboot immediately on panic
-    assertVMOutput = "Onwards and upwards.";
-  });
-}
+# remove broken tests from set
+builtins.removeAttrs allTests [
+  # these fail in CI as of 2025-02-09, printing HTTP errors
+  "closure-nixos-bigtable"
+  "closure-nixos-nar-bridge"
+  "closure-nixos-s3"
+]
diff --git a/tvix/build-go/build.pb.go b/tvix/build-go/build.pb.go
index aaa62d23910f..a8d2b6ae6fc5 100644
--- a/tvix/build-go/build.pb.go
+++ b/tvix/build-go/build.pb.go
@@ -3,7 +3,7 @@
 
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.36.1
+// 	protoc-gen-go v1.36.4
 // 	protoc        (unknown)
 // source: tvix/build/protos/build.proto
 
@@ -15,6 +15,7 @@ import (
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	reflect "reflect"
 	sync "sync"
+	unsafe "unsafe"
 )
 
 const (
@@ -530,7 +531,7 @@ func (x *Build_OutputNeedles) GetNeedles() []uint64 {
 
 var File_tvix_build_protos_build_proto protoreflect.FileDescriptor
 
-var file_tvix_build_protos_build_proto_rawDesc = []byte{
+var file_tvix_build_protos_build_proto_rawDesc = string([]byte{
 	0x0a, 0x1d, 0x74, 0x76, 0x69, 0x78, 0x2f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x2f, 0x70, 0x72, 0x6f,
 	0x74, 0x6f, 0x73, 0x2f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
 	0x0d, 0x74, 0x76, 0x69, 0x78, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x2e, 0x76, 0x31, 0x1a, 0x21,
@@ -606,16 +607,16 @@ var file_tvix_build_protos_build_proto_rawDesc = []byte{
 	0x65, 0x73, 0x42, 0x24, 0x5a, 0x22, 0x63, 0x6f, 0x64, 0x65, 0x2e, 0x74, 0x76, 0x6c, 0x2e, 0x66,
 	0x79, 0x69, 0x2f, 0x74, 0x76, 0x69, 0x78, 0x2f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x2d, 0x67, 0x6f,
 	0x3b, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
-}
+})
 
 var (
 	file_tvix_build_protos_build_proto_rawDescOnce sync.Once
-	file_tvix_build_protos_build_proto_rawDescData = file_tvix_build_protos_build_proto_rawDesc
+	file_tvix_build_protos_build_proto_rawDescData []byte
 )
 
 func file_tvix_build_protos_build_proto_rawDescGZIP() []byte {
 	file_tvix_build_protos_build_proto_rawDescOnce.Do(func() {
-		file_tvix_build_protos_build_proto_rawDescData = protoimpl.X.CompressGZIP(file_tvix_build_protos_build_proto_rawDescData)
+		file_tvix_build_protos_build_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_tvix_build_protos_build_proto_rawDesc), len(file_tvix_build_protos_build_proto_rawDesc)))
 	})
 	return file_tvix_build_protos_build_proto_rawDescData
 }
@@ -654,7 +655,7 @@ func file_tvix_build_protos_build_proto_init() {
 	out := protoimpl.TypeBuilder{
 		File: protoimpl.DescBuilder{
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
-			RawDescriptor: file_tvix_build_protos_build_proto_rawDesc,
+			RawDescriptor: unsafe.Slice(unsafe.StringData(file_tvix_build_protos_build_proto_rawDesc), len(file_tvix_build_protos_build_proto_rawDesc)),
 			NumEnums:      0,
 			NumMessages:   6,
 			NumExtensions: 0,
@@ -665,7 +666,6 @@ func file_tvix_build_protos_build_proto_init() {
 		MessageInfos:      file_tvix_build_protos_build_proto_msgTypes,
 	}.Build()
 	File_tvix_build_protos_build_proto = out.File
-	file_tvix_build_protos_build_proto_rawDesc = nil
 	file_tvix_build_protos_build_proto_goTypes = nil
 	file_tvix_build_protos_build_proto_depIdxs = nil
 }
diff --git a/tvix/build-go/rpc_build.pb.go b/tvix/build-go/rpc_build.pb.go
index b586035d0216..0e1653e8d1af 100644
--- a/tvix/build-go/rpc_build.pb.go
+++ b/tvix/build-go/rpc_build.pb.go
@@ -3,7 +3,7 @@
 
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.36.1
+// 	protoc-gen-go v1.36.4
 // 	protoc        (unknown)
 // source: tvix/build/protos/rpc_build.proto
 
@@ -13,6 +13,7 @@ import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	reflect "reflect"
+	unsafe "unsafe"
 )
 
 const (
@@ -24,7 +25,7 @@ const (
 
 var File_tvix_build_protos_rpc_build_proto protoreflect.FileDescriptor
 
-var file_tvix_build_protos_rpc_build_proto_rawDesc = []byte{
+var file_tvix_build_protos_rpc_build_proto_rawDesc = string([]byte{
 	0x0a, 0x21, 0x74, 0x76, 0x69, 0x78, 0x2f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x2f, 0x70, 0x72, 0x6f,
 	0x74, 0x6f, 0x73, 0x2f, 0x72, 0x70, 0x63, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x2e, 0x70, 0x72,
 	0x6f, 0x74, 0x6f, 0x12, 0x0d, 0x74, 0x76, 0x69, 0x78, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x2e,
@@ -38,7 +39,7 @@ var file_tvix_build_protos_rpc_build_proto_rawDesc = []byte{
 	0x24, 0x5a, 0x22, 0x63, 0x6f, 0x64, 0x65, 0x2e, 0x74, 0x76, 0x6c, 0x2e, 0x66, 0x79, 0x69, 0x2f,
 	0x74, 0x76, 0x69, 0x78, 0x2f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x2d, 0x67, 0x6f, 0x3b, 0x62, 0x75,
 	0x69, 0x6c, 0x64, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
-}
+})
 
 var file_tvix_build_protos_rpc_build_proto_goTypes = []any{
 	(*BuildRequest)(nil), // 0: tvix.build.v1.BuildRequest
@@ -64,7 +65,7 @@ func file_tvix_build_protos_rpc_build_proto_init() {
 	out := protoimpl.TypeBuilder{
 		File: protoimpl.DescBuilder{
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
-			RawDescriptor: file_tvix_build_protos_rpc_build_proto_rawDesc,
+			RawDescriptor: unsafe.Slice(unsafe.StringData(file_tvix_build_protos_rpc_build_proto_rawDesc), len(file_tvix_build_protos_rpc_build_proto_rawDesc)),
 			NumEnums:      0,
 			NumMessages:   0,
 			NumExtensions: 0,
@@ -74,7 +75,6 @@ func file_tvix_build_protos_rpc_build_proto_init() {
 		DependencyIndexes: file_tvix_build_protos_rpc_build_proto_depIdxs,
 	}.Build()
 	File_tvix_build_protos_rpc_build_proto = out.File
-	file_tvix_build_protos_rpc_build_proto_rawDesc = nil
 	file_tvix_build_protos_rpc_build_proto_goTypes = nil
 	file_tvix_build_protos_rpc_build_proto_depIdxs = nil
 }
diff --git a/tvix/castore-go/castore.pb.go b/tvix/castore-go/castore.pb.go
index 9968718c1c2b..f76b9c9eefaa 100644
--- a/tvix/castore-go/castore.pb.go
+++ b/tvix/castore-go/castore.pb.go
@@ -3,7 +3,7 @@
 
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.36.1
+// 	protoc-gen-go v1.36.4
 // 	protoc        (unknown)
 // source: tvix/castore/protos/castore.proto
 
@@ -14,6 +14,7 @@ import (
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	reflect "reflect"
 	sync "sync"
+	unsafe "unsafe"
 )
 
 const (
@@ -395,7 +396,7 @@ func (*Node_Symlink) isNode_Node() {}
 
 var File_tvix_castore_protos_castore_proto protoreflect.FileDescriptor
 
-var file_tvix_castore_protos_castore_proto_rawDesc = []byte{
+var file_tvix_castore_protos_castore_proto_rawDesc = string([]byte{
 	0x0a, 0x21, 0x74, 0x76, 0x69, 0x78, 0x2f, 0x63, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x70,
 	0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x63, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72,
 	0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x74, 0x76, 0x69, 0x78, 0x2e, 0x63, 0x61, 0x73, 0x74, 0x6f, 0x72,
@@ -442,16 +443,16 @@ var file_tvix_castore_protos_castore_proto_rawDesc = []byte{
 	0x66, 0x79, 0x69, 0x2f, 0x74, 0x76, 0x69, 0x78, 0x2f, 0x63, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65,
 	0x2d, 0x67, 0x6f, 0x3b, 0x63, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x76, 0x31, 0x62, 0x06, 0x70,
 	0x72, 0x6f, 0x74, 0x6f, 0x33,
-}
+})
 
 var (
 	file_tvix_castore_protos_castore_proto_rawDescOnce sync.Once
-	file_tvix_castore_protos_castore_proto_rawDescData = file_tvix_castore_protos_castore_proto_rawDesc
+	file_tvix_castore_protos_castore_proto_rawDescData []byte
 )
 
 func file_tvix_castore_protos_castore_proto_rawDescGZIP() []byte {
 	file_tvix_castore_protos_castore_proto_rawDescOnce.Do(func() {
-		file_tvix_castore_protos_castore_proto_rawDescData = protoimpl.X.CompressGZIP(file_tvix_castore_protos_castore_proto_rawDescData)
+		file_tvix_castore_protos_castore_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_tvix_castore_protos_castore_proto_rawDesc), len(file_tvix_castore_protos_castore_proto_rawDesc)))
 	})
 	return file_tvix_castore_protos_castore_proto_rawDescData
 }
@@ -492,7 +493,7 @@ func file_tvix_castore_protos_castore_proto_init() {
 	out := protoimpl.TypeBuilder{
 		File: protoimpl.DescBuilder{
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
-			RawDescriptor: file_tvix_castore_protos_castore_proto_rawDesc,
+			RawDescriptor: unsafe.Slice(unsafe.StringData(file_tvix_castore_protos_castore_proto_rawDesc), len(file_tvix_castore_protos_castore_proto_rawDesc)),
 			NumEnums:      0,
 			NumMessages:   5,
 			NumExtensions: 0,
@@ -503,7 +504,6 @@ func file_tvix_castore_protos_castore_proto_init() {
 		MessageInfos:      file_tvix_castore_protos_castore_proto_msgTypes,
 	}.Build()
 	File_tvix_castore_protos_castore_proto = out.File
-	file_tvix_castore_protos_castore_proto_rawDesc = nil
 	file_tvix_castore_protos_castore_proto_goTypes = nil
 	file_tvix_castore_protos_castore_proto_depIdxs = nil
 }
diff --git a/tvix/castore-go/rpc_blobstore.pb.go b/tvix/castore-go/rpc_blobstore.pb.go
index dfc4a2e50275..c93fe20e47fd 100644
--- a/tvix/castore-go/rpc_blobstore.pb.go
+++ b/tvix/castore-go/rpc_blobstore.pb.go
@@ -3,7 +3,7 @@
 
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.36.1
+// 	protoc-gen-go v1.36.4
 // 	protoc        (unknown)
 // source: tvix/castore/protos/rpc_blobstore.proto
 
@@ -14,6 +14,7 @@ import (
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	reflect "reflect"
 	sync "sync"
+	unsafe "unsafe"
 )
 
 const (
@@ -335,7 +336,7 @@ func (x *StatBlobResponse_ChunkMeta) GetSize() uint64 {
 
 var File_tvix_castore_protos_rpc_blobstore_proto protoreflect.FileDescriptor
 
-var file_tvix_castore_protos_rpc_blobstore_proto_rawDesc = []byte{
+var file_tvix_castore_protos_rpc_blobstore_proto_rawDesc = string([]byte{
 	0x0a, 0x27, 0x74, 0x76, 0x69, 0x78, 0x2f, 0x63, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x70,
 	0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x72, 0x70, 0x63, 0x5f, 0x62, 0x6c, 0x6f, 0x62, 0x73, 0x74,
 	0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x74, 0x76, 0x69, 0x78, 0x2e,
@@ -382,16 +383,16 @@ var file_tvix_castore_protos_rpc_blobstore_proto_rawDesc = []byte{
 	0x65, 0x2e, 0x74, 0x76, 0x6c, 0x2e, 0x66, 0x79, 0x69, 0x2f, 0x74, 0x76, 0x69, 0x78, 0x2f, 0x63,
 	0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2d, 0x67, 0x6f, 0x3b, 0x63, 0x61, 0x73, 0x74, 0x6f, 0x72,
 	0x65, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
-}
+})
 
 var (
 	file_tvix_castore_protos_rpc_blobstore_proto_rawDescOnce sync.Once
-	file_tvix_castore_protos_rpc_blobstore_proto_rawDescData = file_tvix_castore_protos_rpc_blobstore_proto_rawDesc
+	file_tvix_castore_protos_rpc_blobstore_proto_rawDescData []byte
 )
 
 func file_tvix_castore_protos_rpc_blobstore_proto_rawDescGZIP() []byte {
 	file_tvix_castore_protos_rpc_blobstore_proto_rawDescOnce.Do(func() {
-		file_tvix_castore_protos_rpc_blobstore_proto_rawDescData = protoimpl.X.CompressGZIP(file_tvix_castore_protos_rpc_blobstore_proto_rawDescData)
+		file_tvix_castore_protos_rpc_blobstore_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_tvix_castore_protos_rpc_blobstore_proto_rawDesc), len(file_tvix_castore_protos_rpc_blobstore_proto_rawDesc)))
 	})
 	return file_tvix_castore_protos_rpc_blobstore_proto_rawDescData
 }
@@ -429,7 +430,7 @@ func file_tvix_castore_protos_rpc_blobstore_proto_init() {
 	out := protoimpl.TypeBuilder{
 		File: protoimpl.DescBuilder{
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
-			RawDescriptor: file_tvix_castore_protos_rpc_blobstore_proto_rawDesc,
+			RawDescriptor: unsafe.Slice(unsafe.StringData(file_tvix_castore_protos_rpc_blobstore_proto_rawDesc), len(file_tvix_castore_protos_rpc_blobstore_proto_rawDesc)),
 			NumEnums:      0,
 			NumMessages:   6,
 			NumExtensions: 0,
@@ -440,7 +441,6 @@ func file_tvix_castore_protos_rpc_blobstore_proto_init() {
 		MessageInfos:      file_tvix_castore_protos_rpc_blobstore_proto_msgTypes,
 	}.Build()
 	File_tvix_castore_protos_rpc_blobstore_proto = out.File
-	file_tvix_castore_protos_rpc_blobstore_proto_rawDesc = nil
 	file_tvix_castore_protos_rpc_blobstore_proto_goTypes = nil
 	file_tvix_castore_protos_rpc_blobstore_proto_depIdxs = nil
 }
diff --git a/tvix/castore-go/rpc_directory.pb.go b/tvix/castore-go/rpc_directory.pb.go
index 8da866c0fd2b..d323bbdd63bb 100644
--- a/tvix/castore-go/rpc_directory.pb.go
+++ b/tvix/castore-go/rpc_directory.pb.go
@@ -3,7 +3,7 @@
 
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.36.1
+// 	protoc-gen-go v1.36.4
 // 	protoc        (unknown)
 // source: tvix/castore/protos/rpc_directory.proto
 
@@ -14,6 +14,7 @@ import (
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	reflect "reflect"
 	sync "sync"
+	unsafe "unsafe"
 )
 
 const (
@@ -150,7 +151,7 @@ func (x *PutDirectoryResponse) GetRootDigest() []byte {
 
 var File_tvix_castore_protos_rpc_directory_proto protoreflect.FileDescriptor
 
-var file_tvix_castore_protos_rpc_directory_proto_rawDesc = []byte{
+var file_tvix_castore_protos_rpc_directory_proto_rawDesc = string([]byte{
 	0x0a, 0x27, 0x74, 0x76, 0x69, 0x78, 0x2f, 0x63, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x70,
 	0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x72, 0x70, 0x63, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74,
 	0x6f, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x74, 0x76, 0x69, 0x78, 0x2e,
@@ -180,16 +181,16 @@ var file_tvix_castore_protos_rpc_directory_proto_rawDesc = []byte{
 	0x63, 0x6f, 0x64, 0x65, 0x2e, 0x74, 0x76, 0x6c, 0x2e, 0x66, 0x79, 0x69, 0x2f, 0x74, 0x76, 0x69,
 	0x78, 0x2f, 0x63, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2d, 0x67, 0x6f, 0x3b, 0x63, 0x61, 0x73,
 	0x74, 0x6f, 0x72, 0x65, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
-}
+})
 
 var (
 	file_tvix_castore_protos_rpc_directory_proto_rawDescOnce sync.Once
-	file_tvix_castore_protos_rpc_directory_proto_rawDescData = file_tvix_castore_protos_rpc_directory_proto_rawDesc
+	file_tvix_castore_protos_rpc_directory_proto_rawDescData []byte
 )
 
 func file_tvix_castore_protos_rpc_directory_proto_rawDescGZIP() []byte {
 	file_tvix_castore_protos_rpc_directory_proto_rawDescOnce.Do(func() {
-		file_tvix_castore_protos_rpc_directory_proto_rawDescData = protoimpl.X.CompressGZIP(file_tvix_castore_protos_rpc_directory_proto_rawDescData)
+		file_tvix_castore_protos_rpc_directory_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_tvix_castore_protos_rpc_directory_proto_rawDesc), len(file_tvix_castore_protos_rpc_directory_proto_rawDesc)))
 	})
 	return file_tvix_castore_protos_rpc_directory_proto_rawDescData
 }
@@ -225,7 +226,7 @@ func file_tvix_castore_protos_rpc_directory_proto_init() {
 	out := protoimpl.TypeBuilder{
 		File: protoimpl.DescBuilder{
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
-			RawDescriptor: file_tvix_castore_protos_rpc_directory_proto_rawDesc,
+			RawDescriptor: unsafe.Slice(unsafe.StringData(file_tvix_castore_protos_rpc_directory_proto_rawDesc), len(file_tvix_castore_protos_rpc_directory_proto_rawDesc)),
 			NumEnums:      0,
 			NumMessages:   2,
 			NumExtensions: 0,
@@ -236,7 +237,6 @@ func file_tvix_castore_protos_rpc_directory_proto_init() {
 		MessageInfos:      file_tvix_castore_protos_rpc_directory_proto_msgTypes,
 	}.Build()
 	File_tvix_castore_protos_rpc_directory_proto = out.File
-	file_tvix_castore_protos_rpc_directory_proto_rawDesc = nil
 	file_tvix_castore_protos_rpc_directory_proto_goTypes = nil
 	file_tvix_castore_protos_rpc_directory_proto_depIdxs = nil
 }
diff --git a/tvix/docs/src/eval/vm-loop.md b/tvix/docs/src/eval/vm-loop.md
index a75c7eec31df..a964d9278c75 100644
--- a/tvix/docs/src/eval/vm-loop.md
+++ b/tvix/docs/src/eval/vm-loop.md
@@ -243,8 +243,8 @@ generator loop after setting up the frame stack.
 Most of this logic is implemented in cl/8148.
 
 [`Gen::resume`]: https://docs.rs/genawaiter/0.99.1/genawaiter/rc/struct.Gen.html#method.resume_with
-[`VMRequest`]: https://cs.tvl.fyi/depot@2696839770c1ccb62929ff2575a633c07f5c9593/-/blob/tvix/eval/src/vm/generators.rs?L44
-[`VMResponse`]: https://cs.tvl.fyi/depot@2696839770c1ccb62929ff2575a633c07f5c9593/-/blob/tvix/eval/src/vm/generators.rs?L169
+[`VMRequest`]: https://code.tvl.fyi/tree/tvix/eval/src/vm/generators.rs?id=2696839770c1ccb62929ff2575a633c07f5c9593#n44
+[`VMResponse`]: https://code.tvl.fyi/tree/tvix/eval/src/vm/generators.rs?id=2696839770c1ccb62929ff2575a633c07f5c9593#n169
 
 ## Advantages & Disadvantages of the approach
 
diff --git a/tvix/docs/src/introduction.md b/tvix/docs/src/introduction.md
index 744fbeec9fbe..e4ed45f88e0c 100644
--- a/tvix/docs/src/introduction.md
+++ b/tvix/docs/src/introduction.md
@@ -19,5 +19,5 @@ source code available in the [TVL monorepo][].
 
 [Nix]: https://nixos.org
 [TVL]: https://tvl.fyi
-[TVL monorepo]: https://cs.tvl.fyi/depot/-/tree/tvix
+[TVL monorepo]: https://code.tvl.fyi/tree/tvix
 [pronunciation]: data:audio/mpeg;base64,SUQzBAAAAAAAI1RTU0UAAAAPAAADTGF2ZjU4Ljc2LjEwMAAAAAAAAAAAAAAA//NgxAAdEr31SGDGIQAoBRVe/7Yuv8SvC9C3dwMwOCEAE6YG/Cc/fQkSu5PE0Jzr6cRKhH6IEIIiIhOyU5Xdxbk5/0+vpvppXc/hQkrn7iCrn6e/XPield3Mq5oXh3cOLjgB3/+Zl4HAMuH/mAZpM8w8PDw9wAIk//5//gAODz/D1QNAKDLoeuUxZd2VeX0qV80WaVrSQech1Qpo//NixBofrA4YAVQoAYBzKPexmkFBrpGj2IrFxAh2NqwmjI9Bz+zGah1nVTsQQYlvF69rIzoTfLO6sqxMenRnYhhQe0yrQUNoTIrIymeh9/WtTnRjsk4wUEzE/10PE3ibzlRnQc6/o9BICCbzEVRN/E4CAAcgABBIgEtvMot7RXUwz1qnlmvx3zszWyTQ3PnVX6qRmWjvMuWn9CQGyP/zYsQrJuN+NYuYWAEASB1virzQzUvD2SBsJ598MYyYWUpZ6qA6mEkHbSSIDhm8/H9plcHHrYez50ll+Wj//uv7ZT1GfzU3fbbr+n7LPuVZHL9SPn+nww5M3d//3WdmV5O//9HYa2v9/MO7/iPY+tbPP3mqOf7M9YkkMSav2ub42nG43G5HIvvggKFUSYCII1JJlw5Z6Zl7q1gf4Yn/82LEHyfjCo29jHgCUQzqTIkkWtXFjjE6fsipzrFmZQMjI5ItTsH9c63TUWysQ5U0gKuGfMHW9xc1on58bw/fZTZkXamGN4tIM0bGPq0SlY8sJwn//v8/eNU1//j5zvGMb1u8e9/hz3nUPeb4v////r5+a1/9//97/3nesw9/3pKBi////wi4LtEAQQBKQdcrtttdriljiVQZDRBu//NgxA8jssa+X4xAAIyZIQuhQmsVXnSZQfa38AQAguDwKgVRGIoN7QuWGlkB4o01SRTOVz0IMe20lLfhYMST5BsMuNazInz4SXvROUIqeXKGlRF+tFu/ufB9OrGVnjnFYHB/ZL/3//yicvMVv8JzcxLo90MU0OFzaD9BIV4nxgAM8o54spq1vWJ3J1euBsqXgjzNIQwkDXFa+z0M//NixA8jY36IAZlAAE0Rhou7HpU1l3MchEFXAVQ+LzxKHghCoadED8LrAiMaa3xRZJAknkov/0FXWIS2baSv/8BUUcW+QUiR1evWF///Bt0o6RW5m5hYJUYsXF8p////0IR5Zrg8JXOOYVF8gZJHCk1zqTKx/Hf/NfEKJk//Q4OOvjk2lgr2KwVRuroANCW22220WC22WxxSJFJw///zYsQRIPpawl+PQAJIok7ku2H1FcavOpWYUpCxe5s1Q+UMGBAYIxQMDgDA7pVwZaCAHim/+9y90RRhX/+fFaUgdCMJty+f/76mfduCSBt2zTfz///0ic173oKSszA1maHKny9l0yXDjzAfxax9QnSpfGXFwuopIpFDapMcuhPXAR3d0afa5G6KRfINNDCox6CHM0gRpAHhcjpg5S//82LEHSehUqZ/2MAAstHIU01fRJTCUN0W5ONikDty+mkOcMdZggMiyaKrk5FopDHCDIREY5AUvBrQy6mEtXwj5KF2NnjqmcNPxI1hFYIw4cDPo7jsORGJyxhvu7VJ9JSU9PfHgh+s+kasgvIDmlycQOTKARwslggLg44MRq0e9zQPs94laXjb3mzJ4UOxRZAAVyUswcgDasxCuqXL//NgxA4fmbakXspMYGEihpTRnTNbuO2ScS7G8HnUYI0VUba51KySxTFPhAGIBWhZaUlpDwIKEUEFhRRIzMs0un31sV8pgYkDIo/////NZ7kCXBR5z/SmcfCtV7CBYROck2wt1PNAIWBpH20Ch06Mi7nAk6+0XTcL0j1jHvMKBjRANkjutdRwilbDIuehzRxbsWWi8O2LtKEAnFGg//NixB4Y2VKpHsDEnBAxM9VjUzUTxwpSxo3AKtq31VWBlKwUfHv8MKcPFQF6xg8NDlvb/jYab0ka3Q02RWr6nnoat/kxFMsfSd9N1V70VMQEQlUAAWVIF9yCKxm5BjQQyFCjvEAhZkFiwpgEl+ZTMQ9VBAo8lZIkcRIsmUt2JOCoEsO02W3zMnWjMttVnOJbLY1fZOAgf61FKRAJy//zYsRKHYIKclTJhJz/EmyjLKhmM5jG/m/MKFyxPj5WLwlshMRM9RJbjSEpKJ2XajtyqPrsVoMplgElrTccgAtkE8gNDDUgCYAXcJ+KZwji3XvujuyuqqkxkbfGZ1DKtgZj2KNQokgJo0LNS43+WVCkYca9L7GVPh3PpOFRqX6l/5/3Rur//7Lw/2/gXzNXUmb/8+r+cqrG1/jHV1L/82LEZB9r2lmdUxgBY12NW/8yra/VWCY2onY2OqTCqWoDlFYuNJIHSADU0zPoXEANHC/CJQ9VXi2VkPWYu/o3ey675hhm83g4Gol1zFaZnNPdWtnvpzz3pm23+qfMRrP3/6/r/X0+hh85+nmX/Xfm9z9jxwgQSQmIOEPp/VLtr+7q30XaQOBi7SH6gvr/6+/759gUGYNgwPy9etHb//NgxHYY48Zc8484AJ+xN8+cpj5c1N6jT6efgxULyUJDRo8HjxIoqkgnU6rJKkyo1MmEVdlbq8/tio2Xzz+92+/hh7Y2PfDnnZb////tivb//ppv///3GtRNroKtdtiYhOyKSA54dcWIJUKiA8CqGhH/EQqaTS22Kh0VuREVT2/1jkddqAETOd02plawNh7D0gUlIdr7skBZn36Z//NixKEgqp6NlYxYAILyK/Me3NLnji/AGNiP/ppZtSKjlJ0l2MObV3mZmlKRXWLGCQYQn9E46Jzv2Dzpxf/ysWLHKsCQYdizplszP2DBZSnMOXSKJbJb9FksHm6vsrKhodn6+PayULvD6VXqeH9uhIKMilwo0yP2CBnvLSy5ndd/2V52KZe9tOpbuyd50yIzNGgAOzgxhghLnrj73v/zYsSuHxo60l/PYAIQvV0+Y8c5Eve9aCLA7KyvyIpHHTD8kJXBY/XQ6tJix57v/z7aytZXaxOQCgTtIiBnYRmvAn2ZvJfF28zb+Z/Wrwcqb/5/Lgd8RmsQIfWbvKmJZVsISTlOJrSMeiTp8eUdLeIww1K0tPobChnijzJqdpCJGzAMMm+137+u1ZW2uNLKYbv3Gp79FOb9/28bG1f/82LEwR+bMspeEZOsn/dzWfGbF0+9GL7VV/TnVRMHHkLI1ESlvkmsXHOKdIxhqJB5JP0v3//d3ec/7ZetjPpTRMCX/o6Cn9pNqMqqp20AIAUhbGQ2DwQQQajwGmTvpPPSJnvJq0tNMO2ctFOry7oUse5nGs7ig8jCIYQ3qdHYjFUUgVysGNUxCFFnQIsEwuheniLPf/0BXDnTKQBN//NgxNIfOz7PHjBM8CgRwalCwMUpnK7E5qBQEbDK2TUjYjWH2k3dej3zKqqtTHLqs9vnyUABQryVhSrrkyQmUKEyNw88ZKsHE3objjf+74httv+/7btZmU0T2JS6eKit8fLYwttZwfiZViggsacmKkdh5ktgIc8eqhp1WK2SNdYROKUApEUkD5b///7JlyI0S////2igt0ZUAoGR//NixOQd0rLHHlmEPAgysKqZnSLShsPjwV5YYAMPciIi7Ci6nWZJTz0MYSRsSxCiSQ4VJOUHQ7EQ9wkfzy/kPTrqVTK7NYDABwwlZGkyjLS80AYda6qhOy6TSym7epLitq8UJx4QIyIy1Hp4tNC4hSzspu9rPQ/P/9ZVIn0qoAIfdBUESW1UKGLSz4/pEzRC1EQ6kweN/JKHRUpUe//zYsT8KGruolJL04QXyh0uNArGozLD+BhSxsBVGq6QCMKqsGYMBMrUgqki2HXQme1PcskWvW74a8ra7QoAigIobgqjopUJPqbNBY8/DxS92FTwxupQx5wodcqHbcTeCAXqmqkinH6iNJHaKmXLGKEJhKncFgtEGSwkgSSOXMhMm5/3nEpmStNNRqu3p21/LaxJL1RjKUv/Khuu8yP/82DE6iJa2pZMSUfE0e5SmVHKxvSa6AMK0cpeIjjGM6sxUOVjKIh0ylZSpV8xqCQc3A1lRkqr88y7rO1aKlwMtBNoJmhGGCDxgh6UJfVM2PXVKmLM5lkah6mdmczj0nZS6sSjUtgKHoakUZGigFACs7Sl4SZKW8wDBTbOU6IMuq/75Tvn5yU53/OJJUcSx5kjM+fsYU+Z//USxW//82LE7yQTFmmCwYswDAQ86RpBWGiqw1Dp3DqwVATjoifDskVQVcoKB0NHutyw0Gmekq5p7JVuUeqqTEFNRaqqUJagECihZAmgmpE40ouLi2v/mRkfRrLJUcZlDBQoYGCDo5GyhgcdDIjWWWW//////mrKGBgg7oZMoYGiORqGCggYMFUcjL/7LmasoYGCDhI6GTLLZZZZb5GrWSx0//NixO4ikg4wCtGFFDJlWVDJlYMFBAwjoZFLP/8mVrLY5GrWSo5MrUKCBwxKtUxBTUUzLjEwMFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVf/zYsTtH1vZLBQwRq1VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVU=
diff --git a/tvix/store-go/pathinfo.pb.go b/tvix/store-go/pathinfo.pb.go
index 2350a8dc4812..bc0ddafde8b0 100644
--- a/tvix/store-go/pathinfo.pb.go
+++ b/tvix/store-go/pathinfo.pb.go
@@ -3,7 +3,7 @@
 
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.36.1
+// 	protoc-gen-go v1.36.4
 // 	protoc        (unknown)
 // source: tvix/store/protos/pathinfo.proto
 
@@ -15,6 +15,7 @@ import (
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	reflect "reflect"
 	sync "sync"
+	unsafe "unsafe"
 )
 
 const (
@@ -457,7 +458,7 @@ func (x *NARInfo_CA) GetDigest() []byte {
 
 var File_tvix_store_protos_pathinfo_proto protoreflect.FileDescriptor
 
-var file_tvix_store_protos_pathinfo_proto_rawDesc = []byte{
+var file_tvix_store_protos_pathinfo_proto_rawDesc = string([]byte{
 	0x0a, 0x20, 0x74, 0x76, 0x69, 0x78, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f,
 	0x74, 0x6f, 0x73, 0x2f, 0x70, 0x61, 0x74, 0x68, 0x69, 0x6e, 0x66, 0x6f, 0x2e, 0x70, 0x72, 0x6f,
 	0x74, 0x6f, 0x12, 0x0d, 0x74, 0x76, 0x69, 0x78, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76,
@@ -514,16 +515,16 @@ var file_tvix_store_protos_pathinfo_proto_rawDesc = []byte{
 	0x66, 0x79, 0x69, 0x2f, 0x74, 0x76, 0x69, 0x78, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2d, 0x67,
 	0x6f, 0x3b, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
 	0x33,
-}
+})
 
 var (
 	file_tvix_store_protos_pathinfo_proto_rawDescOnce sync.Once
-	file_tvix_store_protos_pathinfo_proto_rawDescData = file_tvix_store_protos_pathinfo_proto_rawDesc
+	file_tvix_store_protos_pathinfo_proto_rawDescData []byte
 )
 
 func file_tvix_store_protos_pathinfo_proto_rawDescGZIP() []byte {
 	file_tvix_store_protos_pathinfo_proto_rawDescOnce.Do(func() {
-		file_tvix_store_protos_pathinfo_proto_rawDescData = protoimpl.X.CompressGZIP(file_tvix_store_protos_pathinfo_proto_rawDescData)
+		file_tvix_store_protos_pathinfo_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_tvix_store_protos_pathinfo_proto_rawDesc), len(file_tvix_store_protos_pathinfo_proto_rawDesc)))
 	})
 	return file_tvix_store_protos_pathinfo_proto_rawDescData
 }
@@ -562,7 +563,7 @@ func file_tvix_store_protos_pathinfo_proto_init() {
 	out := protoimpl.TypeBuilder{
 		File: protoimpl.DescBuilder{
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
-			RawDescriptor: file_tvix_store_protos_pathinfo_proto_rawDesc,
+			RawDescriptor: unsafe.Slice(unsafe.StringData(file_tvix_store_protos_pathinfo_proto_rawDesc), len(file_tvix_store_protos_pathinfo_proto_rawDesc)),
 			NumEnums:      1,
 			NumMessages:   5,
 			NumExtensions: 0,
@@ -574,7 +575,6 @@ func file_tvix_store_protos_pathinfo_proto_init() {
 		MessageInfos:      file_tvix_store_protos_pathinfo_proto_msgTypes,
 	}.Build()
 	File_tvix_store_protos_pathinfo_proto = out.File
-	file_tvix_store_protos_pathinfo_proto_rawDesc = nil
 	file_tvix_store_protos_pathinfo_proto_goTypes = nil
 	file_tvix_store_protos_pathinfo_proto_depIdxs = nil
 }
diff --git a/tvix/store-go/rpc_pathinfo.pb.go b/tvix/store-go/rpc_pathinfo.pb.go
index eb88ceee4550..2b8f1d843d38 100644
--- a/tvix/store-go/rpc_pathinfo.pb.go
+++ b/tvix/store-go/rpc_pathinfo.pb.go
@@ -3,7 +3,7 @@
 
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.36.1
+// 	protoc-gen-go v1.36.4
 // 	protoc        (unknown)
 // source: tvix/store/protos/rpc_pathinfo.proto
 
@@ -15,6 +15,7 @@ import (
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	reflect "reflect"
 	sync "sync"
+	unsafe "unsafe"
 )
 
 const (
@@ -194,7 +195,7 @@ func (x *CalculateNARResponse) GetNarSha256() []byte {
 
 var File_tvix_store_protos_rpc_pathinfo_proto protoreflect.FileDescriptor
 
-var file_tvix_store_protos_rpc_pathinfo_proto_rawDesc = []byte{
+var file_tvix_store_protos_rpc_pathinfo_proto_rawDesc = string([]byte{
 	0x0a, 0x24, 0x74, 0x76, 0x69, 0x78, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f,
 	0x74, 0x6f, 0x73, 0x2f, 0x72, 0x70, 0x63, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x69, 0x6e, 0x66, 0x6f,
 	0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0d, 0x74, 0x76, 0x69, 0x78, 0x2e, 0x73, 0x74, 0x6f,
@@ -235,16 +236,16 @@ var file_tvix_store_protos_rpc_pathinfo_proto_rawDesc = []byte{
 	0x24, 0x5a, 0x22, 0x63, 0x6f, 0x64, 0x65, 0x2e, 0x74, 0x76, 0x6c, 0x2e, 0x66, 0x79, 0x69, 0x2f,
 	0x74, 0x76, 0x69, 0x78, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2d, 0x67, 0x6f, 0x3b, 0x73, 0x74,
 	0x6f, 0x72, 0x65, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
-}
+})
 
 var (
 	file_tvix_store_protos_rpc_pathinfo_proto_rawDescOnce sync.Once
-	file_tvix_store_protos_rpc_pathinfo_proto_rawDescData = file_tvix_store_protos_rpc_pathinfo_proto_rawDesc
+	file_tvix_store_protos_rpc_pathinfo_proto_rawDescData []byte
 )
 
 func file_tvix_store_protos_rpc_pathinfo_proto_rawDescGZIP() []byte {
 	file_tvix_store_protos_rpc_pathinfo_proto_rawDescOnce.Do(func() {
-		file_tvix_store_protos_rpc_pathinfo_proto_rawDescData = protoimpl.X.CompressGZIP(file_tvix_store_protos_rpc_pathinfo_proto_rawDescData)
+		file_tvix_store_protos_rpc_pathinfo_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_tvix_store_protos_rpc_pathinfo_proto_rawDesc), len(file_tvix_store_protos_rpc_pathinfo_proto_rawDesc)))
 	})
 	return file_tvix_store_protos_rpc_pathinfo_proto_rawDescData
 }
@@ -286,7 +287,7 @@ func file_tvix_store_protos_rpc_pathinfo_proto_init() {
 	out := protoimpl.TypeBuilder{
 		File: protoimpl.DescBuilder{
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
-			RawDescriptor: file_tvix_store_protos_rpc_pathinfo_proto_rawDesc,
+			RawDescriptor: unsafe.Slice(unsafe.StringData(file_tvix_store_protos_rpc_pathinfo_proto_rawDesc), len(file_tvix_store_protos_rpc_pathinfo_proto_rawDesc)),
 			NumEnums:      0,
 			NumMessages:   3,
 			NumExtensions: 0,
@@ -297,7 +298,6 @@ func file_tvix_store_protos_rpc_pathinfo_proto_init() {
 		MessageInfos:      file_tvix_store_protos_rpc_pathinfo_proto_msgTypes,
 	}.Build()
 	File_tvix_store_protos_rpc_pathinfo_proto = out.File
-	file_tvix_store_protos_rpc_pathinfo_proto_rawDesc = nil
 	file_tvix_store_protos_rpc_pathinfo_proto_goTypes = nil
 	file_tvix_store_protos_rpc_pathinfo_proto_depIdxs = nil
 }
diff --git a/tvix/website/landing-en.md b/tvix/website/landing-en.md
index f677f20f2fff..0343c6ebd49d 100644
--- a/tvix/website/landing-en.md
+++ b/tvix/website/landing-en.md
@@ -30,7 +30,7 @@ Developer documentation for some parts of Tvix is [available online][docs].
 Benchmarks are run nightly on new commits by [windtunnel][wt].
 
 [TVL]: https://tvl.fyi
-[TVL monorepo]: https://cs.tvl.fyi/depot/-/tree/tvix
+[TVL monorepo]: https://code.tvl.fyi/tree/tvix
 [Tvixbolt]: https://bolt.tvix.dev
 [Tvix README]: https://code.tvl.fyi/about/tvix
 [gh]: https://github.com/tvlfyi/tvix/
diff --git a/users/aspen/resume/resume.tex b/users/aspen/resume/resume.tex
index fb226c4ddffc..11febeb01066 100644
--- a/users/aspen/resume/resume.tex
+++ b/users/aspen/resume/resume.tex
@@ -230,10 +230,10 @@ SQL from the ground up -- and of course also a user}
     {\url{https://blog.readyset.io/bounds-checks/}}{Blog post providing a deep
         evaluation of the runtime cost of bounds checking in safe languages like Rust.
         Front page of Hacker News, doubled month-over-month ReadySet waitlist signups}
-    \project{Tvix}{\url{https://cs.tvl.fyi/depot/-/blob/third\_party/nix/README.md}}{
-        Fork of the Nix build tool delivering increased reliability, code
-        quality, and pluggability}
-    \project{Panettone}{\url{https://cs.tvl.fyi/depot/-/tree/web/panettone}}{
+    \project{Tvix}{\url{https://tvix.dev}}{
+        % TODO(aspen): and now in your own words :)
+        Modular Reimplementation of the Nix build tool in Rust}
+    \project{Panettone}{\url{https://code.tvl.fyi/tree/web/panettone}}{
         Aggressively simple bug-tracker developed in Common Lisp for the community
         involved in the development of Tvix. Hosted at https://b.tvl.fyi}
     \project{Org-Clubhouse}{\url{https://github.com/glittershark/org-clubhouse}}{
diff --git a/users/aspen/system/system/machines/yeren.nix b/users/aspen/system/system/machines/yeren.nix
index 4b563df635aa..1af6327a6cb0 100644
--- a/users/aspen/system/system/machines/yeren.nix
+++ b/users/aspen/system/system/machines/yeren.nix
@@ -33,6 +33,9 @@
       };
     };
 
+    # TODO(aspen): remove after https://github.com/NixOS/nixpkgs/pull/378830/
+    kernelPackages = pkgs.linuxKernel.packages.linux_6_11;
+
     kernelModules = [ "kvm-intel" ];
     blacklistedKernelModules = [ "psmouse" ];
     extraModulePackages = [
diff --git a/users/aspen/web/index.org b/users/aspen/web/index.org
index 109f3a77a08c..7f36d874d54d 100644
--- a/users/aspen/web/index.org
+++ b/users/aspen/web/index.org
@@ -7,7 +7,7 @@ my name is aspen smith and i'm a software engineer and musician.
 * code
 
 - [[https://github.com/glittershark/][github]]
-- [[https://cs.tvl.fyi/depot/-/tree/users/aspen][my directory in the tvl monorepo]]
+- [[https://code.tvl.fyi/tree/users/aspen][my directory in the tvl monorepo]]
 
 * work
 
@@ -24,9 +24,9 @@ that's wire-compatible with postgresql and mysql, based on [[https://github.com/
 - [[https://tvix.dev/][tvix]], a project to reimplement nix in rust with a focus on better performance,
   maintainability, and extensibility. i'm a committer to the project, and mostly
   focus on the implementation of the language evaluator.
-- [[https://cs.tvl.fyi/depot/-/tree/users/aspen/achilles][achilles]], a compiler for (what I plan to become) a dependently typed,
+- [[https://code.tvl.fyi/tree/users/aspen/achilles][achilles]], a compiler for (what I plan to become) a dependently typed,
   low-level functional programming language targeting LLVM
-- [[https://cs.tvl.fyi/depot/-/tree/users/aspen/xanthous][xanthous]], a terminal roguelike in haskell that I work on intermittently and
+- [[https://code.tvl.fyi/tree/users/aspen/xanthous][xanthous]], a terminal roguelike in haskell that I work on intermittently and
   exclusively for fun
 
 * music
diff --git a/users/fogti/store-ref-scanner/Cargo.toml b/users/fogti/store-ref-scanner/Cargo.toml
index 0ed0c20a3938..624cfc0c668c 100644
--- a/users/fogti/store-ref-scanner/Cargo.toml
+++ b/users/fogti/store-ref-scanner/Cargo.toml
@@ -5,7 +5,7 @@ description = "scanner/extractor of Nix-like store paths from byte arrays/stream
 license = "MIT OR Apache-2.0"
 categories = ["no-std", "parsing"]
 edition = "2021"
-homepage = "https://cs.tvl.fyi/depot/-/tree/users/fogti/store-ref-scanner"
+homepage = "https://code.tvl.fyi/tree/users/fogti/store-ref-scanner"
 include = ["/src"]
 
 [dependencies]
diff --git a/users/kranzes/wasm-hello-world/Cargo.lock b/users/kranzes/wasm-hello-world/Cargo.lock
index 5e1cce454d81..0f4b438563f8 100644
--- a/users/kranzes/wasm-hello-world/Cargo.lock
+++ b/users/kranzes/wasm-hello-world/Cargo.lock
@@ -45,6 +45,12 @@ dependencies = [
 ]
 
 [[package]]
+name = "rustversion"
+version = "1.0.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4"
+
+[[package]]
 name = "syn"
 version = "2.0.66"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -63,24 +69,24 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
 
 [[package]]
 name = "wasm-bindgen"
-version = "0.2.95"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e"
+checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
 dependencies = [
  "cfg-if",
  "once_cell",
+ "rustversion",
  "wasm-bindgen-macro",
 ]
 
 [[package]]
 name = "wasm-bindgen-backend"
-version = "0.2.95"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358"
+checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
 dependencies = [
  "bumpalo",
  "log",
- "once_cell",
  "proc-macro2",
  "quote",
  "syn",
@@ -89,9 +95,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro"
-version = "0.2.95"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56"
+checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
 dependencies = [
  "quote",
  "wasm-bindgen-macro-support",
@@ -99,9 +105,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro-support"
-version = "0.2.95"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68"
+checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -112,9 +118,12 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-shared"
-version = "0.2.95"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d"
+checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
+dependencies = [
+ "unicode-ident",
+]
 
 [[package]]
 name = "wasm_hello_world"
diff --git a/users/kranzes/wasm-hello-world/Cargo.nix b/users/kranzes/wasm-hello-world/Cargo.nix
index 9975a2ebf13e..75dcf7f5ddc0 100644
--- a/users/kranzes/wasm-hello-world/Cargo.nix
+++ b/users/kranzes/wasm-hello-world/Cargo.nix
@@ -151,7 +151,6 @@ rec {
           "portable-atomic" = [ "dep:portable-atomic" ];
           "std" = [ "alloc" ];
         };
-        resolvedDefaultFeatures = [ "alloc" "default" "race" "std" ];
       };
       "proc-macro2" = rec {
         crateName = "proc-macro2";
@@ -195,6 +194,18 @@ rec {
         };
         resolvedDefaultFeatures = [ "default" "proc-macro" ];
       };
+      "rustversion" = rec {
+        crateName = "rustversion";
+        version = "1.0.19";
+        edition = "2018";
+        sha256 = "1m39qd65jcd1xgqzdm3017ppimiggh2446xngwp1ngr8hjbmpi7p";
+        procMacro = true;
+        build = "build/build.rs";
+        authors = [
+          "David Tolnay <dtolnay@gmail.com>"
+        ];
+
+      };
       "syn" = rec {
         crateName = "syn";
         version = "2.0.66";
@@ -241,9 +252,9 @@ rec {
       };
       "wasm-bindgen" = rec {
         crateName = "wasm-bindgen";
-        version = "0.2.95";
+        version = "0.2.100";
         edition = "2021";
-        sha256 = "0bpbvmxhil380gpv53smaypl8wc7sy7rq8apxfw349pn78v1x38j";
+        sha256 = "1x8ymcm6yi3i1rwj78myl1agqv2m86i648myy3lc97s9swlqkp0y";
         libName = "wasm_bindgen";
         authors = [
           "The wasm-bindgen Developers"
@@ -256,29 +267,42 @@ rec {
           {
             name = "once_cell";
             packageId = "once_cell";
+            usesDefaultFeatures = false;
+          }
+          {
+            name = "rustversion";
+            packageId = "rustversion";
+            optional = true;
           }
           {
             name = "wasm-bindgen-macro";
             packageId = "wasm-bindgen-macro";
           }
         ];
+        devDependencies = [
+          {
+            name = "once_cell";
+            packageId = "once_cell";
+          }
+        ];
         features = {
-          "default" = [ "spans" "std" ];
+          "default" = [ "std" "msrv" ];
           "enable-interning" = [ "std" ];
+          "msrv" = [ "rustversion" ];
+          "rustversion" = [ "dep:rustversion" ];
           "serde" = [ "dep:serde" ];
           "serde-serialize" = [ "serde" "serde_json" "std" ];
           "serde_json" = [ "dep:serde_json" ];
-          "spans" = [ "wasm-bindgen-macro/spans" ];
           "strict-macro" = [ "wasm-bindgen-macro/strict-macro" ];
           "xxx_debug_only_print_generated_code" = [ "wasm-bindgen-macro/xxx_debug_only_print_generated_code" ];
         };
-        resolvedDefaultFeatures = [ "default" "spans" "std" ];
+        resolvedDefaultFeatures = [ "default" "msrv" "rustversion" "std" ];
       };
       "wasm-bindgen-backend" = rec {
         crateName = "wasm-bindgen-backend";
-        version = "0.2.95";
+        version = "0.2.100";
         edition = "2021";
-        sha256 = "0n53wgy78bgzgjwk0z69zbspzhv8p2a4zh69s4fzvpqdrb9x8vfb";
+        sha256 = "1ihbf1hq3y81c4md9lyh6lcwbx6a5j0fw4fygd423g62lm8hc2ig";
         libName = "wasm_bindgen_backend";
         authors = [
           "The wasm-bindgen Developers"
@@ -293,10 +317,6 @@ rec {
             packageId = "log";
           }
           {
-            name = "once_cell";
-            packageId = "once_cell";
-          }
-          {
             name = "proc-macro2";
             packageId = "proc-macro2";
           }
@@ -317,13 +337,12 @@ rec {
         features = {
           "extra-traits" = [ "syn/extra-traits" ];
         };
-        resolvedDefaultFeatures = [ "spans" ];
       };
       "wasm-bindgen-macro" = rec {
         crateName = "wasm-bindgen-macro";
-        version = "0.2.95";
+        version = "0.2.100";
         edition = "2021";
-        sha256 = "0mic8b2vab1a91m6x3hjxkwz23094bq1cwhnszarsnlggyz894z7";
+        sha256 = "01xls2dvzh38yj17jgrbiib1d3nyad7k2yw9s0mpklwys333zrkz";
         procMacro = true;
         libName = "wasm_bindgen_macro";
         authors = [
@@ -340,16 +359,14 @@ rec {
           }
         ];
         features = {
-          "spans" = [ "wasm-bindgen-macro-support/spans" ];
           "strict-macro" = [ "wasm-bindgen-macro-support/strict-macro" ];
         };
-        resolvedDefaultFeatures = [ "spans" ];
       };
       "wasm-bindgen-macro-support" = rec {
         crateName = "wasm-bindgen-macro-support";
-        version = "0.2.95";
+        version = "0.2.100";
         edition = "2021";
-        sha256 = "0s7g6glb85lyx2pj83shbmg4d50mvqhb2c2qk2j28yigaxbspii6";
+        sha256 = "1plm8dh20jg2id0320pbmrlsv6cazfv6b6907z19ys4z1jj7xs4a";
         libName = "wasm_bindgen_macro_support";
         authors = [
           "The wasm-bindgen Developers"
@@ -379,20 +396,24 @@ rec {
         ];
         features = {
           "extra-traits" = [ "syn/extra-traits" ];
-          "spans" = [ "wasm-bindgen-backend/spans" ];
         };
-        resolvedDefaultFeatures = [ "spans" ];
       };
       "wasm-bindgen-shared" = rec {
         crateName = "wasm-bindgen-shared";
-        version = "0.2.95";
+        version = "0.2.100";
         edition = "2021";
         links = "wasm_bindgen";
-        sha256 = "1386q7mvv5ky003hcc6yyxpid3y1m7fy0l920i3z3ab60vqhkz35";
+        sha256 = "0gffxvqgbh9r9xl36gprkfnh3w9gl8wgia6xrin7v11sjcxxf18s";
         libName = "wasm_bindgen_shared";
         authors = [
           "The wasm-bindgen Developers"
         ];
+        dependencies = [
+          {
+            name = "unicode-ident";
+            packageId = "unicode-ident";
+          }
+        ];
 
       };
       "wasm_hello_world" = rec {
diff --git a/users/kranzes/wasm-hello-world/Cargo.toml b/users/kranzes/wasm-hello-world/Cargo.toml
index 9bb41268dcfb..2ad369d20d7c 100644
--- a/users/kranzes/wasm-hello-world/Cargo.toml
+++ b/users/kranzes/wasm-hello-world/Cargo.toml
@@ -7,4 +7,4 @@ edition = "2021"
 crate-type = ["cdylib"]
 
 [dependencies]
-wasm-bindgen = "0.2.95"
+wasm-bindgen = "0.2.100"
diff --git a/users/sterni/acme/README.md b/users/sterni/acme/README.md
new file mode 100644
index 000000000000..c3ccb1ea0425
--- /dev/null
+++ b/users/sterni/acme/README.md
@@ -0,0 +1,14 @@
+# //users/sterni/acme
+
+Utilities and configurations related to the [acme][] text editor
+from [Plan 9][].
+
+## mkbqnkeyboard.bqn
+
+Script to generate Plan 9 `/lib/keyboard` entries providing compose
+sequences for the Unicode characters used by [BQN][]. For usage
+instructions, refer to [its own documentation](./mkbqnkeyboard.md).
+
+[acme]: https://9p.io/sys/doc/acme/acme.pdf
+[Plan 9]: https://p9f.org/about.html
+[BQN]: https://mlochbaum.github.io/BQN/
diff --git a/users/sterni/acme/mkbqnkeyboard.bqn b/users/sterni/acme/mkbqnkeyboard.bqn
index e255ca27c4e8..8adc4a388457 100755
--- a/users/sterni/acme/mkbqnkeyboard.bqn
+++ b/users/sterni/acme/mkbqnkeyboard.bqn
@@ -17,8 +17,7 @@ IsAscii ← 127⊸≥-⟜@
 # Parse CLI
 opts ← {
  flags‿args ← 2↑'-' ((≠⟜⊑)¨⊔⊢) 𝕩
- # TODO(sterni): support multiple flags in one argument, e.g. -si
- ⟨sort,help,inPlace⟩ ⇐ flags∊˜⟨"-s","-h","-i"⟩
+ ⟨sort,help,inPlace⟩ ⇐ "shi"∊∾1⊸↓¨flags
 
  argCount ← 2
  {𝕤
diff --git a/users/sterni/acme/mkbqnkeyboard.md b/users/sterni/acme/mkbqnkeyboard.md
new file mode 100644
index 000000000000..744004aab26f
--- /dev/null
+++ b/users/sterni/acme/mkbqnkeyboard.md
@@ -0,0 +1,60 @@
+# mkbqnkeyboard.bqn
+
+[mkbqnkeyboard.bqn][] is a script that updates a given Plan 9 `/lib/keyboard`
+file to support the familiar [BQN keymap][] via compose sequences. Since
+it uses the GNU Readline [inputrc distributed with BQN][inputrc] as a database
+for the keymap, you can use a [remapped][] version of the layout.
+Once applied, you'll be able to type the Unicode characters used by BQN
+via <kbd>Compose</kbd> followed by <kbd>\\</kbd> and the
+<kbd>mapped ASCII character</kbd>. For details on the file and what button
+is used for <kbd>Compose</kbd>, refer to
+[keyboard(6)][p9f-keyboard] (see also
+[plan9port's keyboard(7)][p9p-keyboard], [9front's keyboard(6)][9front-keyboard] etc.).
+
+TIP: [mkbqnkeyboard.bqn][] has only been tested with [plan9port][],
+so the instructions below may not work with every Plan 9 variant.
+If you have any any information on/trouble with getting it to work on
+a proper Plan 9 (fork), feel free to [let me know][me] or
+[send a patch][submitting-patches].
+
+The process for updating `/lib/keyboard` with [mkbqnkeyboard.bqn][] is a follows:
+
+1. Prerequisites:
+
+   - [CBQN][] (other BQN implementations are untested)
+   - A local checkout of [mlochbaum/BQN][],
+     `aecb56a323aa` is the latest tested revision.
+
+2. Run
+
+       ./mkbqnkeyboard.bqn -i /path/to/mlochbaum/BQN/editors/inputrc /path/to/lib/keyboard
+
+   If you omit `-i`, the modified `keyboard` file will be printed to stdout instead
+   of written to the file. If you add `-s`, the result will be sorted by (resulting) codepoint.
+
+3. If you're using **plan9port**, you'll need to
+
+   1. Apply [latin1-increase-compose-capacity.patch][] since the default compose
+      sequence lookup table is too small to hold all the mappings BQN adds.
+   2. Recompile plan9port.
+
+   Other Plan 9 variants may also require extra steps.
+
+4. The compose sequences should now work in the [acme][] and [sam][] text editors
+   as well as all other Plan 9 programs.
+
+[acme]: https://9p.io/sys/doc/acme/acme.pdf
+[sam]: https://9p.io/sys/doc/sam/sam.pdf
+[BQN keymap]: https://mlochbaum.github.io/BQN/keymap.html
+[me]: https://grep.tvl.fyi/search/?q=%20path%3Aops%2Fusers%2Fdefault.nix%20name%20%3D%20%22sterni%22%3B&fold_case=auto&regex=false&context=true
+[mkbqnkeyboard.bqn]: ./mkbqnkeyboard.bqn
+[inputrc]: https://github.com/mlochbaum/BQN/blob/master/editors/inputrc
+[remapped]: https://mlochbaum.github.io/BQN/editors/index.html#alternate-layouts
+[p9f-keyboard]: https://p9f.org/magic/man2html/6/keyboard
+[p9p-keyboard]: https://9fans.github.io/plan9port/man/man7/keyboard.html
+[9front-keyboard]: http://man.9front.org/6/keyboard
+[plan9port]: https://9fans.github.io/plan9port/
+[submitting-patches]: https://code.tvl.fyi/about/docs/REVIEWS.md
+[mlochbaum/BQN]: https://github.com/mlochbaum/BQN
+[CBQN]: https://github.com/dzaima/cbqn
+[latin1-increase-compose-capacity.patch]: ./plan9port/latin1-increase-compose-capacity.patch
diff --git a/users/sterni/acme/plan9port/default.nix b/users/sterni/acme/plan9port/default.nix
index a57b0e60b98e..2a26e7003570 100644
--- a/users/sterni/acme/plan9port/default.nix
+++ b/users/sterni/acme/plan9port/default.nix
@@ -9,7 +9,7 @@ let
         (builtins.readDir dir));
 
   mkbqnkeyboard' = pkgs.writeShellScript "mkbqnkeyboard'" ''
-    exec ${pkgs.cbqn}/bin/BQN ${../mkbqnkeyboard.bqn} -s -i \
+    exec ${pkgs.cbqn}/bin/BQN ${../mkbqnkeyboard.bqn} -si \
       "${pkgs.srcOnly pkgs.mbqn}/editors/inputrc" "$1"
   '';
 
@@ -52,6 +52,11 @@ pkgs.plan9port.overrideAttrs (old: {
         '';
   };
 
+  postInstall = ''
+    echo '48.3626 10.9026 483\
+    (OpenLab Augsburg)' > $out/plan9/sky/here
+  '';
+
   doInstallCheck = true;
   installCheckPhase = old.installCheckPhase or "" + ''
     export NAMESPACE="$(mktemp -d)"
diff --git a/users/sterni/acme/plan9port/devdraw-ignore-primary-selection.patch b/users/sterni/acme/plan9port/devdraw-ignore-primary-selection.patch
new file mode 100644
index 000000000000..d50a3af3b88c
--- /dev/null
+++ b/users/sterni/acme/plan9port/devdraw-ignore-primary-selection.patch
@@ -0,0 +1,83 @@
+From b46a68c7327bf1df62d6f836cd5aa53c5b2b96b3 Mon Sep 17 00:00:00 2001
+From: sternenseemann <sternenseemann@systemli.org>
+Date: Sat, 1 Feb 2025 19:33:30 +0100
+Subject: [PATCH] src/cmd/devdraw: ignore primary selection
+
+By default devdraw updates the primary selection when Snarfing (which is
+a little questionable as it's supposed to hold the current selection)
+and prefers the primary selection when Pasting. I use xwayland-satellite
+which does not support syncing the primary selection between wayland and
+X11 which prevents Pasting in plan9port altogether as soon as you've
+Snarfed once (as long as the primary selection is empty, everything
+works as expected, but Snarfing populates the primary selection neither
+devdraw nor xwayland-satellite will ever clear the primary selection).
+
+This issue in xwayland-satellite is tracked at
+<https://github.com/Supreeeme/xwayland-satellite/issues/103>.
+
+In the meantime, I'm working around this issue by just ignoring the
+primary selection altogether. I suspect the preference for the primary
+selection in devdraw is wrong anyways. The Snarf/Paste operations fit
+how the X11 clipboard is supposed to work and is different to the
+primary selection.
+---
+ src/cmd/devdraw/x11-screen.c | 24 +++++++-----------------
+ 1 file changed, 7 insertions(+), 17 deletions(-)
+
+diff --git a/src/cmd/devdraw/x11-screen.c b/src/cmd/devdraw/x11-screen.c
+index 6b02dd7a..201ff044 100644
+--- a/src/cmd/devdraw/x11-screen.c
++++ b/src/cmd/devdraw/x11-screen.c
+@@ -1287,7 +1287,6 @@ _xtoplan9mouse(Xwin *w, XEvent *e, Mouse *m)
+ 
+ 	if(_x.putsnarf != _x.assertsnarf){
+ 		_x.assertsnarf = _x.putsnarf;
+-		XSetSelectionOwner(_x.display, XA_PRIMARY, w->drawable, CurrentTime);
+ 		if(_x.clipboard != None)
+ 			XSetSelectionOwner(_x.display, _x.clipboard, w->drawable, CurrentTime);
+ 		XFlush(_x.display);
+@@ -1527,7 +1526,7 @@ rpc_getsnarf(void)
+ {
+ 	uchar *data;
+ 	Atom clipboard;
+-	XWindow xw;
++	XWindow xw = None;
+ 	Xwin *w;
+ 
+ 	qlock(&clip.lk);
+@@ -1539,26 +1538,17 @@ rpc_getsnarf(void)
+ 	if(_x.putsnarf != _x.assertsnarf)
+ 		goto mine;
+ 
+-	/*
+-	 * Is there a primary selection (highlighted text in an xterm)?
+-	 */
+-	clipboard = XA_PRIMARY;
+-	xw = XGetSelectionOwner(_x.display, XA_PRIMARY);
+-	// TODO check more
+-	if(xw == w->drawable){
+-	mine:
+-		data = (uchar*)strdup(clip.buf);
+-		goto out;
+-	}
+-
+ 	/*
+ 	 * If not, is there a clipboard selection?
+ 	 */
+-	if(xw == None && _x.clipboard != None){
++	if(_x.clipboard != None){
+ 		clipboard = _x.clipboard;
+ 		xw = XGetSelectionOwner(_x.display, _x.clipboard);
+-		if(xw == w->drawable)
+-			goto mine;
++		if(xw == w->drawable) {
++		mine:
++			data = (uchar*)strdup(clip.buf);
++			goto out;
++		}
+ 	}
+ 
+ 	/*
+-- 
+2.47.0
+
diff --git a/users/sterni/blipqn/blipqn.bqn b/users/sterni/blipqn/blipqn.bqn
index a18f68b2e4da..f78332fbd26a 100644
--- a/users/sterni/blipqn/blipqn.bqn
+++ b/users/sterni/blipqn/blipqn.bqn
@@ -34,8 +34,9 @@ MakeFlipdot ← {
 # assertion failure with the error message after executing 𝔾. This looses
 # the original error location, though.
 _defer_ ← {
-  # At least in CBQN, •CurrentError may fail for namespace related reasons
-  s‿r ← (1⊸⋈∘𝔾)⎊(0⊸⋈∘(•CurrentError⎊("_defer_: Unknown Error occurred"˙))) 𝕩 ⋄ 𝔽 𝕩 ⋄ r⊣r!s;
+  # can't use •CurrentError if 𝕩 is namespace: https://github.com/dzaima/cbqn/commit/d6609df82
+  # to avoid this problem, always wrap 𝕩 in a list and unwrap it before calling 𝔾
+  s‿r ← (1⊸⋈∘𝔾∘⊑)⎊(0⊸⋈∘•CurrentError) ⋈𝕩 ⋄ 𝔽 𝕩 ⋄ r⊣r!s;
   (𝕨⊸𝔽) _𝕣_ (𝕨⊸𝔾) 𝕩
 }
 
diff --git a/users/sterni/blërg/README.md b/users/sterni/blërg/README.md
new file mode 100644
index 000000000000..552543c7107d
--- /dev/null
+++ b/users/sterni/blërg/README.md
@@ -0,0 +1,25 @@
+# blërg
+
+## dependencies
+
+- [CBQN][] (other [BQN][] implementations may work, but are untested)
+- Marshall Lochbaum's [bqn-libs][] which blërg expects to find at the
+  location the `BQN_LIBS` environment variable points to.
+- [execline][]
+- POSIX `printf(1)` (e.g. from GNU coreutils)
+- `mail-notes` backend
+  - //users/sterni/mn2html
+  - [mblaze(7)][mblaze]
+- `git` backend
+  - [git][]
+  - [lowdown][] for Markdown support
+  - [pandoc][] for Org Mode support
+
+[mblaze]: https://github.com/leahneukirchen/mblaze/
+[execline]: https://skarnet.org/software/execline/
+[BQN]: https://mlochbaum.github.io/BQN/
+[CBQN]: https://github.com/dzaima/cbqn
+[bqn-libs]: https://github.com/mlochbaum/bqn-libs/
+[lowdown]: https://kristaps.bsd.lv/lowdown/
+[pandoc]: https://pandoc.org/
+[git]: https://git-scm.com/
diff --git a/users/sterni/blërg/blërg.bqn b/users/sterni/blërg/blërg.bqn
new file mode 100755
index 000000000000..c111690e406e
--- /dev/null
+++ b/users/sterni/blërg/blërg.bqn
@@ -0,0 +1,170 @@
+#!/usr/bin/env BQN
+# SPDX-FileCopyrightText: Copyright © 2024-2025 sterni
+# SPDX-License-Identifier: GPL-3.0-only
+#
+# blërg is a reimplementation of mblog in BQN. BQN is used as a sort of bespoke
+# scripting languages so we can rely on external tools for certain tasks (e.g.
+# transforming HTML and parsing MIME messages). A list of dependencies is
+# maintained in README.md.
+
+# Utilities
+
+MkDirP ← •file.CreateDir⍟(¬•file.Exists)
+
+AsciiDown ← ⊢ - ('A'-'a')⊸×⟜('A'⊸≤∧≤⟜'Z')
+Slugify ← '-'⊸⊣⍟(('A'⊸≤ ∧ ≤⟜'z') ¬∘∨ "-_0123456789"⊸(⊑∊˜)⟜<)¨ AsciiDown
+
+DropPrefix ← {𝕩(≠/⊣)𝕨↑˜≠𝕩}
+StripLeft ← (¬ ∧`∘=)/⊢
+StripRight ← ⌽ StripLeft⟜⌽
+
+_join ← {(∾⟜(𝕗⊸∾))´𝕩;𝕨∾𝕗∾𝕩}
+
+nl ← @+10
+SplitChar ← (= (¯1˙⍟⊣)¨ +`∘=)⊔⊢
+Lines ← nl⊸SplitChar
+
+ReadPosInt ← {(𝕨⊸×+⊣)´ ⌽'0'-˜𝕩} # ty leah2
+ReadPosDec ← 10⊸ReadPosInt
+
+Chomp ← {⟨nl⟩≡¯1↑𝕩? ¯1↓𝕩; 𝕩}
+
+Run ← {
+  𝕊 𝕩: 1 𝕊 𝕩;
+  doChomp 𝕊 cmd:
+  exit‿stdout‿stderr ← •SH cmd
+  exit∾Chomp⍟doChomp¨ stdout‿stderr
+}
+
+R ← {𝕊 exit‿stdout‿stderr: stderr!0=exit ⋄ stdout}∘Run
+LR ← Lines∘R
+
+GetEnv ← {R "importas"‿"env"‿𝕩‿"printf"‿"%s"‿"$env"}
+
+RelPath ← •wdpath⊸•file.At
+SplitExt ← (∊⌾⌽ (∨`∘∧ + ¯2⊸×∘∧) =⟜'.')⊔⊢
+
+# 3p dependencies
+
+j ← {
+  # Update README.md if dependency discovery changes
+  ⟨Parse⟩ ⇐ •Import (GetEnv "BQN_LIBS") •file.At "json.bqn"
+
+  ObjGet ⇐ (⊏⊸(⊑∘⊐) ⊑ ⊏˜⟜1)⟜<
+  ObjGetPath ⇐ ObjGet˜´⟜⌽
+
+  _objGetDef ⇐ {𝕨 (⊏⊸(⊑∘⊐) ⊑ (∾⟜(⋈𝕗))∘(⊏˜⟜1)) <𝕩}
+}
+
+# (Apple) Mail Notes Backend
+
+# TODO(sterni): avoid argv limit by chunking
+Hdrs ← {LR "mhdr"‿"-dh"‿(':' _join 𝕨)∾𝕩}
+Dates ← {ReadPosDec¨ LR "mhdr"‿"-Dh"‿"Date"∾𝕩}
+headerNames ← "X-Uniform-Type-Identifier"‿"X-Universally-Unique-Identifier"‿"Subject"
+
+MailNotesBackend ← {𝕊 config:
+  mailDir ← RelPath config j.ObjGet "maildir"
+  Entries ⇐ {𝕊:
+    ms ← LR "mlist"‿mailDir
+    th ← ⟨≠ms,≠headerNames⟩⥊headerNames Hdrs ms
+    dh ← Dates ms
+    ah ← (("com.apple.mail-note"⊸≡⊑)˘/⊢) th∾˘dh≍˘ms
+    {𝕊 ·‿uuid‿title‿time‿path:
+      title ⇐ ⋄ time ⇐
+      id ⇐ Slugify uuid
+      Render ⇐ {R "execline-cd"‿𝕩‿"mshow"‿"-x"‿path ⋄ R "mn2html"‿path}
+    }˘ ah
+  }
+}
+
+# Git Backend
+
+converters ← ⍉>⟨
+  # TODO(sterni): avoid cat
+  ⟨"html", ⋈"cat"⟩,
+  ⟨"md", "lowdown"‿"-T"‿"html"‿"--html-no-skiphtml"‿"--html-no-escapehtml"‿"--html-callout-mdn"⟩,
+  # TODO(sterni): use emacs
+  ⟨"org", "pandoc"‿"-f"‿"org"‿"-t"‿"html5"⟩,
+⟩
+
+# TODO(sterni): don't assemble blocks in this ad hoc fashion
+# TODO(sterni): pipefail
+PipelineCmd ← {⟨"pipeline"⟩∾(' '⊸∾¨𝕨)∾⟨""⟩∾𝕩}
+
+GitBackend ← {𝕊 config:
+  repo ← RelPath config j.ObjGet "repository"
+  path ← ∾⟜'/' '/' StripRight config "." j._ObjGetDef "path"
+
+  # We use zero separated fields when dealing with paths, so quoting is unnecessary
+  GitCmd ← {"git"‿"-c"‿"core.quotePath=false"‿"-C"‿repo∾𝕩}
+  rev ← R GitCmd "rev-parse"‿"HEAD"
+  # Use the author date of the latest commit on the file to establish the date
+  # of the file. The author date is easier to arbitrarily change and survives
+  # history rewrites. It could be interesting to ignore commits that touch
+  # multiple files (especially treewide ones).
+  PathDate ← {ReadPosDec R GitCmd "log"‿"--date=unix"‿"--pretty=tformat:%ad"‿"-1"‿rev‿"--"‿𝕩}
+
+  Entries ⇐ {𝕤⋄
+    blobs ← ∘‿2⥊@ SplitChar R GitCmd "ls-tree"‿"-zr"‿"--format=%(path)%x00%(objectname)"‿rev‿path
+    {𝕊 p‿b:
+      extlessp‿ext ← SplitExt p
+      id ⇐ Slugify path DropPrefix extlessp
+      # TODO(sterni): extract from file if possible
+      title ⇐ •file.Name extlessp
+      time ⇐ PathDate p
+      Render ⇐ {𝕤
+        conv ← converters j.ObjGet ext
+        R (GitCmd "cat-file"‿"blob"‿b) PipelineCmd conv
+      }
+    }˘blobs
+  }
+}
+
+backends ← ⍉>⟨"mail-notes"‿mailNotesBackend, "git"‿gitBackend⟩
+
+# Rendering
+
+RenderPage ← {
+∾"<!doctype html>
+<html lang=""en"">
+<head>
+<meta charset=""utf-8"">
+<title>"‿𝕨‿"</title>
+<body>
+<h1>"‿𝕨‿"</h1>"‿𝕩
+}
+
+WriteEntry ← {outDir 𝕊 entry:
+  entryDir ← MkDirP outDir •file.At entry.id
+  (entryDir •file.At "index.html") •file.Chars entry.title RenderPage entry.Render entryDir
+  # TODO(sterni): urlencode
+  "<li><a href="""∾entry.id∾""">"∾entry.title∾"</a></li>"
+}
+
+# Main
+
+configFile‿outDir ← {
+  # Usage: blërg <config file> <out dir>
+  ! 2=≠•args
+  # TODO(sterni): expand ~/
+  RelPath¨ •args
+}
+
+config ← {
+  raw ← j.Parse •FChars configFile
+
+  [bns,bcs] ← raw j.ObjGet "backends"
+  bcs ↩ bcs ∾˘⟜{2‿1⥊"name"‿𝕩}¨ bns
+  bts ← j.ObjGet⟜"type"¨ bcs
+  backends ⇐ bcs {𝕏 𝕨}¨ backends⊸j.ObjGet¨ bts
+
+  title ⇐ raw j.ObjGet "title"
+}
+
+entries ← ((⍒ •ns.Get⟜"time"¨)⊏⊢) ∾{𝕩.Entries @}¨ config.backends
+"All entry IDs must be unique"!(≠=≠∘⍷) •ns.Get⟜"id"¨ entries
+
+MkDirP outDir
+entryIndex ← outDir⊸WriteEntry¨ entries
+(outDir •file.At "index.html") •file.Chars config.title RenderPage ∾"<ul>"∾entryIndex∾"</ul>"
diff --git a/users/sterni/blërg/default.nix b/users/sterni/blërg/default.nix
new file mode 100644
index 000000000000..0dacf5e15428
--- /dev/null
+++ b/users/sterni/blërg/default.nix
@@ -0,0 +1,42 @@
+{ depot, pkgs, lib, ... }:
+
+let
+  # update README.md when changing this
+  runtimeDependencies = [
+    depot.users.sterni.mn2html
+    pkgs.mblaze
+    pkgs.execline # execline-cd, importas, pipeline
+    # coreutils   # for printf (assumed to be installed)
+    pkgs.pandoc
+    pkgs.lowdown
+  ];
+
+  # … and this
+  buildInputs = [
+    pkgs.cbqn
+  ];
+
+  BQN_LIBS = depot.third_party.bqn-libs + "/lib";
+in
+
+pkgs.runCommandNoCC "blerg"
+{
+  src = builtins.path {
+    name = "blerg.bqn";
+    path = ./. + "/blërg.bqn";
+  };
+  nativeBuildInputs = [ pkgs.buildPackages.makeWrapper ];
+  inherit buildInputs;
+  passthru.shell = pkgs.mkShell {
+    name = "blërg-shell";
+    packages = runtimeDependencies ++ buildInputs;
+    inherit BQN_LIBS;
+  };
+}
+  ''
+    install -Dm755 "$src" "$out/bin/blërg"
+    patchShebangs "$out/bin/blërg"
+    wrapProgram "$out/bin/blërg" \
+      --prefix PATH : "${lib.makeBinPath runtimeDependencies}" \
+      --set BQN_LIBS "${BQN_LIBS}"
+  ''
diff --git a/users/sterni/emacs/subscriptions.el b/users/sterni/emacs/subscriptions.el
index ba63da3063fd..12199e68308c 100644
--- a/users/sterni/emacs/subscriptions.el
+++ b/users/sterni/emacs/subscriptions.el
@@ -14,31 +14,27 @@
   (setq elfeed-feeds
         (append
          ;; immutable subscriptions tracked in git
-         '(("https://repology.org/maintainer/sternenseemann%40systemli.org/feed-for-repo/nix_unstable/atom" dashboard releases)
-           ("https://www.stackage.org/feed" dashboard releases)
-           ("http://hundimbuero.blogspot.com/feeds/posts/default?alt=rss" blog cool-and-nice)
+         '(("https://repology.org/maintainer/sternenseemann%40systemli.org/feed-for-repo/nix_unstable/atom" releases)
+           ("https://www.stackage.org/feed" releases)
            ("https://text.causal.agency/feed.atom" blog)
-           ("http://xsteadfastx.org/feed/" blog cool-and-nice)
-           ("https://tvl.fyi/feed.atom" blog cool-and-nice)
+           ("http://xsteadfastx.org/feed/" blog)
+           ("https://tvl.fyi/feed.atom" blog)
            ("https://hannes.robur.coop/atom" blog)
            ("https://stevelosh.com/rss.xml" blog)
            ("https://blog.benjojo.co.uk/rss.xml" blog)
-           ("https://leahneukirchen.org/blog/index.atom" blog cool-and-nice)
-           ("https://leahneukirchen.org/trivium/index.atom" blog links cool-and-nice)
-           ("https://firefly.nu/feeds/all.atom.xml" blog cool-and-nice)
-           ("https://tazj.in/feed.atom" blog cool-and-nice)
-           ("https://alyssa.is/feed.xml" blog cool-and-nice)
-           ("https://eta.st/feed.xml" blog cool-and-nice)
+           ("https://leahneukirchen.org/blog/index.atom" blog)
+           ("https://leahneukirchen.org/trivium/index.atom" blog links)
+           ("https://firefly.nu/feeds/all.atom.xml" blog)
+           ("https://tazj.in/feed.atom" blog)
+           ("https://alyssa.is/feed.xml" blog)
+           ("https://eta.st/feed.xml" blog)
            ("https://spectrum-os.org/git/www/atom/bibliography.html" links blog)
            ("https://vulns.xyz/feed.xml" blog)
            ("https://www.german-foreign-policy.com/?type=9818" news)
-           ("https://niedzejkob.p4.team/rss.xml" blog)
-           ("https://grahamc.com/feed/" blog)
+           ("https://compilercrim.es/rss.xml" blog)
            ("http://blog.nullspace.io/feed.xml" blog)
            ("https://blog.kingcons.io/rss.xml" blog)
            ("https://www.imperialviolet.org/iv-rss.xml" blog)
-           ("https://22gato.tumblr.com/rss" pictures cool-and-nice)
-           ("https://theprofoundprogrammer.com/rss" blog)
            ("http://shitopenlabsays.tumblr.com/rss" openlab)
            ("https://kristaps.bsd.lv/lowdown/atom.xml" releases)
            ("http://0pointer.net/blog/index.atom" blog)
@@ -52,9 +48,8 @@
            ("http://guteaussicht.org/rss" pictures)
            ("http://konvergenzfehler.de/feed/" blog)
            ("https://markuscisler.com/feed.xml" blog)
-           ("http://www.plomlompom.de/PlomRogue/plomwiki.php?action=Blog_Atom" blog)
            ("http://www.whvrt.de/rss" pictures)
-           ("https://echtsuppe.wordpress.com/feed/" blog defunct)
+           ("https://barnslig.eu/feed/" blog)
            ("https://mgsloan.com/feed.xml" blog)
            ("http://beza1e1.tuxen.de/blog_en.atom" blog)
            ("https://anchor.fm/s/94bb000/podcast/rss" podcast))
diff --git a/users/sterni/exercises/aoc/lib.bqn b/users/sterni/exercises/aoc/lib.bqn
index 5c02358b5980..ad3fdd7e51da 100644
--- a/users/sterni/exercises/aoc/lib.bqn
+++ b/users/sterni/exercises/aoc/lib.bqn
@@ -19,3 +19,5 @@ Xor ⇐ (¬⊸∧∨∧⟜¬)
 
 # To get all Diagonals (⊢∾○Diagonals⌽)
 Diagonals ⇐ {(0‿0⊸⍉ ↓⟜𝕩)¨ (↕≠𝕩)}
+
+ApplyMany ← {fs 𝕊 arg: {𝕏 arg}¨ fs}
diff --git a/users/sterni/mn2html/.gitignore b/users/sterni/mn2html/.gitignore
new file mode 100644
index 000000000000..eb5a316cbd19
--- /dev/null
+++ b/users/sterni/mn2html/.gitignore
@@ -0,0 +1 @@
+target
diff --git a/users/sterni/mn2html/Cargo.lock b/users/sterni/mn2html/Cargo.lock
new file mode 100644
index 000000000000..19de2c57e69d
--- /dev/null
+++ b/users/sterni/mn2html/Cargo.lock
@@ -0,0 +1,534 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "allocator-api2"
+version = "0.2.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
+
+[[package]]
+name = "amn2html"
+version = "0.1.0"
+dependencies = [
+ "lol_html",
+ "mail-parser",
+ "memmap2",
+]
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "bitflags"
+version = "2.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
+
+[[package]]
+name = "byteorder"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "convert_case"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
+
+[[package]]
+name = "cssparser"
+version = "0.27.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "754b69d351cdc2d8ee09ae203db831e005560fc6030da058f86ad60c92a9cb0a"
+dependencies = [
+ "cssparser-macros",
+ "dtoa-short",
+ "itoa",
+ "matches",
+ "phf",
+ "proc-macro2",
+ "quote",
+ "smallvec",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "cssparser-macros"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331"
+dependencies = [
+ "quote",
+ "syn 2.0.90",
+]
+
+[[package]]
+name = "derive_more"
+version = "0.99.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce"
+dependencies = [
+ "convert_case",
+ "proc-macro2",
+ "quote",
+ "rustc_version",
+ "syn 2.0.90",
+]
+
+[[package]]
+name = "dtoa"
+version = "1.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653"
+
+[[package]]
+name = "dtoa-short"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87"
+dependencies = [
+ "dtoa",
+]
+
+[[package]]
+name = "encoding_rs"
+version = "0.8.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "equivalent"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
+
+[[package]]
+name = "foldhash"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2"
+
+[[package]]
+name = "fxhash"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
+dependencies = [
+ "byteorder",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.1.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.15.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
+dependencies = [
+ "allocator-api2",
+ "equivalent",
+ "foldhash",
+]
+
+[[package]]
+name = "itoa"
+version = "0.4.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
+
+[[package]]
+name = "lazy_static"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
+
+[[package]]
+name = "lazycell"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
+
+[[package]]
+name = "libc"
+version = "0.2.168"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d"
+
+[[package]]
+name = "log"
+version = "0.4.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
+
+[[package]]
+name = "lol_html"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2872b88213f3cd4b04f719ec8f2e0b37c98882a7c4aa6fc13ba2f19f5eba1bd2"
+dependencies = [
+ "bitflags 2.6.0",
+ "cfg-if",
+ "cssparser",
+ "encoding_rs",
+ "hashbrown",
+ "lazy_static",
+ "lazycell",
+ "memchr",
+ "mime",
+ "selectors",
+ "thiserror",
+]
+
+[[package]]
+name = "mail-parser"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93c3b9e5d8b17faf573330bbc43b37d6e918c0a3bf8a88e7d0a220ebc84af9fc"
+dependencies = [
+ "encoding_rs",
+]
+
+[[package]]
+name = "matches"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5"
+
+[[package]]
+name = "memchr"
+version = "2.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
+
+[[package]]
+name = "memmap2"
+version = "0.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "mime"
+version = "0.3.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
+
+[[package]]
+name = "nodrop"
+version = "0.1.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
+
+[[package]]
+name = "phf"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12"
+dependencies = [
+ "phf_macros",
+ "phf_shared",
+ "proc-macro-hack",
+]
+
+[[package]]
+name = "phf_codegen"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815"
+dependencies = [
+ "phf_generator",
+ "phf_shared",
+]
+
+[[package]]
+name = "phf_generator"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526"
+dependencies = [
+ "phf_shared",
+ "rand",
+]
+
+[[package]]
+name = "phf_macros"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f6fde18ff429ffc8fe78e2bf7f8b7a5a5a6e2a8b58bc5a9ac69198bbda9189c"
+dependencies = [
+ "phf_generator",
+ "phf_shared",
+ "proc-macro-hack",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "phf_shared"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7"
+dependencies = [
+ "siphasher",
+]
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
+dependencies = [
+ "zerocopy",
+]
+
+[[package]]
+name = "precomputed-hash"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
+
+[[package]]
+name = "proc-macro-hack"
+version = "0.5.20+deprecated"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.92"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "rand"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
+dependencies = [
+ "getrandom",
+ "libc",
+ "rand_chacha",
+ "rand_core",
+ "rand_hc",
+ "rand_pcg",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
+dependencies = [
+ "ppv-lite86",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
+dependencies = [
+ "getrandom",
+]
+
+[[package]]
+name = "rand_hc"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
+dependencies = [
+ "rand_core",
+]
+
+[[package]]
+name = "rand_pcg"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429"
+dependencies = [
+ "rand_core",
+]
+
+[[package]]
+name = "rustc_version"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
+dependencies = [
+ "semver",
+]
+
+[[package]]
+name = "selectors"
+version = "0.22.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df320f1889ac4ba6bc0cdc9c9af7af4bd64bb927bccdf32d81140dc1f9be12fe"
+dependencies = [
+ "bitflags 1.3.2",
+ "cssparser",
+ "derive_more",
+ "fxhash",
+ "log",
+ "matches",
+ "phf",
+ "phf_codegen",
+ "precomputed-hash",
+ "servo_arc",
+ "smallvec",
+ "thin-slice",
+]
+
+[[package]]
+name = "semver"
+version = "1.0.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
+
+[[package]]
+name = "servo_arc"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d98238b800e0d1576d8b6e3de32827c2d74bee68bb97748dcf5071fb53965432"
+dependencies = [
+ "nodrop",
+ "stable_deref_trait",
+]
+
+[[package]]
+name = "siphasher"
+version = "0.3.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
+
+[[package]]
+name = "smallvec"
+version = "1.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
+
+[[package]]
+name = "stable_deref_trait"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
+
+[[package]]
+name = "syn"
+version = "1.0.109"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.90"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "thin-slice"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c"
+
+[[package]]
+name = "thiserror"
+version = "1.0.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.90",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
+
+[[package]]
+name = "wasi"
+version = "0.9.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
+
+[[package]]
+name = "zerocopy"
+version = "0.7.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
+dependencies = [
+ "byteorder",
+ "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 2.0.90",
+]
diff --git a/users/sterni/mn2html/Cargo.toml b/users/sterni/mn2html/Cargo.toml
new file mode 100644
index 000000000000..6c959db4a07d
--- /dev/null
+++ b/users/sterni/mn2html/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+name = "mn2html"
+version = "0.0.0"
+edition = "2021"
+license = "GPL-3.0-only"
+
+[dependencies]
+lol_html = "2.1.0"
+mail-parser = { version = "0.9.4", features = [ "encoding_rs" ] }
+memmap2 = "0.9.5"
+
+[[bin]]
+name = "mn2html"
+path = "mn2html.rs"
diff --git a/users/sterni/mn2html/README.md b/users/sterni/mn2html/README.md
new file mode 100644
index 000000000000..bec557f19ab4
--- /dev/null
+++ b/users/sterni/mn2html/README.md
@@ -0,0 +1,20 @@
+# mn2html
+
+Convert mail notes authored e.g. by the iOS/macOS Notes application,
+into HTML suitable for standard browsers. Instead of full documents,
+mn2html emits HTML fragments that can easily be embedded into other
+documents or postprocessed using a templating engine.
+
+## History
+
+mn2html is a reimplementation mnote-html from //users/sterni/mblog.
+The reason for this was mainly avoiding the startup cost associated
+with Common Lisp programs, so the program would be suitable for
+shell scripting.
+
+## Tasks
+
+- [ ] Properly handle `text/plain` bodies (from e.g. notemap)
+- [ ] Add man page
+- [ ] Help screen
+- [ ] Improve error reporting
diff --git a/users/sterni/mn2html/default.nix b/users/sterni/mn2html/default.nix
new file mode 100644
index 000000000000..d6f2c21a4c1f
--- /dev/null
+++ b/users/sterni/mn2html/default.nix
@@ -0,0 +1,25 @@
+{ pkgs, lib, ... }:
+
+pkgs.rustPlatform.buildRustPackage rec {
+  pname = "mn2hmtl";
+  version = "canon";
+
+  src = lib.fileset.toSource {
+    root = ./.;
+    fileset = lib.fileset.unions [
+      ./Cargo.lock
+      ./Cargo.toml
+      ./mn2html.rs
+    ];
+  };
+
+  cargoLock.lockFile = ./Cargo.lock;
+
+  passthru.shell = pkgs.mkShell {
+    name = "${pname}-shell";
+    nativeBuildInputs = [
+      pkgs.buildPackages.cargo
+      pkgs.buildPackages.rustc
+    ];
+  };
+}
diff --git a/users/sterni/mn2html/mn2html.rs b/users/sterni/mn2html/mn2html.rs
new file mode 100644
index 000000000000..cda8f2993321
--- /dev/null
+++ b/users/sterni/mn2html/mn2html.rs
@@ -0,0 +1,165 @@
+// SPDX-FileCopyrightText: Copyright © 2024 sterni
+// SPDX-License-Identifier: GPL-3.0-only
+use lol_html::html_content::ContentType;
+use lol_html::{element, HtmlRewriter, Settings};
+use mail_parser::{Message, MessageParser, MimeHeaders};
+use memmap2::Mmap;
+
+use std::collections::HashMap;
+use std::env;
+use std::error::Error;
+use std::fmt;
+use std::fs::File;
+use std::io::Write;
+
+type CidMap<'a> = HashMap<&'a str, &'a str>;
+
+#[derive(Debug)]
+enum Mn2htmlError {
+    MimeParseFail,
+    NoMailNote,
+    MissingAttachment(String),
+}
+
+impl fmt::Display for Mn2htmlError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Mn2htmlError::MimeParseFail => {
+                write!(f, "Could not parse given file as a MIME message")
+            }
+            Mn2htmlError::NoMailNote => {
+                write!(f, "Given MIME message does not appear to be a Mail Note")
+            }
+            Mn2htmlError::MissingAttachment(cid) => write!(
+                f,
+                "Given object's Content-Id {} doesn't match any attachment",
+                cid
+            ),
+        }
+    }
+}
+
+impl Error for Mn2htmlError {
+    fn source(&self) -> Option<&(dyn Error + 'static)> {
+        None
+    }
+}
+
+fn warn(msg: &str) {
+    eprintln!("mn2html: {}", msg);
+}
+
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+    for arg in env::args_os().skip(1) {
+        // TODO(sterni): flags, --help and such
+        let msg_file = File::open(arg)?;
+        let msg_raw = unsafe { Mmap::map(&msg_file) }?;
+
+        let msg_parsed = MessageParser::default()
+            .parse(msg_raw.as_ref())
+            .ok_or(Mn2htmlError::MimeParseFail)?;
+
+        if !matches!(
+            msg_parsed
+                .header("X-Uniform-Type-Identifier")
+                .and_then(|h| h.as_text()),
+            Some("com.apple.mail-note")
+        ) {
+            return Err(Box::new(Mn2htmlError::NoMailNote));
+        }
+
+        let cid_map = index_attachments(&msg_parsed);
+        let html_body = msg_parsed
+            .html_bodies()
+            .nth(0)
+            .ok_or(Mn2htmlError::NoMailNote)?
+            .contents();
+
+        rewrite_html(html_body, &cid_map)?;
+    }
+
+    Ok(())
+}
+
+// At some point, it was a consideration to move this out of the Rust program.
+// mn2html would have been a shell script with mblaze(7) tools finding the
+// attachments and their content ideas passing the information to a Rust HTML
+// rewriter via CLI args. It is unclear how much (if at all?) slower this would
+// have been. In the end, it just seemed cleaner to do it in the Rust program,
+// especially since the HTML rewriter would not really have been useful on its
+// own.
+fn index_attachments<'a>(msg: &'a Message) -> CidMap<'a> {
+    let mut map = HashMap::new();
+    for a in msg.attachments() {
+        match (a.content_id(), a.attachment_name()) {
+            (Some(cid), Some(filename)) => {
+                if let Some(_) = map.insert(cid, filename) {
+                    warn("multiple attachments share the same Content-Id");
+                }
+            }
+            (_, _) => warn("attachment without Content-Id and/or filename in Content-Disposition"),
+        }
+    }
+
+    map
+}
+
+fn rewrite_html(html_body: &[u8], cid_map: &CidMap) -> Result<(), Box<dyn std::error::Error>> {
+    let mut stdout = std::io::stdout();
+    let mut rewriter = HtmlRewriter::new(
+        Settings {
+            element_content_handlers: vec![
+                element!("head", |el| {
+                    el.remove();
+                    Ok(())
+                }),
+                element!("body", |el| {
+                    el.remove_and_keep_content();
+                    Ok(())
+                }),
+                element!("html", |el| {
+                    el.remove_and_keep_content();
+                    Ok(())
+                }),
+                element!("object[type][data]", |el| {
+                    if el
+                        .get_attribute("type")
+                        .expect("element! matched object[type] without type attribute")
+                        != "application/x-apple-msg-attachment"
+                    {
+                        warn("encountered object with unknown type attribute, ignoring");
+                        return Ok(());
+                    }
+
+                    match el
+                        .get_attribute("data")
+                        .expect("element! matched object[data] without data attribute")
+                        .split_at_checked(4)
+                    {
+                        Some(("cid:", cid)) => match cid_map.get(cid) {
+                            Some(filename) => el.replace(
+                                &format!(r#"<img src="{}">"#, filename),
+                                ContentType::Html,
+                            ),
+                            _ => {
+                                return Err(Box::new(Mn2htmlError::MissingAttachment(
+                                    cid.to_string(),
+                                )))
+                            }
+                        },
+                        _ => warn("encountered object with malformed data attribute, ignoring"),
+                    };
+
+                    Ok(())
+                }),
+            ],
+            ..Settings::new()
+        },
+        |c: &[u8]| stdout.write_all(c).expect("Can't write to stdout"),
+    );
+
+    rewriter.write(html_body)?;
+    rewriter.end()?;
+
+    Ok(())
+}
diff --git a/users/tazjin/blog/default.nix b/users/tazjin/blog/default.nix
index 60c79f0941e4..10de3c754a01 100644
--- a/users/tazjin/blog/default.nix
+++ b/users/tazjin/blog/default.nix
@@ -14,7 +14,7 @@ let
       <p class="footer">
         <a class="uncoloured-link" href="https://tazj.in">homepage</a>
         |
-        <a class="uncoloured-link" href="https://cs.tvl.fyi/">code</a>
+        <a class="uncoloured-link" href="https://code.tvl.fyi/">code</a>
       </p>
       <p class="lod">ಠ_ಠ</p>
     '';
diff --git a/users/tazjin/blog/posts/nixery-layers.md b/users/tazjin/blog/posts/nixery-layers.md
index 26526d11b5dc..d96fee00ccb5 100644
--- a/users/tazjin/blog/posts/nixery-layers.md
+++ b/users/tazjin/blog/posts/nixery-layers.md
@@ -260,13 +260,13 @@ TIP: This is implemented in [popcount][] in Nixery.
 Hopefully this detailed design review was useful to you. You can also watch [my
 NixCon talk][talk] about Nixery for a review of some of this, and some demos.
 
-[Nixery]: https://cs.tvl.fyi/depot/-/tree/tools/nixery
+[Nixery]: https://code.tvl.fyi/tree/tools/nixery
 [grhmc]: https://grahamc.com/blog/nix-and-layered-docker-images
 [Nix]: https://nixos.org/nix
 [registry protocols]: https://github.com/opencontainers/distribution-spec/blob/master/spec.md
 [nixery.dev]: https://nixery.dev
 [dominator trees]: https://en.wikipedia.org/wiki/Dominator_(graph_theory)
 [gonum/graph]: https://godoc.org/gonum.org/v1/gonum/graph
-[layers.go]: https://cs.tvl.fyi/depot/-/blob/tools/nixery/layers/layers.go
-[popcount]: https://cs.tvl.fyi/depot/-/tree/tools/nixery/popcount
+[layers.go]: https://code.tvl.fyi/tree/tools/nixery/layers/layers.go
+[popcount]: https://code.tvl.fyi/tree/tools/nixery/popcount
 [talk]: https://www.youtube.com/watch?v=pOI9H4oeXqA
diff --git a/users/tazjin/nixos/modules/physical.nix b/users/tazjin/nixos/modules/physical.nix
index baae1b6b5bfe..ef33ae403867 100644
--- a/users/tazjin/nixos/modules/physical.nix
+++ b/users/tazjin/nixos/modules/physical.nix
@@ -86,6 +86,7 @@ in
         unzip
         vlc
         volumeicon
+        watchexec
         whois
         xclip
         xsecurelock
diff --git a/users/wpcarro/common.nix b/users/wpcarro/common.nix
index 582b63fc4c43..f7a03d676f1a 100644
--- a/users/wpcarro/common.nix
+++ b/users/wpcarro/common.nix
@@ -77,7 +77,7 @@ in
     # This depends on compiler-rt-libc-10.0.1, which is marked as broken on
     # aarch64-darwin, but depot sets `allowBroken = true`, which means any
     # build that depends on dig will fail on OSX (e.g. emacs).
-    # https://cs.tvl.fyi/github.com/NixOS/nixpkgs@e9b195248c6cd7961a453b10294aea9ab58e01b4/-/blob/pkgs/development/compilers/llvm/10/compiler-rt/default.nix?L122
+    # https://github.com/NixOS/nixpkgs/blob/e9b195248c6cd7961a453b10294aea9ab58e01b4/pkgs/development/compilers/llvm/10/compiler-rt/default.nix#L122
     dig
   ] else [ ]);
 }
diff --git a/users/wpcarro/website/blog/posts/restic.md b/users/wpcarro/website/blog/posts/restic.md
index 4af1fab3682f..87e7e3a13061 100644
--- a/users/wpcarro/website/blog/posts/restic.md
+++ b/users/wpcarro/website/blog/posts/restic.md
@@ -85,7 +85,7 @@ Snapshots processed:   175
 > Ah... the world agrees again.
 > -- me
 
-[1]: https://cs.tvl.fyi/depot@2ec0d3611960b163a7052e8554ba065f3c89a8cc/-/blob/ops/modules/restic.nix?L9
+[1]: https://code.tvl.fyi/blob/ops/modules/restic.nix?id=2ec0d3611960b163a7052e8554ba065f3c89a8cc#n9
 [2]: https://github.com/profpatsch
 [3]: https://min.io/
 [4]: https://restic.net/
diff --git a/users/wpcarro/website/default.nix b/users/wpcarro/website/default.nix
index 56f5b02cc89d..3a3dc90ba214 100644
--- a/users/wpcarro/website/default.nix
+++ b/users/wpcarro/website/default.nix
@@ -13,7 +13,7 @@ let
     habits = "https://${domain}/habits";
     github = "https://github.com/wpcarro";
     linkedin = "https://linkedin.com/in/williampatrickcarroll";
-    depotWork = "https://cs.tvl.fyi/depot/-/blob/users/wpcarro";
+    depotWork = "https://code.tvl.fyi/tree/users/wpcarro";
   };
 
   renderTemplate = src: vars: pkgs.substituteAll (globalVars // vars // {
diff --git a/web/panettone/src/panettone.lisp b/web/panettone/src/panettone.lisp
index 37d194d0f9af..5396abe59f55 100644
--- a/web/panettone/src/panettone.lisp
+++ b/web/panettone/src/panettone.lisp
@@ -675,7 +675,7 @@ given subject an body (in a thread, to avoid blocking)"
 (comment
  (setq hunchentoot:*catch-errors-p* nil)
  ;; to setup an ssh tunnel to cheddar+irccat for development:
- ;; ssh -N -L 4238:localhost:4238 -L 4722:localhost:4722 whitby.tvl.fyi
+ ;; ssh -N -L 4238:localhost:4238 -L 4722:localhost:4722 nevsky.tvl.fyi
  (start-panettone :port 6161
                   :session-secret "session-secret")
  )
diff --git a/web/pwcrypt/Cargo.lock b/web/pwcrypt/Cargo.lock
index 73d27ae2de59..d7a4a11899d1 100644
--- a/web/pwcrypt/Cargo.lock
+++ b/web/pwcrypt/Cargo.lock
@@ -818,24 +818,24 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
 name = "wasm-bindgen"
-version = "0.2.95"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e"
+checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
 dependencies = [
  "cfg-if",
  "once_cell",
+ "rustversion",
  "wasm-bindgen-macro",
 ]
 
 [[package]]
 name = "wasm-bindgen-backend"
-version = "0.2.95"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358"
+checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
 dependencies = [
  "bumpalo",
  "log",
- "once_cell",
  "proc-macro2",
  "quote",
  "syn 2.0.18",
@@ -856,9 +856,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro"
-version = "0.2.95"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56"
+checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
 dependencies = [
  "quote",
  "wasm-bindgen-macro-support",
@@ -866,9 +866,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro-support"
-version = "0.2.95"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68"
+checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -879,9 +879,12 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-shared"
-version = "0.2.95"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d"
+checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
+dependencies = [
+ "unicode-ident",
+]
 
 [[package]]
 name = "web-sys"
diff --git a/web/pwcrypt/Cargo.toml b/web/pwcrypt/Cargo.toml
index 0479a075deb9..3c4760931c7e 100644
--- a/web/pwcrypt/Cargo.toml
+++ b/web/pwcrypt/Cargo.toml
@@ -8,6 +8,6 @@ argon2 = "0.5.0"
 getrandom = { version = "0.2.10", features = ["js"] }
 gloo = "0.8.0"
 rand_core = { version = "0.6.4", features = ["getrandom"] }
-wasm-bindgen = "= 0.2.95"
+wasm-bindgen = "= 0.2.100"
 web-sys = "0.3"
 yew = { version = "0.20.0", features = [ "csr" ]}
diff --git a/web/tvixbolt/Cargo.lock b/web/tvixbolt/Cargo.lock
index b82469a1af00..789018d2b453 100644
--- a/web/tvixbolt/Cargo.lock
+++ b/web/tvixbolt/Cargo.lock
@@ -1600,24 +1600,24 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
 name = "wasm-bindgen"
-version = "0.2.95"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e"
+checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
 dependencies = [
  "cfg-if",
  "once_cell",
+ "rustversion",
  "wasm-bindgen-macro",
 ]
 
 [[package]]
 name = "wasm-bindgen-backend"
-version = "0.2.95"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358"
+checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
 dependencies = [
  "bumpalo",
  "log",
- "once_cell",
  "proc-macro2",
  "quote",
  "syn 2.0.68",
@@ -1638,9 +1638,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro"
-version = "0.2.95"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56"
+checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
 dependencies = [
  "quote",
  "wasm-bindgen-macro-support",
@@ -1648,9 +1648,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro-support"
-version = "0.2.95"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68"
+checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1661,9 +1661,12 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-shared"
-version = "0.2.95"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d"
+checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
+dependencies = [
+ "unicode-ident",
+]
 
 [[package]]
 name = "web-sys"
diff --git a/web/tvixbolt/Cargo.nix b/web/tvixbolt/Cargo.nix
index 14baec09dc6a..30a915b3a9ce 100644
--- a/web/tvixbolt/Cargo.nix
+++ b/web/tvixbolt/Cargo.nix
@@ -4812,9 +4812,9 @@ rec {
       };
       "wasm-bindgen" = rec {
         crateName = "wasm-bindgen";
-        version = "0.2.95";
+        version = "0.2.100";
         edition = "2021";
-        sha256 = "0bpbvmxhil380gpv53smaypl8wc7sy7rq8apxfw349pn78v1x38j";
+        sha256 = "1x8ymcm6yi3i1rwj78myl1agqv2m86i648myy3lc97s9swlqkp0y";
         libName = "wasm_bindgen";
         authors = [
           "The wasm-bindgen Developers"
@@ -4827,29 +4827,42 @@ rec {
           {
             name = "once_cell";
             packageId = "once_cell";
+            usesDefaultFeatures = false;
+          }
+          {
+            name = "rustversion";
+            packageId = "rustversion";
+            optional = true;
           }
           {
             name = "wasm-bindgen-macro";
             packageId = "wasm-bindgen-macro";
           }
         ];
+        devDependencies = [
+          {
+            name = "once_cell";
+            packageId = "once_cell";
+          }
+        ];
         features = {
-          "default" = [ "spans" "std" ];
+          "default" = [ "std" "msrv" ];
           "enable-interning" = [ "std" ];
+          "msrv" = [ "rustversion" ];
+          "rustversion" = [ "dep:rustversion" ];
           "serde" = [ "dep:serde" ];
           "serde-serialize" = [ "serde" "serde_json" "std" ];
           "serde_json" = [ "dep:serde_json" ];
-          "spans" = [ "wasm-bindgen-macro/spans" ];
           "strict-macro" = [ "wasm-bindgen-macro/strict-macro" ];
           "xxx_debug_only_print_generated_code" = [ "wasm-bindgen-macro/xxx_debug_only_print_generated_code" ];
         };
-        resolvedDefaultFeatures = [ "default" "spans" "std" ];
+        resolvedDefaultFeatures = [ "default" "msrv" "rustversion" "std" ];
       };
       "wasm-bindgen-backend" = rec {
         crateName = "wasm-bindgen-backend";
-        version = "0.2.95";
+        version = "0.2.100";
         edition = "2021";
-        sha256 = "0n53wgy78bgzgjwk0z69zbspzhv8p2a4zh69s4fzvpqdrb9x8vfb";
+        sha256 = "1ihbf1hq3y81c4md9lyh6lcwbx6a5j0fw4fygd423g62lm8hc2ig";
         libName = "wasm_bindgen_backend";
         authors = [
           "The wasm-bindgen Developers"
@@ -4864,10 +4877,6 @@ rec {
             packageId = "log";
           }
           {
-            name = "once_cell";
-            packageId = "once_cell";
-          }
-          {
             name = "proc-macro2";
             packageId = "proc-macro2";
           }
@@ -4888,7 +4897,6 @@ rec {
         features = {
           "extra-traits" = [ "syn/extra-traits" ];
         };
-        resolvedDefaultFeatures = [ "spans" ];
       };
       "wasm-bindgen-futures" = rec {
         crateName = "wasm-bindgen-futures";
@@ -4926,9 +4934,9 @@ rec {
       };
       "wasm-bindgen-macro" = rec {
         crateName = "wasm-bindgen-macro";
-        version = "0.2.95";
+        version = "0.2.100";
         edition = "2021";
-        sha256 = "0mic8b2vab1a91m6x3hjxkwz23094bq1cwhnszarsnlggyz894z7";
+        sha256 = "01xls2dvzh38yj17jgrbiib1d3nyad7k2yw9s0mpklwys333zrkz";
         procMacro = true;
         libName = "wasm_bindgen_macro";
         authors = [
@@ -4945,16 +4953,14 @@ rec {
           }
         ];
         features = {
-          "spans" = [ "wasm-bindgen-macro-support/spans" ];
           "strict-macro" = [ "wasm-bindgen-macro-support/strict-macro" ];
         };
-        resolvedDefaultFeatures = [ "spans" ];
       };
       "wasm-bindgen-macro-support" = rec {
         crateName = "wasm-bindgen-macro-support";
-        version = "0.2.95";
+        version = "0.2.100";
         edition = "2021";
-        sha256 = "0s7g6glb85lyx2pj83shbmg4d50mvqhb2c2qk2j28yigaxbspii6";
+        sha256 = "1plm8dh20jg2id0320pbmrlsv6cazfv6b6907z19ys4z1jj7xs4a";
         libName = "wasm_bindgen_macro_support";
         authors = [
           "The wasm-bindgen Developers"
@@ -4984,20 +4990,24 @@ rec {
         ];
         features = {
           "extra-traits" = [ "syn/extra-traits" ];
-          "spans" = [ "wasm-bindgen-backend/spans" ];
         };
-        resolvedDefaultFeatures = [ "spans" ];
       };
       "wasm-bindgen-shared" = rec {
         crateName = "wasm-bindgen-shared";
-        version = "0.2.95";
+        version = "0.2.100";
         edition = "2021";
         links = "wasm_bindgen";
-        sha256 = "1386q7mvv5ky003hcc6yyxpid3y1m7fy0l920i3z3ab60vqhkz35";
+        sha256 = "0gffxvqgbh9r9xl36gprkfnh3w9gl8wgia6xrin7v11sjcxxf18s";
         libName = "wasm_bindgen_shared";
         authors = [
           "The wasm-bindgen Developers"
         ];
+        dependencies = [
+          {
+            name = "unicode-ident";
+            packageId = "unicode-ident";
+          }
+        ];
 
       };
       "web-sys" = rec {
diff --git a/web/tvixbolt/Cargo.toml b/web/tvixbolt/Cargo.toml
index 998c3712c56a..a92af21eeba3 100644
--- a/web/tvixbolt/Cargo.toml
+++ b/web/tvixbolt/Cargo.toml
@@ -12,4 +12,4 @@ yew-router = "0.18"
 tvix-eval = { path = "../../tvix/eval", default-features = false }
 serde = { version = "1.0.204", features = ["derive"] }
 web-sys = { version = "0.3.69", features = ["HtmlDetailsElement"] }
-wasm-bindgen = "0.2.95"
+wasm-bindgen = "0.2.100"
diff --git a/web/tvixbolt/src/lib.rs b/web/tvixbolt/src/lib.rs
index a2bfeb0a5dd1..51796ee0fc2b 100644
--- a/web/tvixbolt/src/lib.rs
+++ b/web/tvixbolt/src/lib.rs
@@ -75,7 +75,7 @@ fn footer() -> Html {
         <footer>
           <p class="footer">
             {footer_link("https://tvl.fyi", "home")}
-            {footer_link("https://cs.tvl.fyi", "code")}
+            {footer_link("https://code.tvl.fyi", "code")}
             {footer_link("https://tvl.fyi/builds", "ci")}
             {footer_link("https://b.tvl.fyi", "bugs")}
             {"© TVL"}
diff --git a/web/tvl/blog/2024-02-tvix-update.md b/web/tvl/blog/2024-02-tvix-update.md
index ce9bbf547fa8..648c4b803c06 100644
--- a/web/tvl/blog/2024-02-tvix-update.md
+++ b/web/tvl/blog/2024-02-tvix-update.md
@@ -314,7 +314,7 @@ you run into any snags, or have any questions.
 [Tvix]:                       https://tvix.dev
 [aterm]:                      http://program-transformation.org/Tools/ATermFormat.html
 [bazel-remote]:               https://github.com/buchgr/bazel-remote/pull/715
-[castore-docs]:               https://cs.tvl.fyi/depot/-/blob/tvix/castore/docs
+[castore-docs]:               https://code.tvl.fyi/tree/tvix/docs/src/castore
 [frankenbuild]:               https://blog.layus.be/posts/2021-06-25-frankenbuilds.html
 [go-nix-outpath]:             https://github.com/nix-community/go-nix/blob/93cb24a868562714f1691840e94d54ef57bc0a5a/pkg/derivation/hashes.go#L52
 [nix-compat-derivation]:      https://docs.tvix.dev/rust/nix_compat/derivation/struct.Derivation.html
@@ -325,9 +325,9 @@ you run into any snags, or have any questions.
 [nixcpp-builtins-derivation]: https://github.com/NixOS/nix/blob/49cf090cb2f51d6935756a6cf94d568cab063f81/src/libexpr/primops/derivation.nix#L4
 [nixcpp-patch-hashes]:        https://github.com/adisbladis/nix/tree/hash-tracing
 [refscan-string-contexts]:    https://inbox.tvl.su/depot/20230316120039.j4fkp3puzrtbjcpi@tp/T/#t
-[store-docs]:                 https://cs.tvl.fyi/depot/-/blob/tvix/store/docs/api.md
+[store-docs]:                 https://code.tvl.fyi/about/tvix/docs/src/store/api.md
 [string-contexts-nix-bug]:    https://github.com/NixOS/nix/issues/4629
 [tryeval-infrec]:             https://b.tvl.fyi/issues/281
-[tvix-boot-readme]:           https://cs.tvl.fyi/depot/-/blob/tvix/boot/README.md
+[tvix-boot-readme]:           https://code.tvl.fyi/about/tvix/boot/README.md
 [why-string-contexts-now]:    https://cl.tvl.fyi/c/depot/+/10446/7/tvix/eval/docs/build-references.md
 [windtunnel]:                 https://staging.windtunnel.ci/tvl/tvix
diff --git a/web/tvl/blog/rewriting-nix.md b/web/tvl/blog/rewriting-nix.md
index 1b143e5b0ed9..a45cc571ab00 100644
--- a/web/tvl/blog/rewriting-nix.md
+++ b/web/tvl/blog/rewriting-nix.md
@@ -80,7 +80,7 @@ for Nix features that are in use today.
 
 As things ramp up we will be posting more information on this blog,
 for now you can keep an eye on
-[`//tvix`](https://cs.tvl.fyi/depot/-/tree/tvix) in the TVL monorepo
+[`//tvix`](https://code.tvl.fyi/tree/tvix) in the TVL monorepo
 and subscribe to [our feed](https://tvl.fyi/feed.atom).
 
 Stay tuned!
diff --git a/web/tvl/blog/tvix-status-202209.md b/web/tvl/blog/tvix-status-202209.md
index dae1dae194ea..627c2d290670 100644
--- a/web/tvl/blog/tvix-status-202209.md
+++ b/web/tvl/blog/tvix-status-202209.md
@@ -155,7 +155,7 @@ We'll see you around!
 [Tvix]: https://tvl.fyi/blog/rewriting-nix
 [Tvixbolt]: https://bolt.tvix.dev
 [integrated]: https://cl.tvl.fyi/q/status:merged+%2522tvix/eval%2522+mergedbefore:2022-09-09
-[src]: https://cs.tvl.fyi/depot/-/tree/tvix/eval
+[src]: https://code.tvl.fyi/tree/tvix/eval
 [src-noscript]: https://code.tvl.fyi/tree/tvix/eval
 [tazjin]: https://tazj.in
 [grfn]: https://gws.fyi/