about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVova Kryachko <v.kryachko@gmail.com>2024-11-08T15·44-0500
committerVladimir Kryachko <v.kryachko@gmail.com>2024-11-12T02·15+0000
commitb564ed9d43f17c620439815b86d2940be197bd47 (patch)
treea828f081e0b9f3568366534b800c12d88d5cfff7
parent72bc4e0270891d72213989096ff1180adc07a578 (diff)
feat(nix-daemon): Implement client handler. r/8907
This change includes only the basic nix handshake protocol handling and
sets up a client session. The only supported operation at this point is
SetOptions.

Additional operations will be implemented in subsequent cls.

Change-Id: I3eccd9e0ceb270c3865929543c702f1491768852
Reviewed-on: https://cl.tvl.fyi/c/depot/+/12743
Autosubmit: Vladimir Kryachko <v.kryachko@gmail.com>
Tested-by: BuildkiteCI
Reviewed-by: flokli <flokli@flokli.de>
Reviewed-by: edef <edef@edef.eu>
Reviewed-by: Brian Olsen <me@griff.name>
-rw-r--r--tvix/Cargo.lock31
-rw-r--r--tvix/Cargo.nix101
-rw-r--r--tvix/nix-compat/Cargo.toml8
-rw-r--r--tvix/nix-compat/src/lib.rs4
-rw-r--r--tvix/nix-compat/src/nar/wire/mod.rs2
-rw-r--r--tvix/nix-compat/src/nix_daemon/handler.rs229
-rw-r--r--tvix/nix-compat/src/nix_daemon/mod.rs7
-rw-r--r--tvix/nix-compat/src/nix_daemon/types.rs62
-rw-r--r--tvix/nix-compat/src/nix_daemon/worker_protocol.rs203
-rw-r--r--tvix/nix-compat/src/wire/ser/bytes.rs9
-rw-r--r--tvix/nix-compat/src/wire/ser/mod.rs10
-rw-r--r--tvix/nix-daemon/src/bin/nix-daemon.rs39
-rw-r--r--tvix/nix-daemon/src/lib.rs18
-rw-r--r--users/edef/crunch-v2/Cargo.lock57
-rw-r--r--users/edef/crunch-v2/Cargo.nix165
-rw-r--r--users/edef/fetchroots/Cargo.lock79
-rw-r--r--users/edef/fetchroots/Cargo.nix209
-rw-r--r--users/edef/narinfo2parquet/Cargo.lock88
-rw-r--r--users/edef/narinfo2parquet/Cargo.nix224
-rw-r--r--users/edef/narinfo2parquet/Cargo.toml3
-rw-r--r--users/edef/weave/Cargo.lock57
-rw-r--r--users/edef/weave/Cargo.nix165
-rw-r--r--users/picnoir/tvix-daemon/Cargo.lock79
-rw-r--r--users/picnoir/tvix-daemon/Cargo.nix222
-rw-r--r--users/picnoir/tvix-daemon/src/main.rs4
25 files changed, 1822 insertions, 253 deletions
diff --git a/tvix/Cargo.lock b/tvix/Cargo.lock
index 73badc2af496..52496265cb9c 100644
--- a/tvix/Cargo.lock
+++ b/tvix/Cargo.lock
@@ -2300,6 +2300,7 @@ dependencies = [
  "nix-compat-derive",
  "nom",
  "num-traits",
+ "num_enum",
  "pin-project-lite",
  "pretty_assertions",
  "proptest",
@@ -2424,6 +2425,27 @@ dependencies = [
 ]
 
 [[package]]
+name = "num_enum"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179"
+dependencies = [
+ "num_enum_derive",
+]
+
+[[package]]
+name = "num_enum_derive"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56"
+dependencies = [
+ "proc-macro-crate",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.79",
+]
+
+[[package]]
 name = "number_prefix"
 version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2834,6 +2856,15 @@ dependencies = [
 ]
 
 [[package]]
+name = "proc-macro-crate"
+version = "3.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b"
+dependencies = [
+ "toml_edit 0.22.22",
+]
+
+[[package]]
 name = "proc-macro-error-attr2"
 version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/tvix/Cargo.nix b/tvix/Cargo.nix
index ed9132ebf5bb..5a6628af6dd5 100644
--- a/tvix/Cargo.nix
+++ b/tvix/Cargo.nix
@@ -7244,6 +7244,10 @@ rec {
             packageId = "num-traits";
           }
           {
+            name = "num_enum";
+            packageId = "num_enum";
+          }
+          {
             name = "pin-project-lite";
             packageId = "pin-project-lite";
             optional = true;
@@ -7269,7 +7273,7 @@ rec {
             name = "tokio";
             packageId = "tokio";
             optional = true;
-            features = [ "io-util" "macros" ];
+            features = [ "io-util" "macros" "sync" ];
           }
           {
             name = "tracing";
@@ -7328,13 +7332,14 @@ rec {
         features = {
           "async" = [ "tokio" ];
           "bytes" = [ "dep:bytes" ];
-          "default" = [ "async" "wire" "nix-compat-derive" ];
+          "daemon" = [ "tokio" "nix-compat-derive" ];
+          "default" = [ "async" "daemon" "wire" "nix-compat-derive" ];
           "nix-compat-derive" = [ "dep:nix-compat-derive" ];
           "pin-project-lite" = [ "dep:pin-project-lite" ];
           "tokio" = [ "dep:tokio" ];
           "wire" = [ "tokio" "pin-project-lite" "bytes" ];
         };
-        resolvedDefaultFeatures = [ "async" "bytes" "default" "nix-compat-derive" "pin-project-lite" "test" "tokio" "wire" ];
+        resolvedDefaultFeatures = [ "async" "bytes" "daemon" "default" "nix-compat-derive" "pin-project-lite" "test" "tokio" "wire" ];
       };
       "nix-compat-derive" = rec {
         crateName = "nix-compat-derive";
@@ -7453,6 +7458,7 @@ rec {
           }
         ];
         src = lib.cleanSourceWith { filter = sourceFilter; src = ./nix-daemon; };
+        libName = "nix_daemon";
         dependencies = [
           {
             name = "async-trait";
@@ -7656,6 +7662,76 @@ rec {
         ];
 
       };
+      "num_enum" = rec {
+        crateName = "num_enum";
+        version = "0.7.3";
+        edition = "2021";
+        sha256 = "0yai0vafhy85mvhknzfqd7lm04hzaln7i5c599rhy8mj831kyqaf";
+        authors = [
+          "Daniel Wagner-Hall <dawagner@gmail.com>"
+          "Daniel Henry-Mantilla <daniel.henry.mantilla@gmail.com>"
+          "Vincent Esche <regexident@gmail.com>"
+        ];
+        dependencies = [
+          {
+            name = "num_enum_derive";
+            packageId = "num_enum_derive";
+            usesDefaultFeatures = false;
+          }
+        ];
+        features = {
+          "complex-expressions" = [ "num_enum_derive/complex-expressions" ];
+          "default" = [ "std" ];
+          "std" = [ "num_enum_derive/std" ];
+        };
+        resolvedDefaultFeatures = [ "default" "std" ];
+      };
+      "num_enum_derive" = rec {
+        crateName = "num_enum_derive";
+        version = "0.7.3";
+        edition = "2021";
+        sha256 = "0mksna1jj87ydh146gn6jcqkvvs920c3dgh0p4f3xk184kpl865g";
+        procMacro = true;
+        authors = [
+          "Daniel Wagner-Hall <dawagner@gmail.com>"
+          "Daniel Henry-Mantilla <daniel.henry.mantilla@gmail.com>"
+          "Vincent Esche <regexident@gmail.com>"
+        ];
+        dependencies = [
+          {
+            name = "proc-macro-crate";
+            packageId = "proc-macro-crate";
+            optional = true;
+          }
+          {
+            name = "proc-macro2";
+            packageId = "proc-macro2";
+          }
+          {
+            name = "quote";
+            packageId = "quote";
+          }
+          {
+            name = "syn";
+            packageId = "syn 2.0.79";
+            features = [ "parsing" ];
+          }
+        ];
+        devDependencies = [
+          {
+            name = "syn";
+            packageId = "syn 2.0.79";
+            features = [ "extra-traits" "parsing" ];
+          }
+        ];
+        features = {
+          "complex-expressions" = [ "syn/full" ];
+          "default" = [ "std" ];
+          "proc-macro-crate" = [ "dep:proc-macro-crate" ];
+          "std" = [ "proc-macro-crate" ];
+        };
+        resolvedDefaultFeatures = [ "proc-macro-crate" "std" ];
+      };
       "number_prefix" = rec {
         crateName = "number_prefix";
         version = "0.4.0";
@@ -9033,6 +9109,23 @@ rec {
           "verbatim" = [ "syn/parsing" ];
         };
       };
+      "proc-macro-crate" = rec {
+        crateName = "proc-macro-crate";
+        version = "3.2.0";
+        edition = "2021";
+        sha256 = "0yzsqnavb3lmrcsmbrdjfrky9vcbl46v59xi9avn0796rb3likwf";
+        libName = "proc_macro_crate";
+        authors = [
+          "Bastian Köcher <git@kchr.de>"
+        ];
+        dependencies = [
+          {
+            name = "toml_edit";
+            packageId = "toml_edit 0.22.22";
+          }
+        ];
+
+      };
       "proc-macro-error-attr2" = rec {
         crateName = "proc-macro-error-attr2";
         version = "2.0.0";
@@ -13746,7 +13839,7 @@ rec {
           "perf" = [ "dep:kstring" ];
           "serde" = [ "dep:serde" "toml_datetime/serde" "dep:serde_spanned" ];
         };
-        resolvedDefaultFeatures = [ "display" "parse" "serde" ];
+        resolvedDefaultFeatures = [ "default" "display" "parse" "serde" ];
       };
       "tonic" = rec {
         crateName = "tonic";
diff --git a/tvix/nix-compat/Cargo.toml b/tvix/nix-compat/Cargo.toml
index cbbf97175d14..e9b44ddb7adf 100644
--- a/tvix/nix-compat/Cargo.toml
+++ b/tvix/nix-compat/Cargo.toml
@@ -8,10 +8,13 @@ edition = "2021"
 async = ["tokio"]
 # code emitting low-level packets used in the daemon protocol.
 wire = ["tokio", "pin-project-lite", "bytes"]
+
+# nix-daemon protocol handling
+daemon = ["tokio", "nix-compat-derive"]
 test = []
 
 # Enable all features by default.
-default = ["async", "wire", "nix-compat-derive"]
+default = ["async", "daemon", "wire", "nix-compat-derive"]
 
 [dependencies]
 bitflags = { workspace = true }
@@ -30,8 +33,9 @@ sha2 = { workspace = true }
 thiserror = { workspace = true }
 tracing = { workspace = true }
 bytes = { workspace = true, optional = true }
-tokio = { workspace = true, features = ["io-util", "macros"], optional = true }
+tokio = { workspace = true, features = ["io-util", "macros", "sync"], optional = true }
 pin-project-lite = { workspace = true, optional = true }
+num_enum = "0.7.3"
 
 [dependencies.nix-compat-derive]
 path = "../nix-compat-derive"
diff --git a/tvix/nix-compat/src/lib.rs b/tvix/nix-compat/src/lib.rs
index ae9f1674468e..4c327fa4569b 100644
--- a/tvix/nix-compat/src/lib.rs
+++ b/tvix/nix-compat/src/lib.rs
@@ -14,7 +14,7 @@ pub mod store_path;
 #[cfg(feature = "wire")]
 pub mod wire;
 
-#[cfg(feature = "wire")]
+#[cfg(feature = "daemon")]
 pub mod nix_daemon;
-#[cfg(feature = "wire")]
+#[cfg(feature = "daemon")]
 pub use nix_daemon::worker_protocol;
diff --git a/tvix/nix-compat/src/nar/wire/mod.rs b/tvix/nix-compat/src/nar/wire/mod.rs
index ddf021bc1fa1..67654129ee1d 100644
--- a/tvix/nix-compat/src/nar/wire/mod.rs
+++ b/tvix/nix-compat/src/nar/wire/mod.rs
@@ -91,9 +91,11 @@ pub const TOK_ENT: [u8; 48] = *b"\x05\0\0\0\0\0\0\0entry\0\0\0\x01\0\0\0\0\0\0\0
 pub const TOK_NOD: [u8; 48] = *b"\x04\0\0\0\0\0\0\0node\0\0\0\0\x01\0\0\0\0\0\0\0(\0\0\0\0\0\0\0\x04\0\0\0\0\0\0\0type\0\0\0\0";
 pub const TOK_PAR: [u8; 16] = *b"\x01\0\0\0\0\0\0\0)\0\0\0\0\0\0\0";
 #[cfg(feature = "async")]
+#[allow(dead_code)]
 const TOK_PAD_PAR: [u8; 24] = *b"\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0)\0\0\0\0\0\0\0";
 
 #[cfg(feature = "async")]
+#[allow(dead_code)]
 #[derive(Debug)]
 pub(crate) enum PadPar {}
 
diff --git a/tvix/nix-compat/src/nix_daemon/handler.rs b/tvix/nix-compat/src/nix_daemon/handler.rs
new file mode 100644
index 000000000000..c0257d979acc
--- /dev/null
+++ b/tvix/nix-compat/src/nix_daemon/handler.rs
@@ -0,0 +1,229 @@
+use std::{future::Future, sync::Arc};
+
+use tokio::{
+    io::{split, AsyncReadExt, AsyncWriteExt, ReadHalf, WriteHalf},
+    sync::Mutex,
+};
+use tracing::debug;
+
+use super::{
+    worker_protocol::{server_handshake_client, ClientSettings, Operation, Trust, STDERR_LAST},
+    NixDaemonIO,
+};
+use crate::wire::{
+    de::{NixRead, NixReader},
+    ser::{NixSerialize, NixWrite, NixWriter, NixWriterBuilder},
+    ProtocolVersion,
+};
+use crate::{nix_daemon::types::NixError, worker_protocol::STDERR_ERROR};
+
+/// Handles a single connection with a nix client.
+///
+/// As part of its [`initialization`] it performs the handshake with the client
+/// and determines the [ProtocolVersion] and [ClientSettings] to use for the remainder of the session.
+///
+/// Once initialized, [`handle_client`] needs to be called to handle the rest of the session,
+/// it delegates all operation handling to an instance of [NixDaemonIO].
+///
+/// [`initialization`]: NixDaemon::initialize
+#[allow(dead_code)]
+pub struct NixDaemon<IO, R, W> {
+    io: Arc<IO>,
+    protocol_version: ProtocolVersion,
+    client_settings: ClientSettings,
+    reader: NixReader<R>,
+    writer: Arc<Mutex<NixWriter<W>>>,
+}
+
+impl<IO, R, W> NixDaemon<IO, R, W>
+where
+    IO: NixDaemonIO + Sync + Send,
+{
+    pub fn new(
+        io: Arc<IO>,
+        protocol_version: ProtocolVersion,
+        client_settings: ClientSettings,
+        reader: NixReader<R>,
+        writer: NixWriter<W>,
+    ) -> Self {
+        Self {
+            io,
+            protocol_version,
+            client_settings,
+            reader,
+            writer: Arc::new(Mutex::new(writer)),
+        }
+    }
+}
+
+impl<IO, RW> NixDaemon<IO, ReadHalf<RW>, WriteHalf<RW>>
+where
+    RW: AsyncReadExt + AsyncWriteExt + Send + Unpin + 'static,
+    IO: NixDaemonIO + Sync + Send,
+{
+    /// Async constructor for NixDaemon.
+    ///
+    /// Performs the initial handshake with the client and retrieves the client's preferred
+    /// settings.
+    ///
+    /// The resulting daemon can handle the client session by calling [NixDaemon::handle_client].
+    pub async fn initialize(io: Arc<IO>, mut connection: RW) -> Result<Self, std::io::Error>
+    where
+        RW: AsyncReadExt + AsyncWriteExt + Send + Unpin,
+    {
+        let protocol_version =
+            server_handshake_client(&mut connection, "2.18.2", Trust::Trusted).await?;
+
+        connection.write_u64_le(STDERR_LAST).await?;
+        let (reader, writer) = split(connection);
+        let mut reader = NixReader::builder()
+            .set_version(protocol_version)
+            .build(reader);
+        let mut writer = NixWriterBuilder::default()
+            .set_version(protocol_version)
+            .build(writer);
+
+        // The first op is always SetOptions
+        let operation: Operation = reader.read_value().await?;
+        if operation != Operation::SetOptions {
+            return Err(std::io::Error::other(
+                "Expected SetOptions operation, but got {operation}",
+            ));
+        }
+        let client_settings: ClientSettings = reader.read_value().await?;
+        writer.write_number(STDERR_LAST).await?;
+        writer.flush().await?;
+
+        Ok(Self::new(
+            io,
+            protocol_version,
+            client_settings,
+            reader,
+            writer,
+        ))
+    }
+
+    /// Main client connection loop, reads client's requests and responds to them accordingly.
+    pub async fn handle_client(&mut self) -> Result<(), std::io::Error> {
+        loop {
+            let op_code = self.reader.read_number().await?;
+            match TryInto::<Operation>::try_into(op_code) {
+                Ok(operation) => match operation {
+                    Operation::SetOptions => {
+                        self.client_settings = self.reader.read_value().await?;
+                        self.handle(async { Ok(()) }).await?
+                    }
+                    _ => {
+                        return Err(std::io::Error::other(format!(
+                            "Operation {operation:?} is not implemented"
+                        )));
+                    }
+                },
+                _ => {
+                    return Err(std::io::Error::other(format!(
+                        "Unknown operation code received: {op_code}"
+                    )));
+                }
+            }
+        }
+    }
+
+    /// Handles the operation and sends the response or error to the client.
+    ///
+    /// As per nix daemon protocol, after sending the request, the client expects zero or more
+    /// log lines/activities followed by either
+    /// * STDERR_LAST and the response bytes
+    /// * STDERR_ERROR and the error
+    ///
+    /// This is a helper method, awaiting on the passed in future and then
+    /// handling log lines/activities as described above.
+    async fn handle<T>(
+        &mut self,
+        future: impl Future<Output = std::io::Result<T>>,
+    ) -> Result<(), std::io::Error>
+    where
+        T: NixSerialize + Send,
+    {
+        let result = future.await;
+        let mut writer = self.writer.lock().await;
+
+        match result {
+            Ok(r) => {
+                // the protocol requires that we first indicate that we are done sending logs
+                // by sending STDERR_LAST and then the response.
+                writer.write_number(STDERR_LAST).await?;
+                writer.write_value(&r).await?;
+                writer.flush().await
+            }
+            Err(e) => {
+                debug!(err = ?e, "IO error");
+                writer.write_number(STDERR_ERROR).await?;
+                writer.write_value(&NixError::new(format!("{e:?}"))).await?;
+                writer.flush().await
+            }
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use std::sync::Arc;
+
+    use tokio::io::AsyncWriteExt;
+
+    use crate::{
+        wire::ProtocolVersion,
+        worker_protocol::{ClientSettings, WORKER_MAGIC_1, WORKER_MAGIC_2},
+    };
+
+    struct MockDaemonIO {}
+
+    impl NixDaemonIO for MockDaemonIO {}
+
+    #[tokio::test]
+    async fn test_daemon_initialization() {
+        let mut builder = tokio_test::io::Builder::new();
+        let test_conn = builder
+            .read(&WORKER_MAGIC_1.to_le_bytes())
+            .write(&WORKER_MAGIC_2.to_le_bytes())
+            // Our version is 1.37
+            .write(&[37, 1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
+            // The client's versin is 1.35
+            .read(&[35, 1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
+            // cpu affinity
+            .read(&[0; 8])
+            // reservespace
+            .read(&[0; 8])
+            // version (size)
+            .write(&[0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
+            // version (data == 2.18.2 + padding)
+            .write(&[50, 46, 49, 56, 46, 50, 0, 0])
+            // Trusted (1 == client trusted)
+            .write(&[1, 0, 0, 0, 0, 0, 0, 0])
+            // STDERR_LAST
+            .write(&[115, 116, 108, 97, 0, 0, 0, 0]);
+
+        let mut bytes = Vec::new();
+        let mut writer = NixWriter::new(&mut bytes);
+        writer
+            .write_value(&ClientSettings::default())
+            .await
+            .unwrap();
+        writer.flush().await.unwrap();
+
+        let test_conn = test_conn
+            // SetOptions op
+            .read(&[19, 0, 0, 0, 0, 0, 0, 0])
+            .read(&bytes)
+            // STDERR_LAST
+            .write(&[115, 116, 108, 97, 0, 0, 0, 0])
+            .build();
+
+        let daemon = NixDaemon::initialize(Arc::new(MockDaemonIO {}), test_conn)
+            .await
+            .unwrap();
+        assert_eq!(daemon.client_settings, ClientSettings::default());
+        assert_eq!(daemon.protocol_version, ProtocolVersion::from_parts(1, 35));
+    }
+}
diff --git a/tvix/nix-compat/src/nix_daemon/mod.rs b/tvix/nix-compat/src/nix_daemon/mod.rs
index 633fdbebd47c..af487aea37bb 100644
--- a/tvix/nix-compat/src/nix_daemon/mod.rs
+++ b/tvix/nix-compat/src/nix_daemon/mod.rs
@@ -1 +1,8 @@
+pub mod handler;
+pub mod types;
 pub mod worker_protocol;
+
+/// Represents all possible operations over the nix-daemon protocol.
+pub trait NixDaemonIO {
+    // TODO add methods to it.
+}
diff --git a/tvix/nix-compat/src/nix_daemon/types.rs b/tvix/nix-compat/src/nix_daemon/types.rs
new file mode 100644
index 000000000000..6b038ae8aa85
--- /dev/null
+++ b/tvix/nix-compat/src/nix_daemon/types.rs
@@ -0,0 +1,62 @@
+use nix_compat_derive::{NixDeserialize, NixSerialize};
+
+/// Marker type that consumes/sends and ignores a u64.
+#[derive(Clone, Debug, NixDeserialize, NixSerialize)]
+#[nix(from = "u64", into = "u64")]
+pub struct IgnoredZero;
+impl From<u64> for IgnoredZero {
+    fn from(_: u64) -> Self {
+        IgnoredZero
+    }
+}
+
+impl From<IgnoredZero> for u64 {
+    fn from(_: IgnoredZero) -> Self {
+        0
+    }
+}
+
+#[derive(Debug, NixSerialize)]
+pub struct TraceLine {
+    have_pos: IgnoredZero,
+    hint: String,
+}
+
+/// Represents an error returned by the nix-daemon to its client.
+///
+/// Adheres to the format described in serialization.md
+#[derive(NixSerialize)]
+pub struct NixError {
+    #[nix(version = "26..")]
+    type_: &'static str,
+
+    #[nix(version = "26..")]
+    level: u64,
+
+    #[nix(version = "26..")]
+    name: &'static str,
+
+    msg: String,
+    #[nix(version = "26..")]
+    have_pos: IgnoredZero,
+
+    #[nix(version = "26..")]
+    traces: Vec<TraceLine>,
+
+    #[nix(version = "..=25")]
+    exit_status: u64,
+}
+
+impl NixError {
+    pub fn new(msg: String) -> Self {
+        Self {
+            type_: "Error",
+            level: 0, // error
+            name: "Error",
+            msg,
+            have_pos: IgnoredZero {},
+            traces: vec![],
+            exit_status: 1,
+        }
+    }
+}
diff --git a/tvix/nix-compat/src/nix_daemon/worker_protocol.rs b/tvix/nix-compat/src/nix_daemon/worker_protocol.rs
index 92259a0633a0..1ef9b9ab02d7 100644
--- a/tvix/nix-compat/src/nix_daemon/worker_protocol.rs
+++ b/tvix/nix-compat/src/nix_daemon/worker_protocol.rs
@@ -1,20 +1,21 @@
 use std::{
     cmp::min,
-    collections::HashMap,
+    collections::BTreeMap,
     io::{Error, ErrorKind},
 };
 
-use enum_primitive_derive::Primitive;
-use num_traits::{FromPrimitive, ToPrimitive};
+use nix_compat_derive::{NixDeserialize, NixSerialize};
+use num_enum::{FromPrimitive, IntoPrimitive, TryFromPrimitive};
 use tokio::io::{AsyncReadExt, AsyncWriteExt};
 
 use crate::wire;
 
 use crate::wire::ProtocolVersion;
 
-static WORKER_MAGIC_1: u64 = 0x6e697863; // "nixc"
-static WORKER_MAGIC_2: u64 = 0x6478696f; // "dxio"
+pub(crate) static WORKER_MAGIC_1: u64 = 0x6e697863; // "nixc"
+pub(crate) static WORKER_MAGIC_2: u64 = 0x6478696f; // "dxio"
 pub static STDERR_LAST: u64 = 0x616c7473; // "alts"
+pub(crate) static STDERR_ERROR: u64 = 0x63787470; // "cxtp"
 
 /// | Nix version     | Protocol |
 /// |-----------------|----------|
@@ -55,7 +56,11 @@ pub static MAX_SETTING_SIZE: usize = 1024;
 /// Note: for now, we're using the Nix 2.20 operation description. The
 /// operations marked as obsolete are obsolete for Nix 2.20, not
 /// necessarily for Nix 2.3. We'll revisit this later on.
-#[derive(Debug, PartialEq, Primitive)]
+#[derive(
+    Clone, Debug, PartialEq, TryFromPrimitive, IntoPrimitive, NixDeserialize, NixSerialize,
+)]
+#[nix(try_from = "u64", into = "u64")]
+#[repr(u64)]
 pub enum Operation {
     IsValidPath = 1,
     HasSubstitutes = 3,
@@ -106,8 +111,13 @@ pub enum Operation {
 /// Log verbosity. In the Nix wire protocol, the client requests a
 /// verbosity level to the daemon, which in turns does not produce any
 /// log below this verbosity.
-#[derive(Debug, PartialEq, Primitive)]
+#[derive(
+    Debug, PartialEq, FromPrimitive, IntoPrimitive, NixDeserialize, NixSerialize, Default, Clone,
+)]
+#[nix(from = "u64", into = "u64")]
+#[repr(u64)]
 pub enum Verbosity {
+    #[default]
     LvlError = 0,
     LvlWarn = 1,
     LvlNotice = 2,
@@ -120,7 +130,7 @@ pub enum Verbosity {
 
 /// Settings requested by the client. These settings are applied to a
 /// connection to between the daemon and a client.
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, NixDeserialize, NixSerialize, Default)]
 pub struct ClientSettings {
     pub keep_failed: bool,
     pub keep_going: bool,
@@ -128,70 +138,21 @@ pub struct ClientSettings {
     pub verbosity: Verbosity,
     pub max_build_jobs: u64,
     pub max_silent_time: u64,
-    pub verbose_build: bool,
+    pub use_build_hook: bool,
+    pub verbose_build: u64,
+    pub log_type: u64,
+    pub print_build_trace: u64,
     pub build_cores: u64,
     pub use_substitutes: bool,
+
     /// Key/Value dictionary in charge of overriding the settings set
     /// by the Nix config file.
     ///
     /// Some settings can be safely overidden,
     /// some other require the user running the Nix client to be part
     /// of the trusted users group.
-    pub overrides: HashMap<String, String>,
-}
-
-/// Reads the client settings from the wire.
-///
-/// Note: this function **only** reads the settings. It does not
-/// manage the log state with the daemon. You'll have to do that on
-/// your own. A minimal log implementation will consist in sending
-/// back [STDERR_LAST] to the client after reading the client
-/// settings.
-///
-/// FUTUREWORK: write serialization.
-pub async fn read_client_settings<R: AsyncReadExt + Unpin>(
-    r: &mut R,
-    client_version: ProtocolVersion,
-) -> std::io::Result<ClientSettings> {
-    let keep_failed = r.read_u64_le().await? != 0;
-    let keep_going = r.read_u64_le().await? != 0;
-    let try_fallback = r.read_u64_le().await? != 0;
-    let verbosity_uint = r.read_u64_le().await?;
-    let verbosity = Verbosity::from_u64(verbosity_uint).ok_or_else(|| {
-        Error::new(
-            ErrorKind::InvalidData,
-            format!("Can't convert integer {} to verbosity", verbosity_uint),
-        )
-    })?;
-    let max_build_jobs = r.read_u64_le().await?;
-    let max_silent_time = r.read_u64_le().await?;
-    _ = r.read_u64_le().await?; // obsolete useBuildHook
-    let verbose_build = r.read_u64_le().await? != 0;
-    _ = r.read_u64_le().await?; // obsolete logType
-    _ = r.read_u64_le().await?; // obsolete printBuildTrace
-    let build_cores = r.read_u64_le().await?;
-    let use_substitutes = r.read_u64_le().await? != 0;
-    let mut overrides = HashMap::new();
-    if client_version.minor() >= 12 {
-        let num_overrides = r.read_u64_le().await?;
-        for _ in 0..num_overrides {
-            let name = wire::read_string(r, 0..=MAX_SETTING_SIZE).await?;
-            let value = wire::read_string(r, 0..=MAX_SETTING_SIZE).await?;
-            overrides.insert(name, value);
-        }
-    }
-    Ok(ClientSettings {
-        keep_failed,
-        keep_going,
-        try_fallback,
-        verbosity,
-        max_build_jobs,
-        max_silent_time,
-        verbose_build,
-        build_cores,
-        use_substitutes,
-        overrides,
-    })
+    #[nix(version = "12..")]
+    pub overrides: BTreeMap<String, String>,
 }
 
 /// Performs the initial handshake the server is sending to a connecting client.
@@ -269,18 +230,17 @@ where
 /// Read a worker [Operation] from the wire.
 pub async fn read_op<R: AsyncReadExt + Unpin>(r: &mut R) -> std::io::Result<Operation> {
     let op_number = r.read_u64_le().await?;
-    Operation::from_u64(op_number).ok_or(Error::new(
-        ErrorKind::InvalidData,
-        format!("Invalid OP number {}", op_number),
-    ))
+    Operation::try_from(op_number).map_err(|_| {
+        Error::new(
+            ErrorKind::InvalidData,
+            format!("Invalid OP number {}", op_number),
+        )
+    })
 }
 
 /// Write a worker [Operation] to the wire.
-pub async fn write_op<W: AsyncWriteExt + Unpin>(w: &mut W, op: &Operation) -> std::io::Result<()> {
-    let op = Operation::to_u64(op).ok_or(Error::new(
-        ErrorKind::Other,
-        format!("Can't convert the OP {:?} to u64", op),
-    ))?;
+pub async fn write_op<W: AsyncWriteExt + Unpin>(w: &mut W, op: Operation) -> std::io::Result<()> {
+    let op: u64 = op.into();
     w.write_u64(op).await
 }
 
@@ -309,8 +269,6 @@ where
 #[cfg(test)]
 mod tests {
     use super::*;
-    use hex_literal::hex;
-    use tokio_test::io::Builder;
 
     #[tokio::test]
     async fn test_init_hanshake() {
@@ -391,99 +349,4 @@ mod tests {
 
         assert_eq!(picked_version, ProtocolVersion::from_parts(1, 24))
     }
-
-    #[tokio::test]
-    async fn test_read_client_settings_without_overrides() {
-        // Client settings bits captured from a Nix 2.3.17 run w/ sockdump (protocol version 21).
-        let wire_bits = hex!(
-            "00 00 00 00 00 00 00 00 \
-             00 00 00 00 00 00 00 00 \
-             00 00 00 00 00 00 00 00 \
-             02 00 00 00 00 00 00 00 \
-             10 00 00 00 00 00 00 00 \
-             00 00 00 00 00 00 00 00 \
-             01 00 00 00 00 00 00 00 \
-             00 00 00 00 00 00 00 00 \
-             00 00 00 00 00 00 00 00 \
-             00 00 00 00 00 00 00 00 \
-             00 00 00 00 00 00 00 00 \
-             01 00 00 00 00 00 00 00 \
-             00 00 00 00 00 00 00 00"
-        );
-        let mut mock = Builder::new().read(&wire_bits).build();
-        let settings = read_client_settings(&mut mock, ProtocolVersion::from_parts(1, 21))
-            .await
-            .expect("should parse");
-        let expected = ClientSettings {
-            keep_failed: false,
-            keep_going: false,
-            try_fallback: false,
-            verbosity: Verbosity::LvlNotice,
-            max_build_jobs: 16,
-            max_silent_time: 0,
-            verbose_build: false,
-            build_cores: 0,
-            use_substitutes: true,
-            overrides: HashMap::new(),
-        };
-        assert_eq!(settings, expected);
-    }
-
-    #[tokio::test]
-    async fn test_read_client_settings_with_overrides() {
-        // Client settings bits captured from a Nix 2.3.17 run w/ sockdump (protocol version 21).
-        let wire_bits = hex!(
-            "00 00 00 00 00 00 00 00 \
-             00 00 00 00 00 00 00 00 \
-             00 00 00 00 00 00 00 00 \
-             02 00 00 00 00 00 00 00 \
-             10 00 00 00 00 00 00 00 \
-             00 00 00 00 00 00 00 00 \
-             01 00 00 00 00 00 00 00 \
-             00 00 00 00 00 00 00 00 \
-             00 00 00 00 00 00 00 00 \
-             00 00 00 00 00 00 00 00 \
-             00 00 00 00 00 00 00 00 \
-             01 00 00 00 00 00 00 00 \
-             02 00 00 00 00 00 00 00 \
-             0c 00 00 00 00 00 00 00 \
-             61 6c 6c 6f 77 65 64 2d \
-             75 72 69 73 00 00 00 00 \
-             1e 00 00 00 00 00 00 00 \
-             68 74 74 70 73 3a 2f 2f \
-             62 6f 72 64 65 61 75 78 \
-             2e 67 75 69 78 2e 67 6e \
-             75 2e 6f 72 67 2f 00 00 \
-             0d 00 00 00 00 00 00 00 \
-             61 6c 6c 6f 77 65 64 2d \
-             75 73 65 72 73 00 00 00 \
-             0b 00 00 00 00 00 00 00 \
-             6a 65 61 6e 20 70 69 65 \
-             72 72 65 00 00 00 00 00"
-        );
-        let mut mock = Builder::new().read(&wire_bits).build();
-        let settings = read_client_settings(&mut mock, ProtocolVersion::from_parts(1, 21))
-            .await
-            .expect("should parse");
-        let overrides = HashMap::from([
-            (
-                String::from("allowed-uris"),
-                String::from("https://bordeaux.guix.gnu.org/"),
-            ),
-            (String::from("allowed-users"), String::from("jean pierre")),
-        ]);
-        let expected = ClientSettings {
-            keep_failed: false,
-            keep_going: false,
-            try_fallback: false,
-            verbosity: Verbosity::LvlNotice,
-            max_build_jobs: 16,
-            max_silent_time: 0,
-            verbose_build: false,
-            build_cores: 0,
-            use_substitutes: true,
-            overrides,
-        };
-        assert_eq!(settings, expected);
-    }
 }
diff --git a/tvix/nix-compat/src/wire/ser/bytes.rs b/tvix/nix-compat/src/wire/ser/bytes.rs
index 4338d3f8761e..737edb059b5b 100644
--- a/tvix/nix-compat/src/wire/ser/bytes.rs
+++ b/tvix/nix-compat/src/wire/ser/bytes.rs
@@ -38,6 +38,15 @@ impl NixSerialize for str {
     }
 }
 
+impl NixSerialize for &str {
+    async fn serialize<W>(&self, writer: &mut W) -> Result<(), W::Error>
+    where
+        W: NixWrite,
+    {
+        writer.write_slice(self.as_bytes()).await
+    }
+}
+
 #[cfg(test)]
 mod test {
     use hex_literal::hex;
diff --git a/tvix/nix-compat/src/wire/ser/mod.rs b/tvix/nix-compat/src/wire/ser/mod.rs
index 5860226f39eb..ef3c6e2e372f 100644
--- a/tvix/nix-compat/src/wire/ser/mod.rs
+++ b/tvix/nix-compat/src/wire/ser/mod.rs
@@ -122,3 +122,13 @@ pub trait NixSerialize {
     where
         W: NixWrite;
 }
+
+// Noop
+impl NixSerialize for () {
+    async fn serialize<W>(&self, _writer: &mut W) -> Result<(), W::Error>
+    where
+        W: NixWrite,
+    {
+        Ok(())
+    }
+}
diff --git a/tvix/nix-daemon/src/bin/nix-daemon.rs b/tvix/nix-daemon/src/bin/nix-daemon.rs
index 769e968309f8..0bb323c994bc 100644
--- a/tvix/nix-daemon/src/bin/nix-daemon.rs
+++ b/tvix/nix-daemon/src/bin/nix-daemon.rs
@@ -1,8 +1,10 @@
 use clap::Parser;
 use mimalloc::MiMalloc;
-use std::error::Error;
-use tokio::io::AsyncWriteExt;
+use nix_compat::nix_daemon::handler::NixDaemon;
+use nix_daemon::TvixDaemon;
+use std::{error::Error, sync::Arc};
 use tokio_listener::SystemOptions;
+use tracing::error;
 use tvix_store::utils::{construct_services, ServiceUrlsGrpc};
 
 #[global_allocator]
@@ -58,7 +60,7 @@ async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
 }
 
 async fn run(cli: Cli) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
-    let (_blob_service, _directory_service, _path_info_service, _nar_calculation_service) =
+    let (_blob_service, _directory_service, path_info_service, _nar_calculation_service) =
         construct_services(cli.service_addrs).await?;
 
     let listen_address = cli.listen_args.listen_address.unwrap_or_else(|| {
@@ -74,16 +76,29 @@ async fn run(cli: Cli) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
     )
     .await?;
 
-    while let Ok((mut connection, _)) = listener.accept().await {
-        tokio::spawn(async move {
-            let ucred = connection
-                .try_borrow_unix()
-                .and_then(|u| u.peer_cred().ok());
+    let io = Arc::new(TvixDaemon::new(path_info_service));
 
-            // For now we just write the connected process credentials into the connection.
-            let _ = connection
-                .write_all(format!("Hello {:?}", ucred).as_bytes())
-                .await;
+    while let Ok((connection, _)) = listener.accept().await {
+        let io = io.clone();
+        tokio::spawn(async move {
+            match NixDaemon::initialize(io.clone(), connection).await {
+                Ok(mut daemon) => {
+                    if let Err(error) = daemon.handle_client().await {
+                        match error.kind() {
+                            std::io::ErrorKind::UnexpectedEof => {
+                                // client disconnected, nothing to do
+                            }
+                            _ => {
+                                // otherwise log the error and disconnect
+                                error!(error=?error, "client error");
+                            }
+                        }
+                    }
+                }
+                Err(error) => {
+                    error!(error=?error, "nix-daemon handshake failed");
+                }
+            }
         });
     }
     Ok(())
diff --git a/tvix/nix-daemon/src/lib.rs b/tvix/nix-daemon/src/lib.rs
new file mode 100644
index 000000000000..f10d6c7ad669
--- /dev/null
+++ b/tvix/nix-daemon/src/lib.rs
@@ -0,0 +1,18 @@
+use std::sync::Arc;
+
+use nix_compat::nix_daemon::NixDaemonIO;
+use tvix_store::pathinfoservice::PathInfoService;
+
+#[allow(dead_code)]
+pub struct TvixDaemon {
+    path_info_service: Arc<dyn PathInfoService>,
+}
+
+impl TvixDaemon {
+    pub fn new(path_info_service: Arc<dyn PathInfoService>) -> Self {
+        Self { path_info_service }
+    }
+}
+
+/// Implements [NixDaemonIO] backed by tvix services.
+impl NixDaemonIO for TvixDaemon {}
diff --git a/users/edef/crunch-v2/Cargo.lock b/users/edef/crunch-v2/Cargo.lock
index d7959aeee154..5a167c6d79f9 100644
--- a/users/edef/crunch-v2/Cargo.lock
+++ b/users/edef/crunch-v2/Cargo.lock
@@ -1430,6 +1430,7 @@ dependencies = [
  "nix-compat-derive",
  "nom",
  "num-traits",
+ "num_enum",
  "pin-project-lite",
  "serde",
  "serde_json",
@@ -1487,6 +1488,27 @@ dependencies = [
 ]
 
 [[package]]
+name = "num_enum"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179"
+dependencies = [
+ "num_enum_derive",
+]
+
+[[package]]
+name = "num_enum_derive"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56"
+dependencies = [
+ "proc-macro-crate",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.79",
+]
+
+[[package]]
 name = "number_prefix"
 version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1959,6 +1981,15 @@ dependencies = [
 ]
 
 [[package]]
+name = "proc-macro-crate"
+version = "3.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b"
+dependencies = [
+ "toml_edit",
+]
+
+[[package]]
 name = "proc-macro2"
 version = "1.0.88"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2758,6 +2789,23 @@ dependencies = [
 ]
 
 [[package]]
+name = "toml_datetime"
+version = "0.6.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
+
+[[package]]
+name = "toml_edit"
+version = "0.22.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
+dependencies = [
+ "indexmap",
+ "toml_datetime",
+ "winnow",
+]
+
+[[package]]
 name = "tower-service"
 version = "0.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3046,6 +3094,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
 
 [[package]]
+name = "winnow"
+version = "0.6.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
 name = "xml-rs"
 version = "0.8.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/users/edef/crunch-v2/Cargo.nix b/users/edef/crunch-v2/Cargo.nix
index 6bd2be6b113c..502d2ea497cd 100644
--- a/users/edef/crunch-v2/Cargo.nix
+++ b/users/edef/crunch-v2/Cargo.nix
@@ -4142,6 +4142,10 @@ rec {
             packageId = "num-traits";
           }
           {
+            name = "num_enum";
+            packageId = "num_enum";
+          }
+          {
             name = "pin-project-lite";
             packageId = "pin-project-lite";
             optional = true;
@@ -4167,7 +4171,7 @@ rec {
             name = "tokio";
             packageId = "tokio";
             optional = true;
-            features = [ "io-util" "macros" ];
+            features = [ "io-util" "macros" "sync" ];
           }
           {
             name = "tracing";
@@ -4187,13 +4191,14 @@ rec {
         features = {
           "async" = [ "tokio" ];
           "bytes" = [ "dep:bytes" ];
-          "default" = [ "async" "wire" "nix-compat-derive" ];
+          "daemon" = [ "tokio" "nix-compat-derive" ];
+          "default" = [ "async" "daemon" "wire" "nix-compat-derive" ];
           "nix-compat-derive" = [ "dep:nix-compat-derive" ];
           "pin-project-lite" = [ "dep:pin-project-lite" ];
           "tokio" = [ "dep:tokio" ];
           "wire" = [ "tokio" "pin-project-lite" "bytes" ];
         };
-        resolvedDefaultFeatures = [ "async" "bytes" "default" "nix-compat-derive" "pin-project-lite" "tokio" "wire" ];
+        resolvedDefaultFeatures = [ "async" "bytes" "daemon" "default" "nix-compat-derive" "pin-project-lite" "tokio" "wire" ];
       };
       "nix-compat-derive" = rec {
         crateName = "nix-compat-derive";
@@ -4314,6 +4319,76 @@ rec {
         };
         resolvedDefaultFeatures = [ "default" "libm" "std" ];
       };
+      "num_enum" = rec {
+        crateName = "num_enum";
+        version = "0.7.3";
+        edition = "2021";
+        sha256 = "0yai0vafhy85mvhknzfqd7lm04hzaln7i5c599rhy8mj831kyqaf";
+        authors = [
+          "Daniel Wagner-Hall <dawagner@gmail.com>"
+          "Daniel Henry-Mantilla <daniel.henry.mantilla@gmail.com>"
+          "Vincent Esche <regexident@gmail.com>"
+        ];
+        dependencies = [
+          {
+            name = "num_enum_derive";
+            packageId = "num_enum_derive";
+            usesDefaultFeatures = false;
+          }
+        ];
+        features = {
+          "complex-expressions" = [ "num_enum_derive/complex-expressions" ];
+          "default" = [ "std" ];
+          "std" = [ "num_enum_derive/std" ];
+        };
+        resolvedDefaultFeatures = [ "default" "std" ];
+      };
+      "num_enum_derive" = rec {
+        crateName = "num_enum_derive";
+        version = "0.7.3";
+        edition = "2021";
+        sha256 = "0mksna1jj87ydh146gn6jcqkvvs920c3dgh0p4f3xk184kpl865g";
+        procMacro = true;
+        authors = [
+          "Daniel Wagner-Hall <dawagner@gmail.com>"
+          "Daniel Henry-Mantilla <daniel.henry.mantilla@gmail.com>"
+          "Vincent Esche <regexident@gmail.com>"
+        ];
+        dependencies = [
+          {
+            name = "proc-macro-crate";
+            packageId = "proc-macro-crate";
+            optional = true;
+          }
+          {
+            name = "proc-macro2";
+            packageId = "proc-macro2";
+          }
+          {
+            name = "quote";
+            packageId = "quote";
+          }
+          {
+            name = "syn";
+            packageId = "syn 2.0.79";
+            features = [ "parsing" ];
+          }
+        ];
+        devDependencies = [
+          {
+            name = "syn";
+            packageId = "syn 2.0.79";
+            features = [ "extra-traits" "parsing" ];
+          }
+        ];
+        features = {
+          "complex-expressions" = [ "syn/full" ];
+          "default" = [ "std" ];
+          "proc-macro-crate" = [ "dep:proc-macro-crate" ];
+          "std" = [ "proc-macro-crate" ];
+        };
+        resolvedDefaultFeatures = [ "proc-macro-crate" "std" ];
+      };
       "number_prefix" = rec {
         crateName = "number_prefix";
         version = "0.4.0";
@@ -6476,6 +6551,23 @@ rec {
           "verbatim" = [ "syn/parsing" ];
         };
       };
+      "proc-macro-crate" = rec {
+        crateName = "proc-macro-crate";
+        version = "3.2.0";
+        edition = "2021";
+        sha256 = "0yzsqnavb3lmrcsmbrdjfrky9vcbl46v59xi9avn0796rb3likwf";
+        libName = "proc_macro_crate";
+        authors = [
+          "Bastian Köcher <git@kchr.de>"
+        ];
+        dependencies = [
+          {
+            name = "toml_edit";
+            packageId = "toml_edit";
+          }
+        ];
+
+      };
       "proc-macro2" = rec {
         crateName = "proc-macro2";
         version = "1.0.88";
@@ -9062,6 +9154,51 @@ rec {
         };
         resolvedDefaultFeatures = [ "codec" "default" "io" "io-util" ];
       };
+      "toml_datetime" = rec {
+        crateName = "toml_datetime";
+        version = "0.6.8";
+        edition = "2021";
+        sha256 = "0hgv7v9g35d7y9r2afic58jvlwnf73vgd1mz2k8gihlgrf73bmqd";
+        authors = [
+          "Alex Crichton <alex@alexcrichton.com>"
+        ];
+        features = {
+          "serde" = [ "dep:serde" ];
+        };
+      };
+      "toml_edit" = rec {
+        crateName = "toml_edit";
+        version = "0.22.22";
+        edition = "2021";
+        sha256 = "1xf7sxfzmnc45f75x302qrn5aph52vc8w226v59yhrm211i8vr2a";
+        authors = [
+          "Andronik Ordian <write@reusable.software>"
+          "Ed Page <eopage@gmail.com>"
+        ];
+        dependencies = [
+          {
+            name = "indexmap";
+            packageId = "indexmap";
+            features = [ "std" ];
+          }
+          {
+            name = "toml_datetime";
+            packageId = "toml_datetime";
+          }
+          {
+            name = "winnow";
+            packageId = "winnow";
+            optional = true;
+          }
+        ];
+        features = {
+          "default" = [ "parse" "display" ];
+          "parse" = [ "dep:winnow" ];
+          "perf" = [ "dep:kstring" ];
+          "serde" = [ "dep:serde" "toml_datetime/serde" "dep:serde_spanned" ];
+        };
+        resolvedDefaultFeatures = [ "default" "display" "parse" ];
+      };
       "tower-service" = rec {
         crateName = "tower-service";
         version = "0.3.3";
@@ -10658,6 +10795,28 @@ rec {
         ];
 
       };
+      "winnow" = rec {
+        crateName = "winnow";
+        version = "0.6.20";
+        edition = "2021";
+        sha256 = "16y4i8z9vh8hazjxg5mvmq0c5i35wlk8rxi5gkq6cn5vlb0zxh9n";
+        dependencies = [
+          {
+            name = "memchr";
+            packageId = "memchr";
+            optional = true;
+            usesDefaultFeatures = false;
+          }
+        ];
+        features = {
+          "debug" = [ "std" "dep:anstream" "dep:anstyle" "dep:is-terminal" "dep:terminal_size" ];
+          "default" = [ "std" ];
+          "simd" = [ "dep:memchr" ];
+          "std" = [ "alloc" "memchr?/std" ];
+          "unstable-doc" = [ "alloc" "std" "simd" "unstable-recover" ];
+        };
+        resolvedDefaultFeatures = [ "alloc" "default" "std" ];
+      };
       "xml-rs" = rec {
         crateName = "xml-rs";
         version = "0.8.22";
diff --git a/users/edef/fetchroots/Cargo.lock b/users/edef/fetchroots/Cargo.lock
index 1229b886e4e8..3f6b463d8ec0 100644
--- a/users/edef/fetchroots/Cargo.lock
+++ b/users/edef/fetchroots/Cargo.lock
@@ -1319,6 +1319,12 @@ dependencies = [
 ]
 
 [[package]]
+name = "hashbrown"
+version = "0.15.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3"
+
+[[package]]
 name = "heck"
 version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1474,12 +1480,12 @@ dependencies = [
 
 [[package]]
 name = "indexmap"
-version = "2.2.3"
+version = "2.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177"
+checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
 dependencies = [
  "equivalent",
- "hashbrown",
+ "hashbrown 0.15.1",
 ]
 
 [[package]]
@@ -1693,6 +1699,7 @@ dependencies = [
  "nix-compat-derive",
  "nom",
  "num-traits",
+ "num_enum",
  "pin-project-lite",
  "serde",
  "serde_json",
@@ -1765,6 +1772,27 @@ dependencies = [
 ]
 
 [[package]]
+name = "num_enum"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179"
+dependencies = [
+ "num_enum_derive",
+]
+
+[[package]]
+name = "num_enum_derive"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56"
+dependencies = [
+ "proc-macro-crate",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.79",
+]
+
+[[package]]
 name = "number_prefix"
 version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1934,7 +1962,7 @@ dependencies = [
  "foreign_vec",
  "futures",
  "getrandom",
- "hashbrown",
+ "hashbrown 0.14.3",
  "itoa",
  "lz4",
  "multiversion",
@@ -1974,7 +2002,7 @@ dependencies = [
  "chrono",
  "comfy-table",
  "either",
- "hashbrown",
+ "hashbrown 0.14.3",
  "indexmap",
  "num-traits",
  "once_cell",
@@ -2073,7 +2101,7 @@ dependencies = [
  "argminmax",
  "bytemuck",
  "either",
- "hashbrown",
+ "hashbrown 0.14.3",
  "indexmap",
  "memchr",
  "num-traits",
@@ -2123,7 +2151,7 @@ dependencies = [
  "crossbeam-channel",
  "crossbeam-queue",
  "enum_dispatch",
- "hashbrown",
+ "hashbrown 0.14.3",
  "num-traits",
  "polars-arrow",
  "polars-compute",
@@ -2217,7 +2245,7 @@ checksum = "b174ca4a77ad47d7b91a0460aaae65bbf874c8bfbaaa5308675dadef3976bbda"
 dependencies = [
  "ahash",
  "bytemuck",
- "hashbrown",
+ "hashbrown 0.14.3",
  "indexmap",
  "num-traits",
  "once_cell",
@@ -2247,6 +2275,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
 
 [[package]]
+name = "proc-macro-crate"
+version = "3.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b"
+dependencies = [
+ "toml_edit",
+]
+
+[[package]]
 name = "proc-macro2"
 version = "1.0.88"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2915,6 +2952,23 @@ dependencies = [
 ]
 
 [[package]]
+name = "toml_datetime"
+version = "0.6.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
+
+[[package]]
+name = "toml_edit"
+version = "0.22.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
+dependencies = [
+ "indexmap",
+ "toml_datetime",
+ "winnow",
+]
+
+[[package]]
 name = "tower-service"
 version = "0.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3265,6 +3319,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0770833d60a970638e989b3fa9fd2bb1aaadcf88963d1659fd7d9990196ed2d6"
 
 [[package]]
+name = "winnow"
+version = "0.6.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
 name = "xmlparser"
 version = "0.13.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/users/edef/fetchroots/Cargo.nix b/users/edef/fetchroots/Cargo.nix
index f45fc85d6e55..8049acaadc71 100644
--- a/users/edef/fetchroots/Cargo.nix
+++ b/users/edef/fetchroots/Cargo.nix
@@ -4372,7 +4372,7 @@ rec {
         ];
         features = { };
       };
-      "hashbrown" = rec {
+      "hashbrown 0.14.3" = rec {
         crateName = "hashbrown";
         version = "0.14.3";
         edition = "2021";
@@ -4420,7 +4420,29 @@ rec {
           "rustc-dep-of-std" = [ "nightly" "core" "compiler_builtins" "alloc" "rustc-internal-api" ];
           "serde" = [ "dep:serde" ];
         };
-        resolvedDefaultFeatures = [ "ahash" "allocator-api2" "default" "inline-more" "raw" "rayon" ];
+        resolvedDefaultFeatures = [ "ahash" "allocator-api2" "default" "inline-more" "rayon" ];
+      };
+      "hashbrown 0.15.1" = rec {
+        crateName = "hashbrown";
+        version = "0.15.1";
+        edition = "2021";
+        sha256 = "1czsvasi3azv2079fcvbhvpisa16w6fi1mfk8zm2c5wbyqdgr6rs";
+        authors = [
+          "Amanieu d'Antras <amanieu@gmail.com>"
+        ];
+        features = {
+          "alloc" = [ "dep:alloc" ];
+          "allocator-api2" = [ "dep:allocator-api2" ];
+          "compiler_builtins" = [ "dep:compiler_builtins" ];
+          "core" = [ "dep:core" ];
+          "default" = [ "default-hasher" "inline-more" "allocator-api2" "equivalent" "raw-entry" ];
+          "default-hasher" = [ "dep:foldhash" ];
+          "equivalent" = [ "dep:equivalent" ];
+          "nightly" = [ "allocator-api2?/nightly" "bumpalo/allocator_api" ];
+          "rayon" = [ "dep:rayon" ];
+          "rustc-dep-of-std" = [ "nightly" "core" "compiler_builtins" "alloc" "rustc-internal-api" "raw-entry" ];
+          "serde" = [ "dep:serde" ];
+        };
       };
       "heck" = rec {
         crateName = "heck";
@@ -4898,9 +4920,9 @@ rec {
       };
       "indexmap" = rec {
         crateName = "indexmap";
-        version = "2.2.3";
+        version = "2.6.0";
         edition = "2021";
-        sha256 = "0xy1wcad2da199f6y0mwmx9scw7glgs1n2g4m8nfln7hcf8g6g13";
+        sha256 = "1nmrwn8lbs19gkvhxaawffzbvrpyrb5y3drcrr645x957kz0fybh";
         dependencies = [
           {
             name = "equivalent";
@@ -4909,13 +4931,13 @@ rec {
           }
           {
             name = "hashbrown";
-            packageId = "hashbrown";
+            packageId = "hashbrown 0.15.1";
             usesDefaultFeatures = false;
-            features = [ "raw" ];
           }
         ];
         features = {
           "arbitrary" = [ "dep:arbitrary" ];
+          "borsh" = [ "dep:borsh" ];
           "default" = [ "std" ];
           "quickcheck" = [ "dep:quickcheck" ];
           "rayon" = [ "dep:rayon" ];
@@ -5522,6 +5544,10 @@ rec {
             packageId = "num-traits";
           }
           {
+            name = "num_enum";
+            packageId = "num_enum";
+          }
+          {
             name = "pin-project-lite";
             packageId = "pin-project-lite";
             optional = true;
@@ -5547,7 +5573,7 @@ rec {
             name = "tokio";
             packageId = "tokio";
             optional = true;
-            features = [ "io-util" "macros" ];
+            features = [ "io-util" "macros" "sync" ];
           }
           {
             name = "tracing";
@@ -5567,13 +5593,14 @@ rec {
         features = {
           "async" = [ "tokio" ];
           "bytes" = [ "dep:bytes" ];
-          "default" = [ "async" "wire" "nix-compat-derive" ];
+          "daemon" = [ "tokio" "nix-compat-derive" ];
+          "default" = [ "async" "daemon" "wire" "nix-compat-derive" ];
           "nix-compat-derive" = [ "dep:nix-compat-derive" ];
           "pin-project-lite" = [ "dep:pin-project-lite" ];
           "tokio" = [ "dep:tokio" ];
           "wire" = [ "tokio" "pin-project-lite" "bytes" ];
         };
-        resolvedDefaultFeatures = [ "async" "bytes" "default" "nix-compat-derive" "pin-project-lite" "tokio" "wire" ];
+        resolvedDefaultFeatures = [ "async" "bytes" "daemon" "default" "nix-compat-derive" "pin-project-lite" "tokio" "wire" ];
       };
       "nix-compat-derive" = rec {
         crateName = "nix-compat-derive";
@@ -5728,6 +5755,76 @@ rec {
         };
         resolvedDefaultFeatures = [ "default" "i128" "libm" "std" ];
       };
+      "num_enum" = rec {
+        crateName = "num_enum";
+        version = "0.7.3";
+        edition = "2021";
+        sha256 = "0yai0vafhy85mvhknzfqd7lm04hzaln7i5c599rhy8mj831kyqaf";
+        authors = [
+          "Daniel Wagner-Hall <dawagner@gmail.com>"
+          "Daniel Henry-Mantilla <daniel.henry.mantilla@gmail.com>"
+          "Vincent Esche <regexident@gmail.com>"
+        ];
+        dependencies = [
+          {
+            name = "num_enum_derive";
+            packageId = "num_enum_derive";
+            usesDefaultFeatures = false;
+          }
+        ];
+        features = {
+          "complex-expressions" = [ "num_enum_derive/complex-expressions" ];
+          "default" = [ "std" ];
+          "std" = [ "num_enum_derive/std" ];
+        };
+        resolvedDefaultFeatures = [ "default" "std" ];
+      };
+      "num_enum_derive" = rec {
+        crateName = "num_enum_derive";
+        version = "0.7.3";
+        edition = "2021";
+        sha256 = "0mksna1jj87ydh146gn6jcqkvvs920c3dgh0p4f3xk184kpl865g";
+        procMacro = true;
+        authors = [
+          "Daniel Wagner-Hall <dawagner@gmail.com>"
+          "Daniel Henry-Mantilla <daniel.henry.mantilla@gmail.com>"
+          "Vincent Esche <regexident@gmail.com>"
+        ];
+        dependencies = [
+          {
+            name = "proc-macro-crate";
+            packageId = "proc-macro-crate";
+            optional = true;
+          }
+          {
+            name = "proc-macro2";
+            packageId = "proc-macro2";
+          }
+          {
+            name = "quote";
+            packageId = "quote";
+          }
+          {
+            name = "syn";
+            packageId = "syn 2.0.79";
+            features = [ "parsing" ];
+          }
+        ];
+        devDependencies = [
+          {
+            name = "syn";
+            packageId = "syn 2.0.79";
+            features = [ "extra-traits" "parsing" ];
+          }
+        ];
+        features = {
+          "complex-expressions" = [ "syn/full" ];
+          "default" = [ "std" ];
+          "proc-macro-crate" = [ "dep:proc-macro-crate" ];
+          "std" = [ "proc-macro-crate" ];
+        };
+        resolvedDefaultFeatures = [ "proc-macro-crate" "std" ];
+      };
       "number_prefix" = rec {
         crateName = "number_prefix";
         version = "0.4.0";
@@ -6387,7 +6484,7 @@ rec {
           }
           {
             name = "hashbrown";
-            packageId = "hashbrown";
+            packageId = "hashbrown 0.14.3";
             features = [ "rayon" "ahash" ];
           }
           {
@@ -6576,7 +6673,7 @@ rec {
           }
           {
             name = "hashbrown";
-            packageId = "hashbrown";
+            packageId = "hashbrown 0.14.3";
             features = [ "rayon" "ahash" ];
           }
           {
@@ -7155,7 +7252,7 @@ rec {
           }
           {
             name = "hashbrown";
-            packageId = "hashbrown";
+            packageId = "hashbrown 0.14.3";
             features = [ "rayon" "ahash" ];
           }
           {
@@ -7421,7 +7518,7 @@ rec {
           }
           {
             name = "hashbrown";
-            packageId = "hashbrown";
+            packageId = "hashbrown 0.14.3";
             features = [ "rayon" "ahash" ];
           }
           {
@@ -7895,7 +7992,7 @@ rec {
           }
           {
             name = "hashbrown";
-            packageId = "hashbrown";
+            packageId = "hashbrown 0.14.3";
             features = [ "rayon" "ahash" ];
           }
           {
@@ -7983,6 +8080,23 @@ rec {
         };
         resolvedDefaultFeatures = [ "simd" "std" ];
       };
+      "proc-macro-crate" = rec {
+        crateName = "proc-macro-crate";
+        version = "3.2.0";
+        edition = "2021";
+        sha256 = "0yzsqnavb3lmrcsmbrdjfrky9vcbl46v59xi9avn0796rb3likwf";
+        libName = "proc_macro_crate";
+        authors = [
+          "Bastian Köcher <git@kchr.de>"
+        ];
+        dependencies = [
+          {
+            name = "toml_edit";
+            packageId = "toml_edit";
+          }
+        ];
+
+      };
       "proc-macro2" = rec {
         crateName = "proc-macro2";
         version = "1.0.88";
@@ -10009,6 +10123,51 @@ rec {
         };
         resolvedDefaultFeatures = [ "codec" "default" "io" "io-util" "tracing" ];
       };
+      "toml_datetime" = rec {
+        crateName = "toml_datetime";
+        version = "0.6.8";
+        edition = "2021";
+        sha256 = "0hgv7v9g35d7y9r2afic58jvlwnf73vgd1mz2k8gihlgrf73bmqd";
+        authors = [
+          "Alex Crichton <alex@alexcrichton.com>"
+        ];
+        features = {
+          "serde" = [ "dep:serde" ];
+        };
+      };
+      "toml_edit" = rec {
+        crateName = "toml_edit";
+        version = "0.22.22";
+        edition = "2021";
+        sha256 = "1xf7sxfzmnc45f75x302qrn5aph52vc8w226v59yhrm211i8vr2a";
+        authors = [
+          "Andronik Ordian <write@reusable.software>"
+          "Ed Page <eopage@gmail.com>"
+        ];
+        dependencies = [
+          {
+            name = "indexmap";
+            packageId = "indexmap";
+            features = [ "std" ];
+          }
+          {
+            name = "toml_datetime";
+            packageId = "toml_datetime";
+          }
+          {
+            name = "winnow";
+            packageId = "winnow";
+            optional = true;
+          }
+        ];
+        features = {
+          "default" = [ "parse" "display" ];
+          "parse" = [ "dep:winnow" ];
+          "perf" = [ "dep:kstring" ];
+          "serde" = [ "dep:serde" "toml_datetime/serde" "dep:serde_spanned" ];
+        };
+        resolvedDefaultFeatures = [ "default" "display" "parse" ];
+      };
       "tower-service" = rec {
         crateName = "tower-service";
         version = "0.3.2";
@@ -11726,6 +11885,28 @@ rec {
         ];
 
       };
+      "winnow" = rec {
+        crateName = "winnow";
+        version = "0.6.20";
+        edition = "2021";
+        sha256 = "16y4i8z9vh8hazjxg5mvmq0c5i35wlk8rxi5gkq6cn5vlb0zxh9n";
+        dependencies = [
+          {
+            name = "memchr";
+            packageId = "memchr";
+            optional = true;
+            usesDefaultFeatures = false;
+          }
+        ];
+        features = {
+          "debug" = [ "std" "dep:anstream" "dep:anstyle" "dep:is-terminal" "dep:terminal_size" ];
+          "default" = [ "std" ];
+          "simd" = [ "dep:memchr" ];
+          "std" = [ "alloc" "memchr?/std" ];
+          "unstable-doc" = [ "alloc" "std" "simd" "unstable-recover" ];
+        };
+        resolvedDefaultFeatures = [ "alloc" "default" "std" ];
+      };
       "xmlparser" = rec {
         crateName = "xmlparser";
         version = "0.13.6";
diff --git a/users/edef/narinfo2parquet/Cargo.lock b/users/edef/narinfo2parquet/Cargo.lock
index 97a7ea712433..7ebfe1350278 100644
--- a/users/edef/narinfo2parquet/Cargo.lock
+++ b/users/edef/narinfo2parquet/Cargo.lock
@@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
 
 [[package]]
 name = "ahash"
-version = "0.8.6"
+version = "0.8.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a"
+checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
 dependencies = [
  "cfg-if",
  "getrandom",
@@ -696,9 +696,9 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
 
 [[package]]
 name = "hashbrown"
-version = "0.14.2"
+version = "0.14.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156"
+checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
 dependencies = [
  "ahash",
  "allocator-api2",
@@ -706,6 +706,12 @@ dependencies = [
 ]
 
 [[package]]
+name = "hashbrown"
+version = "0.15.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3"
+
+[[package]]
 name = "heck"
 version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -751,12 +757,12 @@ dependencies = [
 
 [[package]]
 name = "indexmap"
-version = "2.1.0"
+version = "2.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
+checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
 dependencies = [
  "equivalent",
- "hashbrown",
+ "hashbrown 0.15.1",
 ]
 
 [[package]]
@@ -944,6 +950,7 @@ name = "narinfo2parquet"
 version = "0.1.0"
 dependencies = [
  "anyhow",
+ "hashbrown 0.14.5",
  "jemallocator",
  "nix-compat",
  "polars",
@@ -967,6 +974,7 @@ dependencies = [
  "nix-compat-derive",
  "nom",
  "num-traits",
+ "num_enum",
  "pin-project-lite",
  "serde",
  "serde_json",
@@ -1024,6 +1032,27 @@ dependencies = [
 ]
 
 [[package]]
+name = "num_enum"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179"
+dependencies = [
+ "num_enum_derive",
+]
+
+[[package]]
+name = "num_enum_derive"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56"
+dependencies = [
+ "proc-macro-crate",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.79",
+]
+
+[[package]]
 name = "object"
 version = "0.32.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1124,7 +1153,7 @@ dependencies = [
  "foreign_vec",
  "futures",
  "getrandom",
- "hashbrown",
+ "hashbrown 0.14.5",
  "itoa",
  "lz4",
  "multiversion",
@@ -1163,7 +1192,7 @@ dependencies = [
  "bytemuck",
  "chrono",
  "either",
- "hashbrown",
+ "hashbrown 0.14.5",
  "indexmap",
  "num-traits",
  "once_cell",
@@ -1255,7 +1284,7 @@ dependencies = [
  "argminmax",
  "bytemuck",
  "either",
- "hashbrown",
+ "hashbrown 0.14.5",
  "indexmap",
  "memchr",
  "num-traits",
@@ -1305,7 +1334,7 @@ dependencies = [
  "crossbeam-channel",
  "crossbeam-queue",
  "enum_dispatch",
- "hashbrown",
+ "hashbrown 0.14.5",
  "num-traits",
  "polars-arrow",
  "polars-compute",
@@ -1399,7 +1428,7 @@ checksum = "b174ca4a77ad47d7b91a0460aaae65bbf874c8bfbaaa5308675dadef3976bbda"
 dependencies = [
  "ahash",
  "bytemuck",
- "hashbrown",
+ "hashbrown 0.14.5",
  "indexmap",
  "num-traits",
  "once_cell",
@@ -1417,6 +1446,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
 
 [[package]]
+name = "proc-macro-crate"
+version = "3.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b"
+dependencies = [
+ "toml_edit",
+]
+
+[[package]]
 name = "proc-macro2"
 version = "1.0.87"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1875,6 +1913,23 @@ dependencies = [
 ]
 
 [[package]]
+name = "toml_datetime"
+version = "0.6.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
+
+[[package]]
+name = "toml_edit"
+version = "0.22.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
+dependencies = [
+ "indexmap",
+ "toml_datetime",
+ "winnow",
+]
+
+[[package]]
 name = "tracing"
 version = "0.1.40"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2166,6 +2221,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
 
 [[package]]
+name = "winnow"
+version = "0.6.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
 name = "xxhash-rust"
 version = "0.8.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/users/edef/narinfo2parquet/Cargo.nix b/users/edef/narinfo2parquet/Cargo.nix
index fb8b59b2dea2..05ce99a9029c 100644
--- a/users/edef/narinfo2parquet/Cargo.nix
+++ b/users/edef/narinfo2parquet/Cargo.nix
@@ -129,9 +129,9 @@ rec {
       };
       "ahash" = rec {
         crateName = "ahash";
-        version = "0.8.6";
+        version = "0.8.11";
         edition = "2018";
-        sha256 = "0yn9i8nc6mmv28ig9w3dga571q09vg9f1f650mi5z8phx42r6hli";
+        sha256 = "04chdfkls5xmhp1d48gnjsmglbqibizs3bpbj6rsj604m10si7g8";
         authors = [
           "Tom Kaitchuck <Tom.Kaitchuck@gmail.com>"
         ];
@@ -150,7 +150,7 @@ rec {
             packageId = "once_cell";
             usesDefaultFeatures = false;
             target = { target, features }: (!(("arm" == target."arch" or null) && ("none" == target."os" or null)));
-            features = [ "unstable" "alloc" ];
+            features = [ "alloc" ];
           }
           {
             name = "zerocopy";
@@ -2062,11 +2062,11 @@ rec {
         ];
 
       };
-      "hashbrown" = rec {
+      "hashbrown 0.14.5" = rec {
         crateName = "hashbrown";
-        version = "0.14.2";
+        version = "0.14.5";
         edition = "2021";
-        sha256 = "0mj1x1d16acxf4zg7wr7q2x8pgzfi1bzpifygcsxmg4d2n972gpr";
+        sha256 = "1wa1vy1xs3mp11bn3z9dv0jricgr6a2j0zkf1g19yz3vw4il89z5";
         authors = [
           "Amanieu d'Antras <amanieu@gmail.com>"
         ];
@@ -2112,6 +2112,28 @@ rec {
         };
         resolvedDefaultFeatures = [ "ahash" "allocator-api2" "default" "inline-more" "raw" "rayon" ];
       };
+      "hashbrown 0.15.1" = rec {
+        crateName = "hashbrown";
+        version = "0.15.1";
+        edition = "2021";
+        sha256 = "1czsvasi3azv2079fcvbhvpisa16w6fi1mfk8zm2c5wbyqdgr6rs";
+        authors = [
+          "Amanieu d'Antras <amanieu@gmail.com>"
+        ];
+        features = {
+          "alloc" = [ "dep:alloc" ];
+          "allocator-api2" = [ "dep:allocator-api2" ];
+          "compiler_builtins" = [ "dep:compiler_builtins" ];
+          "core" = [ "dep:core" ];
+          "default" = [ "default-hasher" "inline-more" "allocator-api2" "equivalent" "raw-entry" ];
+          "default-hasher" = [ "dep:foldhash" ];
+          "equivalent" = [ "dep:equivalent" ];
+          "nightly" = [ "allocator-api2?/nightly" "bumpalo/allocator_api" ];
+          "rayon" = [ "dep:rayon" ];
+          "rustc-dep-of-std" = [ "nightly" "core" "compiler_builtins" "alloc" "rustc-internal-api" "raw-entry" ];
+          "serde" = [ "dep:serde" ];
+        };
+      };
       "heck" = rec {
         crateName = "heck";
         version = "0.4.1";
@@ -2226,9 +2248,9 @@ rec {
       };
       "indexmap" = rec {
         crateName = "indexmap";
-        version = "2.1.0";
+        version = "2.6.0";
         edition = "2021";
-        sha256 = "07rxrqmryr1xfnmhrjlz8ic6jw28v6h5cig3ws2c9d0wifhy2c6m";
+        sha256 = "1nmrwn8lbs19gkvhxaawffzbvrpyrb5y3drcrr645x957kz0fybh";
         dependencies = [
           {
             name = "equivalent";
@@ -2237,13 +2259,13 @@ rec {
           }
           {
             name = "hashbrown";
-            packageId = "hashbrown";
+            packageId = "hashbrown 0.15.1";
             usesDefaultFeatures = false;
-            features = [ "raw" ];
           }
         ];
         features = {
           "arbitrary" = [ "dep:arbitrary" ];
+          "borsh" = [ "dep:borsh" ];
           "default" = [ "std" ];
           "quickcheck" = [ "dep:quickcheck" ];
           "rayon" = [ "dep:rayon" ];
@@ -2757,6 +2779,11 @@ rec {
             features = [ "backtrace" ];
           }
           {
+            name = "hashbrown";
+            packageId = "hashbrown 0.14.5";
+            features = [ "raw" ];
+          }
+          {
             name = "jemallocator";
             packageId = "jemallocator";
           }
@@ -2841,6 +2868,10 @@ rec {
             packageId = "num-traits";
           }
           {
+            name = "num_enum";
+            packageId = "num_enum";
+          }
+          {
             name = "pin-project-lite";
             packageId = "pin-project-lite";
             optional = true;
@@ -2866,7 +2897,7 @@ rec {
             name = "tokio";
             packageId = "tokio";
             optional = true;
-            features = [ "io-util" "macros" ];
+            features = [ "io-util" "macros" "sync" ];
           }
           {
             name = "tracing";
@@ -2886,13 +2917,14 @@ rec {
         features = {
           "async" = [ "tokio" ];
           "bytes" = [ "dep:bytes" ];
-          "default" = [ "async" "wire" "nix-compat-derive" ];
+          "daemon" = [ "tokio" "nix-compat-derive" ];
+          "default" = [ "async" "daemon" "wire" "nix-compat-derive" ];
           "nix-compat-derive" = [ "dep:nix-compat-derive" ];
           "pin-project-lite" = [ "dep:pin-project-lite" ];
           "tokio" = [ "dep:tokio" ];
           "wire" = [ "tokio" "pin-project-lite" "bytes" ];
         };
-        resolvedDefaultFeatures = [ "async" "bytes" "default" "nix-compat-derive" "pin-project-lite" "tokio" "wire" ];
+        resolvedDefaultFeatures = [ "async" "bytes" "daemon" "default" "nix-compat-derive" "pin-project-lite" "tokio" "wire" ];
       };
       "nix-compat-derive" = rec {
         crateName = "nix-compat-derive";
@@ -3013,6 +3045,76 @@ rec {
         };
         resolvedDefaultFeatures = [ "default" "libm" "std" ];
       };
+      "num_enum" = rec {
+        crateName = "num_enum";
+        version = "0.7.3";
+        edition = "2021";
+        sha256 = "0yai0vafhy85mvhknzfqd7lm04hzaln7i5c599rhy8mj831kyqaf";
+        authors = [
+          "Daniel Wagner-Hall <dawagner@gmail.com>"
+          "Daniel Henry-Mantilla <daniel.henry.mantilla@gmail.com>"
+          "Vincent Esche <regexident@gmail.com>"
+        ];
+        dependencies = [
+          {
+            name = "num_enum_derive";
+            packageId = "num_enum_derive";
+            usesDefaultFeatures = false;
+          }
+        ];
+        features = {
+          "complex-expressions" = [ "num_enum_derive/complex-expressions" ];
+          "default" = [ "std" ];
+          "std" = [ "num_enum_derive/std" ];
+        };
+        resolvedDefaultFeatures = [ "default" "std" ];
+      };
+      "num_enum_derive" = rec {
+        crateName = "num_enum_derive";
+        version = "0.7.3";
+        edition = "2021";
+        sha256 = "0mksna1jj87ydh146gn6jcqkvvs920c3dgh0p4f3xk184kpl865g";
+        procMacro = true;
+        authors = [
+          "Daniel Wagner-Hall <dawagner@gmail.com>"
+          "Daniel Henry-Mantilla <daniel.henry.mantilla@gmail.com>"
+          "Vincent Esche <regexident@gmail.com>"
+        ];
+        dependencies = [
+          {
+            name = "proc-macro-crate";
+            packageId = "proc-macro-crate";
+            optional = true;
+          }
+          {
+            name = "proc-macro2";
+            packageId = "proc-macro2";
+          }
+          {
+            name = "quote";
+            packageId = "quote";
+          }
+          {
+            name = "syn";
+            packageId = "syn 2.0.79";
+            features = [ "parsing" ];
+          }
+        ];
+        devDependencies = [
+          {
+            name = "syn";
+            packageId = "syn 2.0.79";
+            features = [ "extra-traits" "parsing" ];
+          }
+        ];
+        features = {
+          "complex-expressions" = [ "syn/full" ];
+          "default" = [ "std" ];
+          "proc-macro-crate" = [ "dep:proc-macro-crate" ];
+          "std" = [ "proc-macro-crate" ];
+        };
+        resolvedDefaultFeatures = [ "proc-macro-crate" "std" ];
+      };
       "object" = rec {
         crateName = "object";
         version = "0.32.1";
@@ -3061,7 +3163,7 @@ rec {
           "parking_lot" = [ "dep:parking_lot_core" ];
           "std" = [ "alloc" ];
         };
-        resolvedDefaultFeatures = [ "alloc" "default" "race" "std" "unstable" ];
+        resolvedDefaultFeatures = [ "alloc" "default" "race" "std" ];
       };
       "parquet-format-safe" = rec {
         crateName = "parquet-format-safe";
@@ -3455,7 +3557,7 @@ rec {
           }
           {
             name = "hashbrown";
-            packageId = "hashbrown";
+            packageId = "hashbrown 0.14.5";
             features = [ "rayon" "ahash" ];
           }
           {
@@ -3638,7 +3740,7 @@ rec {
           }
           {
             name = "hashbrown";
-            packageId = "hashbrown";
+            packageId = "hashbrown 0.14.5";
             features = [ "rayon" "ahash" ];
           }
           {
@@ -4179,7 +4281,7 @@ rec {
           }
           {
             name = "hashbrown";
-            packageId = "hashbrown";
+            packageId = "hashbrown 0.14.5";
             features = [ "rayon" "ahash" ];
           }
           {
@@ -4445,7 +4547,7 @@ rec {
           }
           {
             name = "hashbrown";
-            packageId = "hashbrown";
+            packageId = "hashbrown 0.14.5";
             features = [ "rayon" "ahash" ];
           }
           {
@@ -4919,7 +5021,7 @@ rec {
           }
           {
             name = "hashbrown";
-            packageId = "hashbrown";
+            packageId = "hashbrown 0.14.5";
             features = [ "rayon" "ahash" ];
           }
           {
@@ -4980,6 +5082,23 @@ rec {
         };
         resolvedDefaultFeatures = [ "simd" "std" ];
       };
+      "proc-macro-crate" = rec {
+        crateName = "proc-macro-crate";
+        version = "3.2.0";
+        edition = "2021";
+        sha256 = "0yzsqnavb3lmrcsmbrdjfrky9vcbl46v59xi9avn0796rb3likwf";
+        libName = "proc_macro_crate";
+        authors = [
+          "Bastian Köcher <git@kchr.de>"
+        ];
+        dependencies = [
+          {
+            name = "toml_edit";
+            packageId = "toml_edit";
+          }
+        ];
+
+      };
       "proc-macro2" = rec {
         crateName = "proc-macro2";
         version = "1.0.87";
@@ -6395,6 +6514,51 @@ rec {
         };
         resolvedDefaultFeatures = [ "default" "io" "io-util" ];
       };
+      "toml_datetime" = rec {
+        crateName = "toml_datetime";
+        version = "0.6.8";
+        edition = "2021";
+        sha256 = "0hgv7v9g35d7y9r2afic58jvlwnf73vgd1mz2k8gihlgrf73bmqd";
+        authors = [
+          "Alex Crichton <alex@alexcrichton.com>"
+        ];
+        features = {
+          "serde" = [ "dep:serde" ];
+        };
+      };
+      "toml_edit" = rec {
+        crateName = "toml_edit";
+        version = "0.22.22";
+        edition = "2021";
+        sha256 = "1xf7sxfzmnc45f75x302qrn5aph52vc8w226v59yhrm211i8vr2a";
+        authors = [
+          "Andronik Ordian <write@reusable.software>"
+          "Ed Page <eopage@gmail.com>"
+        ];
+        dependencies = [
+          {
+            name = "indexmap";
+            packageId = "indexmap";
+            features = [ "std" ];
+          }
+          {
+            name = "toml_datetime";
+            packageId = "toml_datetime";
+          }
+          {
+            name = "winnow";
+            packageId = "winnow";
+            optional = true;
+          }
+        ];
+        features = {
+          "default" = [ "parse" "display" ];
+          "parse" = [ "dep:winnow" ];
+          "perf" = [ "dep:kstring" ];
+          "serde" = [ "dep:serde" "toml_datetime/serde" "dep:serde_spanned" ];
+        };
+        resolvedDefaultFeatures = [ "default" "display" "parse" ];
+      };
       "tracing" = rec {
         crateName = "tracing";
         version = "0.1.40";
@@ -8233,6 +8397,28 @@ rec {
         ];
 
       };
+      "winnow" = rec {
+        crateName = "winnow";
+        version = "0.6.20";
+        edition = "2021";
+        sha256 = "16y4i8z9vh8hazjxg5mvmq0c5i35wlk8rxi5gkq6cn5vlb0zxh9n";
+        dependencies = [
+          {
+            name = "memchr";
+            packageId = "memchr";
+            optional = true;
+            usesDefaultFeatures = false;
+          }
+        ];
+        features = {
+          "debug" = [ "std" "dep:anstream" "dep:anstyle" "dep:is-terminal" "dep:terminal_size" ];
+          "default" = [ "std" ];
+          "simd" = [ "dep:memchr" ];
+          "std" = [ "alloc" "memchr?/std" ];
+          "unstable-doc" = [ "alloc" "std" "simd" "unstable-recover" ];
+        };
+        resolvedDefaultFeatures = [ "alloc" "default" "std" ];
+      };
       "xxhash-rust" = rec {
         crateName = "xxhash-rust";
         version = "0.8.7";
diff --git a/users/edef/narinfo2parquet/Cargo.toml b/users/edef/narinfo2parquet/Cargo.toml
index 40d721d28cef..5a8c9bdbfa15 100644
--- a/users/edef/narinfo2parquet/Cargo.toml
+++ b/users/edef/narinfo2parquet/Cargo.toml
@@ -15,6 +15,9 @@ nix-compat = { version = "0.1.0", path = "../../../tvix/nix-compat" }
 tempfile-fast = "0.3.4"
 zstd = "0.13.0"
 
+# See https://github.com/pola-rs/polars/issues/19157
+hashbrown = { version = "0.14.5", features = ["raw"] }
+
 [dependencies.polars]
 version = "0.36.2"
 default-features = false
diff --git a/users/edef/weave/Cargo.lock b/users/edef/weave/Cargo.lock
index 734f12d4e699..192b029683ef 100644
--- a/users/edef/weave/Cargo.lock
+++ b/users/edef/weave/Cargo.lock
@@ -1013,6 +1013,7 @@ dependencies = [
  "nix-compat-derive",
  "nom",
  "num-traits",
+ "num_enum",
  "pin-project-lite",
  "serde",
  "serde_json",
@@ -1080,6 +1081,27 @@ dependencies = [
 ]
 
 [[package]]
+name = "num_enum"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179"
+dependencies = [
+ "num_enum_derive",
+]
+
+[[package]]
+name = "num_enum_derive"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56"
+dependencies = [
+ "proc-macro-crate",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.79",
+]
+
+[[package]]
 name = "number_prefix"
 version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1526,6 +1548,15 @@ dependencies = [
 ]
 
 [[package]]
+name = "proc-macro-crate"
+version = "3.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b"
+dependencies = [
+ "toml_edit",
+]
+
+[[package]]
 name = "proc-macro2"
 version = "1.0.87"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2034,6 +2065,23 @@ dependencies = [
 ]
 
 [[package]]
+name = "toml_datetime"
+version = "0.6.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
+
+[[package]]
+name = "toml_edit"
+version = "0.22.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
+dependencies = [
+ "indexmap",
+ "toml_datetime",
+ "winnow",
+]
+
+[[package]]
 name = "tracing"
 version = "0.1.40"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2379,6 +2427,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
 
 [[package]]
+name = "winnow"
+version = "0.6.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
 name = "xxhash-rust"
 version = "0.8.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/users/edef/weave/Cargo.nix b/users/edef/weave/Cargo.nix
index b10bdfb7688c..61f7170d050d 100644
--- a/users/edef/weave/Cargo.nix
+++ b/users/edef/weave/Cargo.nix
@@ -2951,6 +2951,10 @@ rec {
             packageId = "num-traits";
           }
           {
+            name = "num_enum";
+            packageId = "num_enum";
+          }
+          {
             name = "pin-project-lite";
             packageId = "pin-project-lite";
             optional = true;
@@ -2976,7 +2980,7 @@ rec {
             name = "tokio";
             packageId = "tokio";
             optional = true;
-            features = [ "io-util" "macros" ];
+            features = [ "io-util" "macros" "sync" ];
           }
           {
             name = "tracing";
@@ -2996,13 +3000,14 @@ rec {
         features = {
           "async" = [ "tokio" ];
           "bytes" = [ "dep:bytes" ];
-          "default" = [ "async" "wire" "nix-compat-derive" ];
+          "daemon" = [ "tokio" "nix-compat-derive" ];
+          "default" = [ "async" "daemon" "wire" "nix-compat-derive" ];
           "nix-compat-derive" = [ "dep:nix-compat-derive" ];
           "pin-project-lite" = [ "dep:pin-project-lite" ];
           "tokio" = [ "dep:tokio" ];
           "wire" = [ "tokio" "pin-project-lite" "bytes" ];
         };
-        resolvedDefaultFeatures = [ "async" "bytes" "default" "nix-compat-derive" "pin-project-lite" "tokio" "wire" ];
+        resolvedDefaultFeatures = [ "async" "bytes" "daemon" "default" "nix-compat-derive" "pin-project-lite" "tokio" "wire" ];
       };
       "nix-compat-derive" = rec {
         crateName = "nix-compat-derive";
@@ -3152,6 +3157,76 @@ rec {
         };
         resolvedDefaultFeatures = [ "default" "libm" "std" ];
       };
+      "num_enum" = rec {
+        crateName = "num_enum";
+        version = "0.7.3";
+        edition = "2021";
+        sha256 = "0yai0vafhy85mvhknzfqd7lm04hzaln7i5c599rhy8mj831kyqaf";
+        authors = [
+          "Daniel Wagner-Hall <dawagner@gmail.com>"
+          "Daniel Henry-Mantilla <daniel.henry.mantilla@gmail.com>"
+          "Vincent Esche <regexident@gmail.com>"
+        ];
+        dependencies = [
+          {
+            name = "num_enum_derive";
+            packageId = "num_enum_derive";
+            usesDefaultFeatures = false;
+          }
+        ];
+        features = {
+          "complex-expressions" = [ "num_enum_derive/complex-expressions" ];
+          "default" = [ "std" ];
+          "std" = [ "num_enum_derive/std" ];
+        };
+        resolvedDefaultFeatures = [ "default" "std" ];
+      };
+      "num_enum_derive" = rec {
+        crateName = "num_enum_derive";
+        version = "0.7.3";
+        edition = "2021";
+        sha256 = "0mksna1jj87ydh146gn6jcqkvvs920c3dgh0p4f3xk184kpl865g";
+        procMacro = true;
+        authors = [
+          "Daniel Wagner-Hall <dawagner@gmail.com>"
+          "Daniel Henry-Mantilla <daniel.henry.mantilla@gmail.com>"
+          "Vincent Esche <regexident@gmail.com>"
+        ];
+        dependencies = [
+          {
+            name = "proc-macro-crate";
+            packageId = "proc-macro-crate";
+            optional = true;
+          }
+          {
+            name = "proc-macro2";
+            packageId = "proc-macro2";
+          }
+          {
+            name = "quote";
+            packageId = "quote";
+          }
+          {
+            name = "syn";
+            packageId = "syn 2.0.79";
+            features = [ "parsing" ];
+          }
+        ];
+        devDependencies = [
+          {
+            name = "syn";
+            packageId = "syn 2.0.79";
+            features = [ "extra-traits" "parsing" ];
+          }
+        ];
+        features = {
+          "complex-expressions" = [ "syn/full" ];
+          "default" = [ "std" ];
+          "proc-macro-crate" = [ "dep:proc-macro-crate" ];
+          "std" = [ "proc-macro-crate" ];
+        };
+        resolvedDefaultFeatures = [ "proc-macro-crate" "std" ];
+      };
       "number_prefix" = rec {
         crateName = "number_prefix";
         version = "0.4.0";
@@ -5282,6 +5357,23 @@ rec {
         };
         resolvedDefaultFeatures = [ "simd" "std" ];
       };
+      "proc-macro-crate" = rec {
+        crateName = "proc-macro-crate";
+        version = "3.2.0";
+        edition = "2021";
+        sha256 = "0yzsqnavb3lmrcsmbrdjfrky9vcbl46v59xi9avn0796rb3likwf";
+        libName = "proc_macro_crate";
+        authors = [
+          "Bastian Köcher <git@kchr.de>"
+        ];
+        dependencies = [
+          {
+            name = "toml_edit";
+            packageId = "toml_edit";
+          }
+        ];
+
+      };
       "proc-macro2" = rec {
         crateName = "proc-macro2";
         version = "1.0.87";
@@ -6739,6 +6831,51 @@ rec {
         };
         resolvedDefaultFeatures = [ "default" "io" "io-util" ];
       };
+      "toml_datetime" = rec {
+        crateName = "toml_datetime";
+        version = "0.6.8";
+        edition = "2021";
+        sha256 = "0hgv7v9g35d7y9r2afic58jvlwnf73vgd1mz2k8gihlgrf73bmqd";
+        authors = [
+          "Alex Crichton <alex@alexcrichton.com>"
+        ];
+        features = {
+          "serde" = [ "dep:serde" ];
+        };
+      };
+      "toml_edit" = rec {
+        crateName = "toml_edit";
+        version = "0.22.22";
+        edition = "2021";
+        sha256 = "1xf7sxfzmnc45f75x302qrn5aph52vc8w226v59yhrm211i8vr2a";
+        authors = [
+          "Andronik Ordian <write@reusable.software>"
+          "Ed Page <eopage@gmail.com>"
+        ];
+        dependencies = [
+          {
+            name = "indexmap";
+            packageId = "indexmap";
+            features = [ "std" ];
+          }
+          {
+            name = "toml_datetime";
+            packageId = "toml_datetime";
+          }
+          {
+            name = "winnow";
+            packageId = "winnow";
+            optional = true;
+          }
+        ];
+        features = {
+          "default" = [ "parse" "display" ];
+          "parse" = [ "dep:winnow" ];
+          "perf" = [ "dep:kstring" ];
+          "serde" = [ "dep:serde" "toml_datetime/serde" "dep:serde_spanned" ];
+        };
+        resolvedDefaultFeatures = [ "default" "display" "parse" ];
+      };
       "tracing" = rec {
         crateName = "tracing";
         version = "0.1.40";
@@ -8587,6 +8724,28 @@ rec {
         ];
 
       };
+      "winnow" = rec {
+        crateName = "winnow";
+        version = "0.6.20";
+        edition = "2021";
+        sha256 = "16y4i8z9vh8hazjxg5mvmq0c5i35wlk8rxi5gkq6cn5vlb0zxh9n";
+        dependencies = [
+          {
+            name = "memchr";
+            packageId = "memchr";
+            optional = true;
+            usesDefaultFeatures = false;
+          }
+        ];
+        features = {
+          "debug" = [ "std" "dep:anstream" "dep:anstyle" "dep:is-terminal" "dep:terminal_size" ];
+          "default" = [ "std" ];
+          "simd" = [ "dep:memchr" ];
+          "std" = [ "alloc" "memchr?/std" ];
+          "unstable-doc" = [ "alloc" "std" "simd" "unstable-recover" ];
+        };
+        resolvedDefaultFeatures = [ "alloc" "default" "std" ];
+      };
       "xxhash-rust" = rec {
         crateName = "xxhash-rust";
         version = "0.8.12";
diff --git a/users/picnoir/tvix-daemon/Cargo.lock b/users/picnoir/tvix-daemon/Cargo.lock
index 8756e8a753da..8731e7cbe68b 100644
--- a/users/picnoir/tvix-daemon/Cargo.lock
+++ b/users/picnoir/tvix-daemon/Cargo.lock
@@ -403,6 +403,12 @@ dependencies = [
 ]
 
 [[package]]
+name = "equivalent"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
+
+[[package]]
 name = "fiat-crypto"
 version = "0.2.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -509,6 +515,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
 
 [[package]]
+name = "hashbrown"
+version = "0.15.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3"
+
+[[package]]
 name = "heck"
 version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -602,6 +614,16 @@ dependencies = [
 ]
 
 [[package]]
+name = "indexmap"
+version = "2.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
+dependencies = [
+ "equivalent",
+ "hashbrown",
+]
+
+[[package]]
 name = "is_terminal_polyfill"
 version = "1.70.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -738,6 +760,7 @@ dependencies = [
  "nix-compat-derive",
  "nom",
  "num-traits",
+ "num_enum",
  "pin-project-lite",
  "serde",
  "serde_json",
@@ -786,6 +809,27 @@ dependencies = [
 ]
 
 [[package]]
+name = "num_enum"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179"
+dependencies = [
+ "num_enum_derive",
+]
+
+[[package]]
+name = "num_enum_derive"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56"
+dependencies = [
+ "proc-macro-crate",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
 name = "object"
 version = "0.36.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -878,6 +922,15 @@ dependencies = [
 ]
 
 [[package]]
+name = "proc-macro-crate"
+version = "3.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b"
+dependencies = [
+ "toml_edit",
+]
+
+[[package]]
 name = "proc-macro2"
 version = "1.0.87"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1241,6 +1294,23 @@ dependencies = [
 ]
 
 [[package]]
+name = "toml_datetime"
+version = "0.6.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
+
+[[package]]
+name = "toml_edit"
+version = "0.22.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
+dependencies = [
+ "indexmap",
+ "toml_datetime",
+ "winnow",
+]
+
+[[package]]
 name = "tower"
 version = "0.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1471,6 +1541,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
 
 [[package]]
+name = "winnow"
+version = "0.6.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
 name = "zeroize"
 version = "1.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/users/picnoir/tvix-daemon/Cargo.nix b/users/picnoir/tvix-daemon/Cargo.nix
index 0a2a18c9c843..04fa57091bf0 100644
--- a/users/picnoir/tvix-daemon/Cargo.nix
+++ b/users/picnoir/tvix-daemon/Cargo.nix
@@ -1312,6 +1312,13 @@ rec {
         ];
 
       };
+      "equivalent" = rec {
+        crateName = "equivalent";
+        version = "1.0.1";
+        edition = "2015";
+        sha256 = "1malmx5f4lkfvqasz319lq6gb3ddg19yzf9s8cykfsgzdmyq0hsl";
+
+      };
       "fiat-crypto" = rec {
         crateName = "fiat-crypto";
         version = "0.2.9";
@@ -1596,6 +1603,28 @@ rec {
         ];
 
       };
+      "hashbrown" = rec {
+        crateName = "hashbrown";
+        version = "0.15.1";
+        edition = "2021";
+        sha256 = "1czsvasi3azv2079fcvbhvpisa16w6fi1mfk8zm2c5wbyqdgr6rs";
+        authors = [
+          "Amanieu d'Antras <amanieu@gmail.com>"
+        ];
+        features = {
+          "alloc" = [ "dep:alloc" ];
+          "allocator-api2" = [ "dep:allocator-api2" ];
+          "compiler_builtins" = [ "dep:compiler_builtins" ];
+          "core" = [ "dep:core" ];
+          "default" = [ "default-hasher" "inline-more" "allocator-api2" "equivalent" "raw-entry" ];
+          "default-hasher" = [ "dep:foldhash" ];
+          "equivalent" = [ "dep:equivalent" ];
+          "nightly" = [ "allocator-api2?/nightly" "bumpalo/allocator_api" ];
+          "rayon" = [ "dep:rayon" ];
+          "rustc-dep-of-std" = [ "nightly" "core" "compiler_builtins" "alloc" "rustc-internal-api" "raw-entry" ];
+          "serde" = [ "dep:serde" ];
+        };
+      };
       "heck" = rec {
         crateName = "heck";
         version = "0.5.0";
@@ -1901,6 +1930,34 @@ rec {
         };
         resolvedDefaultFeatures = [ "default" "http1" "server" "service" "tokio" ];
       };
+      "indexmap" = rec {
+        crateName = "indexmap";
+        version = "2.6.0";
+        edition = "2021";
+        sha256 = "1nmrwn8lbs19gkvhxaawffzbvrpyrb5y3drcrr645x957kz0fybh";
+        dependencies = [
+          {
+            name = "equivalent";
+            packageId = "equivalent";
+            usesDefaultFeatures = false;
+          }
+          {
+            name = "hashbrown";
+            packageId = "hashbrown";
+            usesDefaultFeatures = false;
+          }
+        ];
+        features = {
+          "arbitrary" = [ "dep:arbitrary" ];
+          "borsh" = [ "dep:borsh" ];
+          "default" = [ "std" ];
+          "quickcheck" = [ "dep:quickcheck" ];
+          "rayon" = [ "dep:rayon" ];
+          "rustc-rayon" = [ "dep:rustc-rayon" ];
+          "serde" = [ "dep:serde" ];
+        };
+        resolvedDefaultFeatures = [ "default" "std" ];
+      };
       "is_terminal_polyfill" = rec {
         crateName = "is_terminal_polyfill";
         version = "1.70.1";
@@ -2300,6 +2357,10 @@ rec {
             packageId = "num-traits";
           }
           {
+            name = "num_enum";
+            packageId = "num_enum";
+          }
+          {
             name = "pin-project-lite";
             packageId = "pin-project-lite";
             optional = true;
@@ -2325,7 +2386,7 @@ rec {
             name = "tokio";
             packageId = "tokio";
             optional = true;
-            features = [ "io-util" "macros" ];
+            features = [ "io-util" "macros" "sync" ];
           }
           {
             name = "tracing";
@@ -2345,13 +2406,14 @@ rec {
         features = {
           "async" = [ "tokio" ];
           "bytes" = [ "dep:bytes" ];
-          "default" = [ "async" "wire" "nix-compat-derive" ];
+          "daemon" = [ "tokio" "nix-compat-derive" ];
+          "default" = [ "async" "daemon" "wire" "nix-compat-derive" ];
           "nix-compat-derive" = [ "dep:nix-compat-derive" ];
           "pin-project-lite" = [ "dep:pin-project-lite" ];
           "tokio" = [ "dep:tokio" ];
           "wire" = [ "tokio" "pin-project-lite" "bytes" ];
         };
-        resolvedDefaultFeatures = [ "async" "bytes" "default" "nix-compat-derive" "pin-project-lite" "tokio" "wire" ];
+        resolvedDefaultFeatures = [ "async" "bytes" "daemon" "default" "nix-compat-derive" "pin-project-lite" "tokio" "wire" ];
       };
       "nix-compat-derive" = rec {
         crateName = "nix-compat-derive";
@@ -2455,6 +2517,76 @@ rec {
         };
         resolvedDefaultFeatures = [ "default" "std" ];
       };
+      "num_enum" = rec {
+        crateName = "num_enum";
+        version = "0.7.3";
+        edition = "2021";
+        sha256 = "0yai0vafhy85mvhknzfqd7lm04hzaln7i5c599rhy8mj831kyqaf";
+        authors = [
+          "Daniel Wagner-Hall <dawagner@gmail.com>"
+          "Daniel Henry-Mantilla <daniel.henry.mantilla@gmail.com>"
+          "Vincent Esche <regexident@gmail.com>"
+        ];
+        dependencies = [
+          {
+            name = "num_enum_derive";
+            packageId = "num_enum_derive";
+            usesDefaultFeatures = false;
+          }
+        ];
+        features = {
+          "complex-expressions" = [ "num_enum_derive/complex-expressions" ];
+          "default" = [ "std" ];
+          "std" = [ "num_enum_derive/std" ];
+        };
+        resolvedDefaultFeatures = [ "default" "std" ];
+      };
+      "num_enum_derive" = rec {
+        crateName = "num_enum_derive";
+        version = "0.7.3";
+        edition = "2021";
+        sha256 = "0mksna1jj87ydh146gn6jcqkvvs920c3dgh0p4f3xk184kpl865g";
+        procMacro = true;
+        authors = [
+          "Daniel Wagner-Hall <dawagner@gmail.com>"
+          "Daniel Henry-Mantilla <daniel.henry.mantilla@gmail.com>"
+          "Vincent Esche <regexident@gmail.com>"
+        ];
+        dependencies = [
+          {
+            name = "proc-macro-crate";
+            packageId = "proc-macro-crate";
+            optional = true;
+          }
+          {
+            name = "proc-macro2";
+            packageId = "proc-macro2";
+          }
+          {
+            name = "quote";
+            packageId = "quote";
+          }
+          {
+            name = "syn";
+            packageId = "syn";
+            features = [ "parsing" ];
+          }
+        ];
+        devDependencies = [
+          {
+            name = "syn";
+            packageId = "syn";
+            features = [ "extra-traits" "parsing" ];
+          }
+        ];
+        features = {
+          "complex-expressions" = [ "syn/full" ];
+          "default" = [ "std" ];
+          "proc-macro-crate" = [ "dep:proc-macro-crate" ];
+          "std" = [ "proc-macro-crate" ];
+        };
+        resolvedDefaultFeatures = [ "proc-macro-crate" "std" ];
+      };
       "object" = rec {
         crateName = "object";
         version = "0.36.5";
@@ -2692,6 +2824,23 @@ rec {
         };
         resolvedDefaultFeatures = [ "alloc" "std" ];
       };
+      "proc-macro-crate" = rec {
+        crateName = "proc-macro-crate";
+        version = "3.2.0";
+        edition = "2021";
+        sha256 = "0yzsqnavb3lmrcsmbrdjfrky9vcbl46v59xi9avn0796rb3likwf";
+        libName = "proc_macro_crate";
+        authors = [
+          "Bastian Köcher <git@kchr.de>"
+        ];
+        dependencies = [
+          {
+            name = "toml_edit";
+            packageId = "toml_edit";
+          }
+        ];
+
+      };
       "proc-macro2" = rec {
         crateName = "proc-macro2";
         version = "1.0.87";
@@ -3772,6 +3921,51 @@ rec {
         };
         resolvedDefaultFeatures = [ "codec" "default" "net" ];
       };
+      "toml_datetime" = rec {
+        crateName = "toml_datetime";
+        version = "0.6.8";
+        edition = "2021";
+        sha256 = "0hgv7v9g35d7y9r2afic58jvlwnf73vgd1mz2k8gihlgrf73bmqd";
+        authors = [
+          "Alex Crichton <alex@alexcrichton.com>"
+        ];
+        features = {
+          "serde" = [ "dep:serde" ];
+        };
+      };
+      "toml_edit" = rec {
+        crateName = "toml_edit";
+        version = "0.22.22";
+        edition = "2021";
+        sha256 = "1xf7sxfzmnc45f75x302qrn5aph52vc8w226v59yhrm211i8vr2a";
+        authors = [
+          "Andronik Ordian <write@reusable.software>"
+          "Ed Page <eopage@gmail.com>"
+        ];
+        dependencies = [
+          {
+            name = "indexmap";
+            packageId = "indexmap";
+            features = [ "std" ];
+          }
+          {
+            name = "toml_datetime";
+            packageId = "toml_datetime";
+          }
+          {
+            name = "winnow";
+            packageId = "winnow";
+            optional = true;
+          }
+        ];
+        features = {
+          "default" = [ "parse" "display" ];
+          "parse" = [ "dep:winnow" ];
+          "perf" = [ "dep:kstring" ];
+          "serde" = [ "dep:serde" "toml_datetime/serde" "dep:serde_spanned" ];
+        };
+        resolvedDefaultFeatures = [ "default" "display" "parse" ];
+      };
       "tower" = rec {
         crateName = "tower";
         version = "0.5.1";
@@ -4673,6 +4867,28 @@ rec {
         ];
 
       };
+      "winnow" = rec {
+        crateName = "winnow";
+        version = "0.6.20";
+        edition = "2021";
+        sha256 = "16y4i8z9vh8hazjxg5mvmq0c5i35wlk8rxi5gkq6cn5vlb0zxh9n";
+        dependencies = [
+          {
+            name = "memchr";
+            packageId = "memchr";
+            optional = true;
+            usesDefaultFeatures = false;
+          }
+        ];
+        features = {
+          "debug" = [ "std" "dep:anstream" "dep:anstyle" "dep:is-terminal" "dep:terminal_size" ];
+          "default" = [ "std" ];
+          "simd" = [ "dep:memchr" ];
+          "std" = [ "alloc" "memchr?/std" ];
+          "unstable-doc" = [ "alloc" "std" "simd" "unstable-recover" ];
+        };
+        resolvedDefaultFeatures = [ "alloc" "default" "std" ];
+      };
       "zeroize" = rec {
         crateName = "zeroize";
         version = "1.8.1";
diff --git a/users/picnoir/tvix-daemon/src/main.rs b/users/picnoir/tvix-daemon/src/main.rs
index d34acabc99a0..d60fcfbff8bd 100644
--- a/users/picnoir/tvix-daemon/src/main.rs
+++ b/users/picnoir/tvix-daemon/src/main.rs
@@ -108,7 +108,9 @@ async fn op_set_options<R>(conn: &mut ClientConnection<R>) -> std::io::Result<Cl
 where
     R: AsyncReadExt + AsyncWriteExt + Unpin + std::fmt::Debug,
 {
-    let settings = worker_protocol::read_client_settings(&mut conn.conn, conn.version).await?;
+    // TODO: This code used read_client_settings which did not implement the protocol correctly,
+    // returning default() for now to unblock CI.
+    let settings = ClientSettings::default();
     // The client expects us to send some logs when we're processing
     // the settings. Sending STDERR_LAST signal we're done processing.
     conn.conn.write_u64_le(worker_protocol::STDERR_LAST).await?;