From 60e5ab4d57e23c00de6ae2a3e1433b7b95437eb8 Mon Sep 17 00:00:00 2001
From: Claude
Date: Sat, 27 Jun 2026 02:41:21 +0000
Subject: [PATCH 1/5] feat(lingbot-map-rs): scaffold standalone Rust port of
LingBot-Map
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Add a self-contained Cargo workspace porting LingBot-Map (robbyant/lingbot-map,
Apache-2.0) — a streaming feed-forward 3D reconstruction model — to Rust.
Foundation (P0-P2, builds + tests green):
- lingbot-memory: StreamingMemory over the real ruvector-core VectorDB API,
replacing the FlashInfer paged KV cache with lock-free HNSW retrieval
(O(log N) long-range drift correction, no VRAM ceiling). Long-range recall
verified at 5000-frame range.
- lingbot-tensor: ModelConfig (serde from config.json) + header-only
safetensors WeightIndex (validate multi-GB checkpoints without loading them);
candle weight materialization behind a feature flag.
- ADR-0001..0005: workspace topology, ruvector memory layer, candle/safetensors
backend, wgpu+WebGPU/WASM rendering & GitHub Pages deploy, MP4/PNG output.
- PROGRESS.md: loop-state tracker driving the iterative build-out.
- .cargo/config.toml: sparse crates.io protocol for sandboxed/offline builds.
Excluded from the root workspace so it never perturbs the parent build and can
be split into its own repo unchanged.
Co-Authored-By: claude-flow
Claude-Session: https://claude.ai/code/session_016aHCtJGcejmWbzX2PXKtLH
---
Cargo.toml | 2 +-
lingbot-map-rs/.cargo/config.toml | 9 +
lingbot-map-rs/.gitignore | 8 +
lingbot-map-rs/Cargo.lock | 2086 +++++++++++++++++
lingbot-map-rs/Cargo.toml | 41 +
lingbot-map-rs/LICENSE | 201 ++
lingbot-map-rs/PROGRESS.md | 83 +
lingbot-map-rs/README.md | 68 +
.../crates/lingbot-memory/Cargo.toml | 20 +
.../crates/lingbot-memory/src/lib.rs | 304 +++
.../crates/lingbot-tensor/Cargo.toml | 25 +
.../crates/lingbot-tensor/src/config.rs | 121 +
.../crates/lingbot-tensor/src/lib.rs | 110 +
...standalone-workspace-and-crate-topology.md | 56 +
.../adr/ADR-0002-ruvector-streaming-memory.md | 55 +
...-0003-candle-tensor-backend-and-weights.md | 45 +
.../adr/ADR-0004-rendering-and-deployment.md | 42 +
.../adr/ADR-0005-streaming-mp4-png-output.md | 43 +
lingbot-map-rs/rust-toolchain.toml | 4 +
19 files changed, 3322 insertions(+), 1 deletion(-)
create mode 100644 lingbot-map-rs/.cargo/config.toml
create mode 100644 lingbot-map-rs/.gitignore
create mode 100644 lingbot-map-rs/Cargo.lock
create mode 100644 lingbot-map-rs/Cargo.toml
create mode 100644 lingbot-map-rs/LICENSE
create mode 100644 lingbot-map-rs/PROGRESS.md
create mode 100644 lingbot-map-rs/README.md
create mode 100644 lingbot-map-rs/crates/lingbot-memory/Cargo.toml
create mode 100644 lingbot-map-rs/crates/lingbot-memory/src/lib.rs
create mode 100644 lingbot-map-rs/crates/lingbot-tensor/Cargo.toml
create mode 100644 lingbot-map-rs/crates/lingbot-tensor/src/config.rs
create mode 100644 lingbot-map-rs/crates/lingbot-tensor/src/lib.rs
create mode 100644 lingbot-map-rs/docs/adr/ADR-0001-standalone-workspace-and-crate-topology.md
create mode 100644 lingbot-map-rs/docs/adr/ADR-0002-ruvector-streaming-memory.md
create mode 100644 lingbot-map-rs/docs/adr/ADR-0003-candle-tensor-backend-and-weights.md
create mode 100644 lingbot-map-rs/docs/adr/ADR-0004-rendering-and-deployment.md
create mode 100644 lingbot-map-rs/docs/adr/ADR-0005-streaming-mp4-png-output.md
create mode 100644 lingbot-map-rs/rust-toolchain.toml
diff --git a/Cargo.toml b/Cargo.toml
index c82190e3d9..05820d79b2 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,5 +1,5 @@
[workspace]
-exclude = ["external/ruqu", "external/rvdna", "examples/OSpipe", "examples/rvf", "crates/micro-hnsw-wasm", "crates/ruvector-hyperbolic-hnsw", "crates/ruvector-hyperbolic-hnsw-wasm", "examples/ruvLLM/esp32", "examples/ruvLLM/esp32-flash", "examples/edge-net", "examples/data", "examples/ruvLLM", "examples/delta-behavior", "crates/rvf", "crates/rvf/*", "crates/rvf/*/*", "examples/rvf-desktop", "crates/mcp-brain-server",
+exclude = ["lingbot-map-rs", "lingbot-map-rs/*", "lingbot-map-rs/crates/*", "external/ruqu", "external/rvdna", "examples/OSpipe", "examples/rvf", "crates/micro-hnsw-wasm", "crates/ruvector-hyperbolic-hnsw", "crates/ruvector-hyperbolic-hnsw-wasm", "examples/ruvLLM/esp32", "examples/ruvLLM/esp32-flash", "examples/edge-net", "examples/data", "examples/ruvLLM", "examples/delta-behavior", "crates/rvf", "crates/rvf/*", "crates/rvf/*/*", "examples/rvf-desktop", "crates/mcp-brain-server",
# emergent-time-wasm: standalone cdylib with own opt-level=z, panic=abort
"crates/emergent-time-wasm",
# sonic-ct crates: self-contained detached workspaces
diff --git a/lingbot-map-rs/.cargo/config.toml b/lingbot-map-rs/.cargo/config.toml
new file mode 100644
index 0000000000..783f6f1370
--- /dev/null
+++ b/lingbot-map-rs/.cargo/config.toml
@@ -0,0 +1,9 @@
+# The parent repo's .cargo/config.toml forces the crates.io *git* protocol,
+# which routes through github.com and is blocked in the sandboxed build env.
+# The sparse protocol uses index.crates.io, which is allow-listed. This nested
+# config takes precedence when cargo is invoked from within lingbot-map-rs.
+[registries.crates-io]
+protocol = "sparse"
+
+[net]
+git-fetch-with-cli = true
diff --git a/lingbot-map-rs/.gitignore b/lingbot-map-rs/.gitignore
new file mode 100644
index 0000000000..1f8bd4d4bc
--- /dev/null
+++ b/lingbot-map-rs/.gitignore
@@ -0,0 +1,8 @@
+/target
+**/*.rs.bk
+*.safetensors
+*.mp4
+*.png
+!demo/assets/*.png
+checkpoints/
+.DS_Store
diff --git a/lingbot-map-rs/Cargo.lock b/lingbot-map-rs/Cargo.lock
new file mode 100644
index 0000000000..cddedabf70
--- /dev/null
+++ b/lingbot-map-rs/Cargo.lock
@@ -0,0 +1,2086 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "aho-corasick"
+version = "1.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "allocator-api2"
+version = "0.2.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
+
+[[package]]
+name = "android_system_properties"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "anndists"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a8396b473aa0bceed68fb32462505387ea39fa47c7029417e0a49f10592b036"
+dependencies = [
+ "anyhow",
+ "cfg-if",
+ "cpu-time",
+ "env_logger",
+ "lazy_static",
+ "log",
+ "num-traits",
+ "num_cpus",
+ "rayon",
+]
+
+[[package]]
+name = "anstream"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d"
+dependencies = [
+ "anstyle",
+ "anstyle-parse",
+ "anstyle-query",
+ "anstyle-wincon",
+ "colorchoice",
+ "is_terminal_polyfill",
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle"
+version = "1.0.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000"
+
+[[package]]
+name = "anstyle-parse"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e"
+dependencies = [
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle-query"
+version = "1.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
+dependencies = [
+ "windows-sys",
+]
+
+[[package]]
+name = "anstyle-wincon"
+version = "3.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
+dependencies = [
+ "anstyle",
+ "once_cell_polyfill",
+ "windows-sys",
+]
+
+[[package]]
+name = "anyhow"
+version = "1.0.103"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3"
+
+[[package]]
+name = "autocfg"
+version = "1.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
+
+[[package]]
+name = "bincode"
+version = "1.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "bincode"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740"
+dependencies = [
+ "bincode_derive",
+ "serde",
+ "unty",
+]
+
+[[package]]
+name = "bincode_derive"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf95709a440f45e986983918d0e8a1f30a9b1df04918fc828670606804ac3c09"
+dependencies = [
+ "virtue",
+]
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "bitflags"
+version = "2.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8"
+
+[[package]]
+name = "bumpalo"
+version = "3.20.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
+
+[[package]]
+name = "bytecheck"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0caa33a2c0edca0419d15ac723dff03f1956f7978329b1e3b5fdaaaed9d3ca8b"
+dependencies = [
+ "bytecheck_derive",
+ "ptr_meta",
+ "rancor",
+ "simdutf8",
+]
+
+[[package]]
+name = "bytecheck_derive"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "89385e82b5d1821d2219e0b095efa2cc1f246cbf99080f3be46a1a85c0d392d9"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "bytemuck"
+version = "1.25.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec"
+dependencies = [
+ "bytemuck_derive",
+]
+
+[[package]]
+name = "bytemuck_derive"
+version = "1.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "byteorder"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+
+[[package]]
+name = "bytes"
+version = "1.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ae3f5d315924270530207e2a68396c3cc547f6dca3fbdca317cfb1a51edb593"
+
+[[package]]
+name = "candle-core"
+version = "0.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c15b675b80d994b2eadb20a4bbe434eabeb454eac3ee5e2b4cf6f147ee9be091"
+dependencies = [
+ "byteorder",
+ "float8",
+ "gemm",
+ "half",
+ "libm",
+ "memmap2",
+ "num-traits",
+ "num_cpus",
+ "rand 0.9.4",
+ "rand_distr 0.5.1",
+ "rayon",
+ "safetensors 0.7.0",
+ "thiserror 2.0.18",
+ "yoke",
+ "zip",
+]
+
+[[package]]
+name = "candle-nn"
+version = "0.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3045fa9e7aef8567d209a27d56b692f60b96f4d0569f4c3011f8ca6715c65e03"
+dependencies = [
+ "candle-core",
+ "half",
+ "libc",
+ "num-traits",
+ "rayon",
+ "safetensors 0.7.0",
+ "serde",
+ "thiserror 2.0.18",
+]
+
+[[package]]
+name = "cc"
+version = "1.2.65"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e228eec9be7c17ccb640b59b36a5cd805ea2a564a4c5e162c2f659fea30d3b96"
+dependencies = [
+ "find-msvc-tools",
+ "shlex",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
+
+[[package]]
+name = "cfg_aliases"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
+
+[[package]]
+name = "chrono"
+version = "0.4.45"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327"
+dependencies = [
+ "iana-time-zone",
+ "js-sys",
+ "num-traits",
+ "serde",
+ "wasm-bindgen",
+ "windows-link",
+]
+
+[[package]]
+name = "colorchoice"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570"
+
+[[package]]
+name = "combine"
+version = "4.6.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd"
+dependencies = [
+ "bytes",
+ "memchr",
+]
+
+[[package]]
+name = "core-foundation-sys"
+version = "0.8.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
+
+[[package]]
+name = "cpu-time"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e9e393a7668fe1fad3075085b86c781883000b4ede868f43627b34a87c8b7ded"
+dependencies = [
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "crc32fast"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "crossbeam"
+version = "0.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8"
+dependencies = [
+ "crossbeam-channel",
+ "crossbeam-deque",
+ "crossbeam-epoch",
+ "crossbeam-queue",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-channel"
+version = "0.5.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2"
+dependencies = [
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-deque"
+version = "0.8.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
+dependencies = [
+ "crossbeam-epoch",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-epoch"
+version = "0.9.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
+dependencies = [
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-queue"
+version = "0.3.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115"
+dependencies = [
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.8.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
+
+[[package]]
+name = "crunchy"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
+
+[[package]]
+name = "dashmap"
+version = "6.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6361d5c062261c78a176addb82d4c821ae42bed6089de0e12603cd25de2059c"
+dependencies = [
+ "cfg-if",
+ "crossbeam-utils",
+ "hashbrown 0.14.5",
+ "lock_api",
+ "once_cell",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "defmt"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a6e524506490a1953d237cb87b1cfc1e46f88c18f10a22dfe0f507dc6bfc7f7f"
+dependencies = [
+ "bitflags 1.3.2",
+ "defmt-macros",
+]
+
+[[package]]
+name = "defmt-macros"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0a27770e9c8f719a79d8b638281f4d828f77d8fd61e0bd94451b9b85e576a0b"
+dependencies = [
+ "defmt-parser",
+ "proc-macro-error2",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "defmt-parser"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e"
+dependencies = [
+ "thiserror 2.0.18",
+]
+
+[[package]]
+name = "dyn-stack"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1c4713e43e2886ba72b8271aa66c93d722116acf7a75555cce11dcde84388fe8"
+dependencies = [
+ "bytemuck",
+ "dyn-stack-macros",
+]
+
+[[package]]
+name = "dyn-stack-macros"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e1d926b4d407d372f141f93bb444696142c29d32962ccbd3531117cf3aa0bfa9"
+
+[[package]]
+name = "either"
+version = "1.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e"
+
+[[package]]
+name = "enum-as-inner"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "env_filter"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "900d271a03799a1ee8d1ca9b19893b48ca674a9284fefcfb85f05e74ed314217"
+dependencies = [
+ "log",
+ "regex",
+]
+
+[[package]]
+name = "env_logger"
+version = "0.11.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "de671bd27a75a797dc9ae289ba1e77276e75e2026408aab65185384e2d5cd3f6"
+dependencies = [
+ "anstream",
+ "anstyle",
+ "env_filter",
+ "jiff",
+ "log",
+]
+
+[[package]]
+name = "equivalent"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
+
+[[package]]
+name = "find-msvc-tools"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
+
+[[package]]
+name = "float8"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "719a903cc23e4a89e87962c2a80fdb45cdaad0983a89bd150bb57b4c8571a7d5"
+dependencies = [
+ "half",
+ "num-traits",
+ "rand 0.9.4",
+ "rand_distr 0.5.1",
+]
+
+[[package]]
+name = "foldhash"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
+
+[[package]]
+name = "foldhash"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb"
+
+[[package]]
+name = "futures-core"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
+
+[[package]]
+name = "futures-task"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393"
+
+[[package]]
+name = "futures-util"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
+dependencies = [
+ "futures-core",
+ "futures-task",
+ "pin-project-lite",
+ "slab",
+]
+
+[[package]]
+name = "gemm"
+version = "0.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa0673db364b12263d103b68337a68fbecc541d6f6b61ba72fe438654709eacb"
+dependencies = [
+ "dyn-stack",
+ "gemm-c32",
+ "gemm-c64",
+ "gemm-common",
+ "gemm-f16",
+ "gemm-f32",
+ "gemm-f64",
+ "num-complex",
+ "num-traits",
+ "paste",
+ "raw-cpuid",
+ "seq-macro",
+]
+
+[[package]]
+name = "gemm-c32"
+version = "0.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "086936dbdcb99e37aad81d320f98f670e53c1e55a98bee70573e83f95beb128c"
+dependencies = [
+ "dyn-stack",
+ "gemm-common",
+ "num-complex",
+ "num-traits",
+ "paste",
+ "raw-cpuid",
+ "seq-macro",
+]
+
+[[package]]
+name = "gemm-c64"
+version = "0.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "20c8aeeeec425959bda4d9827664029ba1501a90a0d1e6228e48bef741db3a3f"
+dependencies = [
+ "dyn-stack",
+ "gemm-common",
+ "num-complex",
+ "num-traits",
+ "paste",
+ "raw-cpuid",
+ "seq-macro",
+]
+
+[[package]]
+name = "gemm-common"
+version = "0.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "88027625910cc9b1085aaaa1c4bc46bb3a36aad323452b33c25b5e4e7c8e2a3e"
+dependencies = [
+ "bytemuck",
+ "dyn-stack",
+ "half",
+ "libm",
+ "num-complex",
+ "num-traits",
+ "once_cell",
+ "paste",
+ "pulp",
+ "raw-cpuid",
+ "rayon",
+ "seq-macro",
+ "sysctl",
+]
+
+[[package]]
+name = "gemm-f16"
+version = "0.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3df7a55202e6cd6739d82ae3399c8e0c7e1402859b30e4cb780e61525d9486e"
+dependencies = [
+ "dyn-stack",
+ "gemm-common",
+ "gemm-f32",
+ "half",
+ "num-complex",
+ "num-traits",
+ "paste",
+ "raw-cpuid",
+ "rayon",
+ "seq-macro",
+]
+
+[[package]]
+name = "gemm-f32"
+version = "0.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "02e0b8c9da1fbec6e3e3ab2ce6bc259ef18eb5f6f0d3e4edf54b75f9fd41a81c"
+dependencies = [
+ "dyn-stack",
+ "gemm-common",
+ "num-complex",
+ "num-traits",
+ "paste",
+ "raw-cpuid",
+ "seq-macro",
+]
+
+[[package]]
+name = "gemm-f64"
+version = "0.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "056131e8f2a521bfab322f804ccd652520c79700d81209e9d9275bbdecaadc6a"
+dependencies = [
+ "dyn-stack",
+ "gemm-common",
+ "num-complex",
+ "num-traits",
+ "paste",
+ "raw-cpuid",
+ "seq-macro",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "r-efi 5.3.0",
+ "wasip2",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "r-efi 6.0.0",
+]
+
+[[package]]
+name = "half"
+version = "2.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b"
+dependencies = [
+ "bytemuck",
+ "cfg-if",
+ "crunchy",
+ "num-traits",
+ "rand 0.9.4",
+ "rand_distr 0.5.1",
+ "zerocopy",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.14.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
+
+[[package]]
+name = "hashbrown"
+version = "0.15.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
+dependencies = [
+ "allocator-api2",
+ "equivalent",
+ "foldhash 0.1.5",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.16.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
+dependencies = [
+ "allocator-api2",
+ "equivalent",
+ "foldhash 0.2.0",
+ "serde",
+ "serde_core",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.17.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
+
+[[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
+[[package]]
+name = "hermit-abi"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
+
+[[package]]
+name = "hnsw_rs"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43a5258f079b97bf2e8311ff9579e903c899dcbac0d9a138d62e9a066778bd07"
+dependencies = [
+ "anndists",
+ "anyhow",
+ "bincode 1.3.3",
+ "cfg-if",
+ "cpu-time",
+ "env_logger",
+ "hashbrown 0.15.5",
+ "indexmap",
+ "lazy_static",
+ "log",
+ "mmap-rs",
+ "num-traits",
+ "num_cpus",
+ "parking_lot",
+ "rand 0.9.4",
+ "rayon",
+ "serde",
+]
+
+[[package]]
+name = "iana-time-zone"
+version = "0.1.65"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470"
+dependencies = [
+ "android_system_properties",
+ "core-foundation-sys",
+ "iana-time-zone-haiku",
+ "js-sys",
+ "log",
+ "wasm-bindgen",
+ "windows-core",
+]
+
+[[package]]
+name = "iana-time-zone-haiku"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "indexmap"
+version = "2.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
+dependencies = [
+ "equivalent",
+ "hashbrown 0.17.1",
+]
+
+[[package]]
+name = "is_terminal_polyfill"
+version = "1.70.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
+
+[[package]]
+name = "itoa"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
+
+[[package]]
+name = "jiff"
+version = "0.2.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34f877a98676d2fb664698d74cc6a51ce6c484ce8c770f05d0108ec9090aeb46"
+dependencies = [
+ "defmt",
+ "jiff-static",
+ "log",
+ "portable-atomic",
+ "portable-atomic-util",
+ "serde_core",
+]
+
+[[package]]
+name = "jiff-static"
+version = "0.2.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0666b5ab5ecaca213fc2a85b8c0083d9004e84ee2d5f9a7e0017aaf50986f25f"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "js-sys"
+version = "0.3.103"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102"
+dependencies = [
+ "cfg-if",
+ "futures-util",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
+
+[[package]]
+name = "libc"
+version = "0.2.186"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
+
+[[package]]
+name = "libm"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
+
+[[package]]
+name = "lingbot-memory"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "ruvector-core",
+ "serde",
+ "serde_json",
+ "thiserror 2.0.18",
+ "tracing",
+]
+
+[[package]]
+name = "lingbot-tensor"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "candle-core",
+ "candle-nn",
+ "half",
+ "safetensors 0.4.5",
+ "serde",
+ "serde_json",
+ "thiserror 2.0.18",
+]
+
+[[package]]
+name = "lock_api"
+version = "0.4.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
+dependencies = [
+ "scopeguard",
+]
+
+[[package]]
+name = "log"
+version = "0.4.33"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad"
+
+[[package]]
+name = "mach2"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d640282b302c0bb0a2a8e0233ead9035e3bed871f0b7e81fe4a1ec829765db44"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "matrixmultiply"
+version = "0.3.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a06de3016e9fae57a36fd14dba131fccf49f74b40b7fbdb472f96e361ec71a08"
+dependencies = [
+ "autocfg",
+ "rawpointer",
+]
+
+[[package]]
+name = "memchr"
+version = "2.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4"
+
+[[package]]
+name = "memmap2"
+version = "0.9.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d1219ed1b7f229ee7104d281dd01d6802fe28bb6e95d292942c4daacdeb798c0"
+dependencies = [
+ "libc",
+ "stable_deref_trait",
+]
+
+[[package]]
+name = "mmap-rs"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ecce9d566cb9234ae3db9e249c8b55665feaaf32b0859ff1e27e310d2beb3d8"
+dependencies = [
+ "bitflags 2.13.0",
+ "combine",
+ "libc",
+ "mach2",
+ "nix",
+ "sysctl",
+ "thiserror 2.0.18",
+ "widestring",
+ "windows",
+]
+
+[[package]]
+name = "munge"
+version = "0.4.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e17401f259eba956ca16491461b6e8f72913a0a114e39736ce404410f915a0c"
+dependencies = [
+ "munge_macro",
+]
+
+[[package]]
+name = "munge_macro"
+version = "0.4.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4568f25ccbd45ab5d5603dc34318c1ec56b117531781260002151b8530a9f931"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "ndarray"
+version = "0.16.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "882ed72dce9365842bf196bdeedf5055305f11fc8c03dee7bb0194a6cad34841"
+dependencies = [
+ "matrixmultiply",
+ "num-complex",
+ "num-integer",
+ "num-traits",
+ "portable-atomic",
+ "portable-atomic-util",
+ "rawpointer",
+ "serde",
+]
+
+[[package]]
+name = "nix"
+version = "0.30.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6"
+dependencies = [
+ "bitflags 2.13.0",
+ "cfg-if",
+ "cfg_aliases",
+ "libc",
+]
+
+[[package]]
+name = "num-complex"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
+dependencies = [
+ "bytemuck",
+ "num-traits",
+]
+
+[[package]]
+name = "num-integer"
+version = "0.1.46"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
+dependencies = [
+ "autocfg",
+ "libm",
+]
+
+[[package]]
+name = "num_cpus"
+version = "1.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b"
+dependencies = [
+ "hermit-abi",
+ "libc",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.21.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
+
+[[package]]
+name = "once_cell_polyfill"
+version = "1.70.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
+
+[[package]]
+name = "parking_lot"
+version = "0.12.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a"
+dependencies = [
+ "lock_api",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.9.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "redox_syscall",
+ "smallvec",
+ "windows-link",
+]
+
+[[package]]
+name = "paste"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
+
+[[package]]
+name = "pin-project-lite"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
+
+[[package]]
+name = "portable-atomic"
+version = "1.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49"
+
+[[package]]
+name = "portable-atomic-util"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c2a106d1259c23fac8e543272398ae0e3c0b8d33c88ed73d0cc71b0f1d902618"
+dependencies = [
+ "portable-atomic",
+]
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
+dependencies = [
+ "zerocopy",
+]
+
+[[package]]
+name = "proc-macro-error-attr2"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5"
+dependencies = [
+ "proc-macro2",
+ "quote",
+]
+
+[[package]]
+name = "proc-macro-error2"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802"
+dependencies = [
+ "proc-macro-error-attr2",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.106"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "ptr_meta"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b9a0cf95a1196af61d4f1cbdab967179516d9a4a4312af1f31948f8f6224a79"
+dependencies = [
+ "ptr_meta_derive",
+]
+
+[[package]]
+name = "ptr_meta_derive"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7347867d0a7e1208d93b46767be83e2b8f978c3dad35f775ac8d8847551d6fe1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "pulp"
+version = "0.22.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "046aa45b989642ec2e4717c8e72d677b13edd831a4d3b6cf37d9a3e54912496a"
+dependencies = [
+ "bytemuck",
+ "cfg-if",
+ "libm",
+ "num-complex",
+ "paste",
+ "pulp-wasm-simd-flag",
+ "raw-cpuid",
+ "reborrow",
+ "version_check",
+]
+
+[[package]]
+name = "pulp-wasm-simd-flag"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d8f70e07b9c3962945a74e59ca1c511bba65b6419468acc217c457d93f3c740"
+
+[[package]]
+name = "quote"
+version = "1.0.46"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "r-efi"
+version = "5.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
+
+[[package]]
+name = "r-efi"
+version = "6.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
+
+[[package]]
+name = "rancor"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a063ea72381527c2a0561da9c80000ef822bdd7c3241b1cc1b12100e3df081ee"
+dependencies = [
+ "ptr_meta",
+]
+
+[[package]]
+name = "rand"
+version = "0.8.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a"
+dependencies = [
+ "libc",
+ "rand_chacha 0.3.1",
+ "rand_core 0.6.4",
+]
+
+[[package]]
+name = "rand"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea"
+dependencies = [
+ "rand_chacha 0.9.0",
+ "rand_core 0.9.5",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
+dependencies = [
+ "ppv-lite86",
+ "rand_core 0.6.4",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
+dependencies = [
+ "ppv-lite86",
+ "rand_core 0.9.5",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
+dependencies = [
+ "getrandom 0.2.17",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c"
+dependencies = [
+ "getrandom 0.3.4",
+]
+
+[[package]]
+name = "rand_distr"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31"
+dependencies = [
+ "num-traits",
+ "rand 0.8.6",
+]
+
+[[package]]
+name = "rand_distr"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a8615d50dcf34fa31f7ab52692afec947c4dd0ab803cc87cb3b0b4570ff7463"
+dependencies = [
+ "num-traits",
+ "rand 0.9.4",
+]
+
+[[package]]
+name = "raw-cpuid"
+version = "11.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186"
+dependencies = [
+ "bitflags 2.13.0",
+]
+
+[[package]]
+name = "rawpointer"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"
+
+[[package]]
+name = "rayon"
+version = "1.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d"
+dependencies = [
+ "either",
+ "rayon-core",
+]
+
+[[package]]
+name = "rayon-core"
+version = "1.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91"
+dependencies = [
+ "crossbeam-deque",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "reborrow"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "03251193000f4bd3b042892be858ee50e8b3719f2b08e5833ac4353724632430"
+
+[[package]]
+name = "redox_syscall"
+version = "0.5.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
+dependencies = [
+ "bitflags 2.13.0",
+]
+
+[[package]]
+name = "regex"
+version = "1.12.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
+
+[[package]]
+name = "rend"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cadadef317c2f20755a64d7fdc48f9e7178ee6b0e1f7fce33fa60f1d68a276e6"
+dependencies = [
+ "bytecheck",
+]
+
+[[package]]
+name = "rkyv"
+version = "0.8.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73389e0c99e664f919275ab5b5b0471391fe9a8de61e1dff9b1eaf56a90f16e3"
+dependencies = [
+ "bytecheck",
+ "bytes",
+ "hashbrown 0.17.1",
+ "indexmap",
+ "munge",
+ "ptr_meta",
+ "rancor",
+ "rend",
+ "rkyv_derive",
+ "tinyvec",
+ "uuid",
+]
+
+[[package]]
+name = "rkyv_derive"
+version = "0.8.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d2ed0b54125315fb36bd021e82d314d1c126548f871634b483f46b31d13cac6"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "rustversion"
+version = "1.0.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
+
+[[package]]
+name = "ruvector-core"
+version = "2.2.3"
+dependencies = [
+ "anyhow",
+ "bincode 2.0.1",
+ "chrono",
+ "crossbeam",
+ "dashmap",
+ "hnsw_rs",
+ "ndarray",
+ "once_cell",
+ "parking_lot",
+ "rand 0.8.6",
+ "rand_distr 0.4.3",
+ "rayon",
+ "rkyv",
+ "serde",
+ "serde_json",
+ "thiserror 2.0.18",
+ "tracing",
+ "uuid",
+]
+
+[[package]]
+name = "safetensors"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "44560c11236a6130a46ce36c836a62936dc81ebf8c36a37947423571be0e55b6"
+dependencies = [
+ "serde",
+ "serde_json",
+]
+
+[[package]]
+name = "safetensors"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "675656c1eabb620b921efea4f9199f97fc86e36dd6ffd1fbbe48d0f59a4987f5"
+dependencies = [
+ "hashbrown 0.16.1",
+ "serde",
+ "serde_json",
+]
+
+[[package]]
+name = "same-file"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "scopeguard"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
+
+[[package]]
+name = "seq-macro"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bc711410fbe7399f390ca1c3b60ad0f53f80e95c5eb935e52268a0e2cd49acc"
+
+[[package]]
+name = "serde"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
+dependencies = [
+ "serde_core",
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_core"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.150"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9"
+dependencies = [
+ "itoa",
+ "memchr",
+ "serde",
+ "serde_core",
+ "zmij",
+]
+
+[[package]]
+name = "shlex"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba"
+
+[[package]]
+name = "simdutf8"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e"
+
+[[package]]
+name = "slab"
+version = "0.4.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
+
+[[package]]
+name = "smallvec"
+version = "1.15.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90"
+
+[[package]]
+name = "stable_deref_trait"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
+
+[[package]]
+name = "syn"
+version = "2.0.118"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "synstructure"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "sysctl"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "01198a2debb237c62b6826ec7081082d951f46dbb64b0e8c7649a452230d1dfc"
+dependencies = [
+ "bitflags 2.13.0",
+ "byteorder",
+ "enum-as-inner",
+ "libc",
+ "thiserror 1.0.69",
+ "walkdir",
+]
+
+[[package]]
+name = "thiserror"
+version = "1.0.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
+dependencies = [
+ "thiserror-impl 1.0.69",
+]
+
+[[package]]
+name = "thiserror"
+version = "2.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
+dependencies = [
+ "thiserror-impl 2.0.18",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "2.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "tinyvec"
+version = "1.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3"
+dependencies = [
+ "tinyvec_macros",
+]
+
+[[package]]
+name = "tinyvec_macros"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
+
+[[package]]
+name = "tracing"
+version = "0.1.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
+dependencies = [
+ "pin-project-lite",
+ "tracing-attributes",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-attributes"
+version = "0.1.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.36"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
+dependencies = [
+ "once_cell",
+]
+
+[[package]]
+name = "typed-path"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e28f89b80c87b8fb0cf04ab448d5dd0dd0ade2f8891bae878de66a75a28600e"
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
+
+[[package]]
+name = "unty"
+version = "0.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae"
+
+[[package]]
+name = "utf8parse"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
+
+[[package]]
+name = "uuid"
+version = "1.23.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf80a72845275afea99e7f2b434723d3bc7e38470fcd1c7ed39a599c73319a53"
+dependencies = [
+ "getrandom 0.4.3",
+ "js-sys",
+ "serde_core",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "version_check"
+version = "0.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
+
+[[package]]
+name = "virtue"
+version = "0.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1"
+
+[[package]]
+name = "walkdir"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
+dependencies = [
+ "same-file",
+ "winapi-util",
+]
+
+[[package]]
+name = "wasi"
+version = "0.11.1+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
+
+[[package]]
+name = "wasip2"
+version = "1.0.4+wasi-0.2.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487"
+dependencies = [
+ "wit-bindgen",
+]
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.126"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+ "rustversion",
+ "wasm-bindgen-macro",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.126"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.126"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e"
+dependencies = [
+ "bumpalo",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.126"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "widestring"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72069c3113ab32ab29e5584db3c6ec55d416895e60715417b5b883a357c3e471"
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
+dependencies = [
+ "windows-sys",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "windows"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-core"
+version = "0.62.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
+dependencies = [
+ "windows-implement",
+ "windows-interface",
+ "windows-link",
+ "windows-result",
+ "windows-strings",
+]
+
+[[package]]
+name = "windows-implement"
+version = "0.60.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "windows-interface"
+version = "0.59.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "windows-link"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
+
+[[package]]
+name = "windows-result"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "windows-strings"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.61.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
+
+[[package]]
+name = "wit-bindgen"
+version = "0.57.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
+
+[[package]]
+name = "yoke"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5"
+dependencies = [
+ "stable_deref_trait",
+ "yoke-derive",
+ "zerofrom",
+]
+
+[[package]]
+name = "yoke-derive"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "synstructure",
+]
+
+[[package]]
+name = "zerocopy"
+version = "0.8.52"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce1022995ff5ff5d841ad7d994facc23098cd40152f2c1d11cd607c6f530653f"
+dependencies = [
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.8.52"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ae7f38b72ec2a254e2b87ef277cf2cd4fb97cbebf944faa6f33354da0867930"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "zerofrom"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272"
+dependencies = [
+ "zerofrom-derive",
+]
+
+[[package]]
+name = "zerofrom-derive"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "synstructure",
+]
+
+[[package]]
+name = "zip"
+version = "7.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c42e33efc22a0650c311c2ef19115ce232583abbe80850bc8b66509ebef02de0"
+dependencies = [
+ "crc32fast",
+ "indexmap",
+ "memchr",
+ "typed-path",
+]
+
+[[package]]
+name = "zmij"
+version = "1.0.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
diff --git a/lingbot-map-rs/Cargo.toml b/lingbot-map-rs/Cargo.toml
new file mode 100644
index 0000000000..487e4a31f6
--- /dev/null
+++ b/lingbot-map-rs/Cargo.toml
@@ -0,0 +1,41 @@
+[workspace]
+resolver = "2"
+members = [
+ "crates/lingbot-memory",
+ "crates/lingbot-tensor",
+]
+
+# Crates added in later iterations (kept out of `members` until they exist so
+# `cargo build` always succeeds):
+# crates/lingbot-model - Geometric Context Transformer (candle)
+# crates/lingbot-io - frame streaming, PNG + MP4 export
+# crates/lingbot-pipeline - streaming inference orchestration
+# crates/lingbot-cli - native demo binary (wgpu point-cloud viewer)
+# crates/lingbot-wasm - WebGPU/WASM demo bindings
+
+[workspace.package]
+version = "0.1.0"
+edition = "2021"
+rust-version = "1.77"
+license = "Apache-2.0"
+authors = ["RuVector Team"]
+repository = "https://github.com/ruvnet/ruvector"
+description = "Standalone Rust port of LingBot-Map: streaming feed-forward 3D reconstruction"
+
+[workspace.dependencies]
+anyhow = "1.0"
+thiserror = "2.0"
+serde = { version = "1.0", features = ["derive"] }
+serde_json = "1.0"
+tracing = "0.1"
+
+# Memory layer: the real ruvector-core API (in-memory, lock-free HNSW).
+# default-features=false drops redb persistence + avx512 (nightly) for a
+# portable, fast-building streaming memory pool.
+ruvector-core = { path = "../crates/ruvector-core", default-features = false, features = ["hnsw", "parallel"] }
+
+# Tensor backend (pure-Rust). Pinned to the workspace-wide candle 0.9.
+candle-core = "0.9"
+candle-nn = "0.9"
+safetensors = "0.4"
+half = "2"
diff --git a/lingbot-map-rs/LICENSE b/lingbot-map-rs/LICENSE
new file mode 100644
index 0000000000..78b1096b05
--- /dev/null
+++ b/lingbot-map-rs/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or Derivative
+ Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and do
+ not modify the License. You may add Your own attribution notices
+ within Derivative Works that You distribute, alongside or as an
+ addendum to the NOTICE text from the Work, provided that such
+ additional attribution notices cannot be construed as modifying
+ the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright 2026 RuVector Team
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/lingbot-map-rs/PROGRESS.md b/lingbot-map-rs/PROGRESS.md
new file mode 100644
index 0000000000..6e2c156ea3
--- /dev/null
+++ b/lingbot-map-rs/PROGRESS.md
@@ -0,0 +1,83 @@
+# LingBot-Map Rust Port — Progress Tracker
+
+> **This file is the source of truth for the `/loop` continuation.** Each loop
+> iteration: read this file, pick the first unchecked step, implement + test +
+> commit + push, then check it off here. Stop the loop only when every box in
+> "Phases" is checked and `cargo test` is green.
+
+## Task
+
+Standalone Rust port of **LingBot-Map** (`robbyant/lingbot-map`, HF, Apache-2.0,
+arXiv:2604.14141): a feed-forward streaming 3D reconstruction foundation model.
+Deliverables requested by the user:
+
+- Full Rust crate port (multi-crate workspace).
+- All ADRs.
+- Demo UI: native (wgpu) **and** WebGPU/WASM, deployed to GitHub Pages.
+- Streaming video output (MP4) + image (PNG) saving.
+- Memory layer ported from PyTorch/FlashInfer paged KV cache to **ruvector-core**
+ HNSW retrieval (see `lingbot-memory`).
+- Borrow the trained model from the original project (safetensors loading path).
+
+## Ground-truth constraints (verified)
+
+- **Environment is offline for crates.io git protocol.** Build with the sparse
+ protocol — handled by `lingbot-map-rs/.cargo/config.toml`. If a build hits a
+ 403 on the git index, that config was bypassed; re-add it.
+- **Standalone repo** = self-contained `lingbot-map-rs/` workspace inside the
+ monorepo (GitHub access is scoped to `ruvnet/ruvector`; a separate repo cannot
+ be created). It is in the root `Cargo.toml` `exclude` list so it never breaks
+ the parent build, and can be split out later unchanged.
+- **The 4.63 GB checkpoint cannot be downloaded/run to completion here.** The
+ real safetensors loading path is wired; a deterministic **synthetic fallback**
+ lets the full pipeline (inference → point cloud → PNG/MP4) run end-to-end
+ without the weights. Full-fidelity SOTA reproduction is explicitly out of
+ scope for the sandbox and is documented as such.
+- candle 0.9 is the tensor backend (already used elsewhere in the monorepo).
+
+## Build & test
+
+```bash
+cd lingbot-map-rs
+cargo build # sparse protocol via .cargo/config.toml
+cargo test
+```
+
+## Phases
+
+- [x] **P0 Foundation** — standalone workspace, `.cargo/config`, root `exclude`,
+ toolchain, README, LICENSE. Builds + tests green.
+- [x] **P1 Memory layer** (`lingbot-memory`) — `StreamingMemory` over real
+ `ruvector-core` `VectorDB` API; insert/retrieve; long-range recall test. ✅
+- [x] **P2 Tensor/config** (`lingbot-tensor`) — `ModelConfig`, safetensors
+ header `WeightIndex` (header-only, no multi-GB load). candle behind feature.
+- [ ] **P3 Model** (`lingbot-model`) — Geometric Context Transformer in candle:
+ patch embed, attention block w/ anchor cross-attention, drift-correction head.
+ Synthetic-weight path + real safetensors path. Unit tests on shapes.
+- [ ] **P4 IO** (`lingbot-io`) — frame source (image crate / synthetic),
+ PNG export, MP4 muxing (streaming). Tests write a tiny PNG + MP4 to tmp.
+- [ ] **P5 Pipeline** (`lingbot-pipeline`) — streaming loop: frame → encode →
+ retrieve_context(top_k) → attention → point cloud; candle⇄&[f32] bridge to
+ `lingbot-memory`. Integration test over N synthetic frames.
+- [ ] **P6 Native demo** (`lingbot-cli`) — wgpu point-cloud viewer + headless
+ render-to-PNG/MP4. `--frames N --out out.mp4`.
+- [ ] **P7 Web demo** (`lingbot-wasm` + `demo/`) — WebGPU renderer, wasm-bindgen
+ bindings, static site. Builds with `wasm-pack` / `cargo build --target wasm32`.
+- [ ] **P8 Deploy** — `.github/workflows/lingbot-pages.yml` (workflow_dispatch +
+ path filter `lingbot-map-rs/**`) publishing `demo/` to GitHub Pages.
+- [ ] **P9 Polish** — top-level README with arch diagram, ADR index, CI for the
+ workspace (`build-lingbot.yml`), final `cargo test` + `cargo clippy` green.
+
+## ADRs (in `docs/adr/`)
+
+- [x] ADR-0001 Standalone workspace & crate topology
+- [x] ADR-0002 ruvector-core streaming memory replaces paged KV cache
+- [x] ADR-0003 candle tensor backend & safetensors weight loading
+- [x] ADR-0004 Rendering (wgpu native + WebGPU/WASM) & GitHub Pages deploy
+- [x] ADR-0005 Streaming MP4 + PNG output pipeline
+- [ ] ADR-0006 Synthetic-fallback strategy & checkpoint provenance (write in P3)
+
+## Next step
+
+→ **P3**: scaffold `lingbot-model` (candle) with the Geometric Context
+Transformer blocks and shape tests; add ADR-0006.
diff --git a/lingbot-map-rs/README.md b/lingbot-map-rs/README.md
new file mode 100644
index 0000000000..b7ac9318f6
--- /dev/null
+++ b/lingbot-map-rs/README.md
@@ -0,0 +1,68 @@
+# lingbot-map-rs
+
+A standalone **Rust port of [LingBot-Map](https://huggingface.co/robbyant/lingbot-map)** —
+a feed-forward, streaming 3D reconstruction foundation model (arXiv:2604.14141,
+Apache-2.0). This port replaces the Python/PyTorch + FlashInfer stack with a
+pure-Rust [candle](https://github.com/huggingface/candle) tensor backend and an
+HNSW trajectory-memory layer backed by
+[`ruvector-core`](../crates/ruvector-core).
+
+> **Status:** active port (see [`PROGRESS.md`](./PROGRESS.md)). The streaming
+> memory layer, model config, and safetensors loading are implemented and
+> tested; the model, IO, pipeline, and demo crates are landing iteratively.
+
+## Why a Rust port?
+
+| Concern | LingBot-Map (Python) | lingbot-map-rs |
+|---|---|---|
+| Tensor backend | PyTorch 2.9 | candle 0.9 (pure Rust, WASM-capable) |
+| Long-range memory | FlashInfer **paged KV cache** in VRAM, forgets past a sliding window | **ruvector-core HNSW**, `O(log N)` retrieval, no VRAM ceiling |
+| Deployment | Python + CUDA | native (wgpu) **and** WebGPU/WASM in the browser |
+
+The headline change is the memory layer: instead of a linearly-growing KV cache
+bounded by GPU VRAM, keyframe features stream into a lock-free HNSW index and the
+transformer retrieves the top-K structurally similar past frames each step —
+solving long-range drift without a forgetful sliding window. See
+[ADR-0002](./docs/adr/ADR-0002-ruvector-streaming-memory.md).
+
+## Crates
+
+| Crate | Purpose |
+|---|---|
+| [`lingbot-memory`](./crates/lingbot-memory) | Streaming trajectory memory over `ruvector-core` (KV-cache replacement) |
+| [`lingbot-tensor`](./crates/lingbot-tensor) | `ModelConfig` + safetensors header indexing + candle weight loading |
+| `lingbot-model` *(landing)* | Geometric Context Transformer (candle) |
+| `lingbot-io` *(landing)* | Frame sources, PNG export, streaming MP4 |
+| `lingbot-pipeline` *(landing)* | Streaming inference orchestration |
+| `lingbot-cli` *(landing)* | Native wgpu demo + headless render |
+| `lingbot-wasm` *(landing)* | WebGPU/WASM browser demo |
+
+## Build & test
+
+```bash
+cd lingbot-map-rs
+cargo build
+cargo test
+```
+
+The build uses the crates.io **sparse** protocol (configured in
+`.cargo/config.toml`) for sandboxed/offline-friendly environments.
+
+## The model checkpoint
+
+The ~4.63 GB checkpoint is **borrowed from the upstream project at runtime**
+(local path or HF download) and never committed. When weights are absent, a
+deterministic synthetic fallback drives the full pipeline so the demo and
+video/image export run end-to-end. See
+[ADR-0003](./docs/adr/ADR-0003-candle-tensor-backend-and-weights.md).
+
+## Architecture Decision Records
+
+See [`docs/adr/`](./docs/adr). ADR-0001 (topology) · 0002 (memory) · 0003
+(tensors/weights) · 0004 (rendering/deploy) · 0005 (MP4/PNG output).
+
+## License
+
+Apache-2.0, matching the upstream LingBot-Map model. See [`LICENSE`](./LICENSE).
+This is an independent reimplementation; model weights remain property of the
+original authors under their license.
diff --git a/lingbot-map-rs/crates/lingbot-memory/Cargo.toml b/lingbot-map-rs/crates/lingbot-memory/Cargo.toml
new file mode 100644
index 0000000000..afeef91b3a
--- /dev/null
+++ b/lingbot-map-rs/crates/lingbot-memory/Cargo.toml
@@ -0,0 +1,20 @@
+[package]
+name = "lingbot-memory"
+version.workspace = true
+edition.workspace = true
+rust-version.workspace = true
+license.workspace = true
+authors.workspace = true
+repository.workspace = true
+description = "Streaming trajectory memory for LingBot-Map: ruvector-core HNSW retrieval replacing the paged KV cache"
+
+[dependencies]
+ruvector-core.workspace = true
+anyhow.workspace = true
+thiserror.workspace = true
+serde.workspace = true
+serde_json.workspace = true
+tracing.workspace = true
+
+[dev-dependencies]
+# deterministic feature generation for tests
diff --git a/lingbot-map-rs/crates/lingbot-memory/src/lib.rs b/lingbot-map-rs/crates/lingbot-memory/src/lib.rs
new file mode 100644
index 0000000000..5a0a39e38f
--- /dev/null
+++ b/lingbot-map-rs/crates/lingbot-memory/src/lib.rs
@@ -0,0 +1,304 @@
+//! # lingbot-memory
+//!
+//! Streaming **trajectory memory** for the LingBot-Map Rust port.
+//!
+//! ## Why this crate exists
+//!
+//! The original LingBot-Map (PyTorch + FlashInfer) manages temporal frame
+//! representations in a **paged KV cache** living in GPU VRAM. That cache grows
+//! linearly with the number of frames; past a few thousand frames the model
+//! either exhausts VRAM or falls back to a *sliding window* that permanently
+//! forgets old geometry, causing long-range drift.
+//!
+//! This crate replaces that mechanism with a lock-free **HNSW** index backed by
+//! [`ruvector_core`]. Keyframe feature vectors are inserted as they stream in;
+//! for each new frame the transformer queries the index for the top-K most
+//! structurally similar past keyframes — whether they occurred 10 frames ago or
+//! 10,000 frames ago — giving O(log N) drift correction with no VRAM ceiling.
+//!
+//! ## Relationship to the `ruvector-core` API
+//!
+//! Earlier design sketches referenced a `VectorDb` / `IndexConfig` /
+//! `MetricType` surface. The *real* `ruvector-core` API is [`VectorDB`] driven
+//! by [`DbOptions`] / [`VectorEntry`] / [`SearchQuery`] / [`SearchResult`].
+//! [`StreamingMemory`] is the thin, intent-revealing wrapper over that real API
+//! — `insert_keyframe` / `retrieve_context` — so the rest of the port speaks in
+//! frame-domain terms (`u64` frame ids, `&[f32]` features) instead of database
+//! terms.
+//!
+//! The wrapper is deliberately **candle-free**: it operates on `&[f32]` slices
+//! so it builds fast and stays testable without a tensor backend. The
+//! `lingbot-pipeline` crate owns the `candle_core::Tensor` <-> `&[f32]` bridge.
+
+use ruvector_core::types::{
+ DbOptions, DistanceMetric, HnswConfig, SearchQuery, VectorEntry,
+};
+use ruvector_core::vector_db::VectorDB;
+
+/// Errors surfaced by the streaming memory layer.
+#[derive(Debug, thiserror::Error)]
+pub enum MemoryError {
+ /// A feature vector did not match the configured dimensionality.
+ #[error("feature dimension mismatch: expected {expected}, got {got}")]
+ DimensionMismatch {
+ /// Configured dimensionality.
+ expected: usize,
+ /// Dimensionality of the supplied vector.
+ got: usize,
+ },
+
+ /// The underlying `ruvector-core` database returned an error.
+ #[error("ruvector-core error: {0}")]
+ Backend(String),
+}
+
+/// Distance metric used to compare keyframe features.
+///
+/// Geometric embeddings are normally L2-normalized, so [`Metric::Cosine`] is the
+/// sensible default for structural similarity.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
+pub enum Metric {
+ /// Cosine similarity (recommended for normalized geometric embeddings).
+ Cosine,
+ /// Euclidean (L2) distance.
+ Euclidean,
+ /// Dot product.
+ DotProduct,
+}
+
+impl From for DistanceMetric {
+ fn from(m: Metric) -> Self {
+ match m {
+ Metric::Cosine => DistanceMetric::Cosine,
+ Metric::Euclidean => DistanceMetric::Euclidean,
+ Metric::DotProduct => DistanceMetric::DotProduct,
+ }
+ }
+}
+
+/// Configuration for the streaming HNSW memory pool.
+#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
+pub struct StreamingMemoryConfig {
+ /// Dimensionality of keyframe feature vectors.
+ pub dimension: usize,
+ /// Distance metric.
+ pub metric: Metric,
+ /// HNSW connections per layer (M). Higher = better recall, more memory.
+ pub hnsw_m: usize,
+ /// HNSW build-time candidate list size (efConstruction).
+ pub ef_construction: usize,
+ /// HNSW query-time candidate list size (efSearch).
+ pub ef_search: usize,
+ /// Upper bound on stored keyframes (pre-allocation hint, not a hard cap on
+ /// streaming length — bump it for very long sessions).
+ pub max_elements: usize,
+}
+
+impl StreamingMemoryConfig {
+ /// Config tuned for dense geometric keyframe lookups at the given dimension.
+ pub fn new(dimension: usize) -> Self {
+ Self {
+ dimension,
+ metric: Metric::Cosine,
+ hnsw_m: 16,
+ ef_construction: 128,
+ ef_search: 64,
+ max_elements: 1_000_000,
+ }
+ }
+}
+
+/// A retrieved keyframe and its similarity score.
+#[derive(Debug, Clone, Copy, PartialEq)]
+pub struct KeyframeMatch {
+ /// Frame id of the matched keyframe.
+ pub frame_id: u64,
+ /// Distance/similarity score (lower is closer for distance metrics).
+ pub score: f32,
+}
+
+/// Streaming trajectory memory: insert keyframes, retrieve drift-correction
+/// anchors. Replaces the paged KV cache of the Python original.
+pub struct StreamingMemory {
+ db: VectorDB,
+ config: StreamingMemoryConfig,
+}
+
+impl StreamingMemory {
+ /// Build an in-memory, lock-free HNSW keyframe index.
+ pub fn new(config: StreamingMemoryConfig) -> Result {
+ let options = DbOptions {
+ dimensions: config.dimension,
+ distance_metric: config.metric.into(),
+ // In-memory backend (no `storage` feature): the storage path is
+ // unused but the field is required.
+ storage_path: String::from(":memory:"),
+ hnsw_config: Some(HnswConfig {
+ m: config.hnsw_m,
+ ef_construction: config.ef_construction,
+ ef_search: config.ef_search,
+ max_elements: config.max_elements,
+ }),
+ quantization: None,
+ };
+
+ let db = VectorDB::new(options).map_err(|e| MemoryError::Backend(e.to_string()))?;
+ Ok(Self { db, config })
+ }
+
+ /// Convenience constructor with defaults for the given dimension.
+ pub fn with_dimension(dimension: usize) -> Result {
+ Self::new(StreamingMemoryConfig::new(dimension))
+ }
+
+ /// The active configuration.
+ pub fn config(&self) -> &StreamingMemoryConfig {
+ &self.config
+ }
+
+ /// Ingest a keyframe's flattened feature vector.
+ ///
+ /// The `frame_id` is stored as the entry id so retrieval can map straight
+ /// back to the streaming timeline. `ruvector-core` is lock-free, so this may
+ /// run on a background ingestion thread while inference proceeds.
+ pub fn insert_keyframe(&self, frame_id: u64, features: &[f32]) -> Result<(), MemoryError> {
+ if features.len() != self.config.dimension {
+ return Err(MemoryError::DimensionMismatch {
+ expected: self.config.dimension,
+ got: features.len(),
+ });
+ }
+
+ let entry = VectorEntry {
+ id: Some(frame_id.to_string()),
+ vector: features.to_vec(),
+ metadata: None,
+ };
+
+ self.db
+ .insert(entry)
+ .map(|_| ())
+ .map_err(|e| MemoryError::Backend(e.to_string()))
+ }
+
+ /// Retrieve the top-K structurally most similar past keyframes for drift
+ /// correction / pose-reference windowing.
+ pub fn retrieve_context(
+ &self,
+ query_features: &[f32],
+ top_k: usize,
+ ) -> Result, MemoryError> {
+ if query_features.len() != self.config.dimension {
+ return Err(MemoryError::DimensionMismatch {
+ expected: self.config.dimension,
+ got: query_features.len(),
+ });
+ }
+
+ let query = SearchQuery {
+ vector: query_features.to_vec(),
+ k: top_k,
+ filter: None,
+ ef_search: Some(self.config.ef_search.max(top_k)),
+ };
+
+ let results = self
+ .db
+ .search(query)
+ .map_err(|e| MemoryError::Backend(e.to_string()))?;
+
+ Ok(results
+ .into_iter()
+ .filter_map(|r| {
+ r.id
+ .parse::()
+ .ok()
+ .map(|frame_id| KeyframeMatch {
+ frame_id,
+ score: r.score,
+ })
+ })
+ .collect())
+ }
+
+ /// Number of keyframes currently held in memory.
+ pub fn len(&self) -> usize {
+ self.db.len().unwrap_or(0)
+ }
+
+ /// Whether the memory pool is empty.
+ pub fn is_empty(&self) -> bool {
+ self.len() == 0
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ /// Deterministic, low-collision synthetic feature. Uses a per-(seed, index)
+ /// hash so distinct frames get distinct vectors with negligible aliasing,
+ /// even across thousands of frames (a smooth `sin(seed)` ramp aliases).
+ fn synth(dim: usize, seed: u64) -> Vec {
+ (0..dim)
+ .map(|i| {
+ let h = (seed.wrapping_mul(0x9E3779B97F4A7C15))
+ ^ (i as u64).wrapping_mul(0xC2B2AE3D27D4EB4F);
+ // map to [-1, 1]
+ ((h >> 11) as f32 / (1u64 << 53) as f32) * 2.0 - 1.0
+ })
+ .collect()
+ }
+
+ #[test]
+ fn metric_maps_to_core() {
+ assert_eq!(DistanceMetric::from(Metric::Cosine), DistanceMetric::Cosine);
+ assert_eq!(
+ DistanceMetric::from(Metric::Euclidean),
+ DistanceMetric::Euclidean
+ );
+ }
+
+ #[test]
+ fn insert_and_count() {
+ let mem = StreamingMemory::with_dimension(64).unwrap();
+ assert!(mem.is_empty());
+ for f in 0..10u64 {
+ mem.insert_keyframe(f, &synth(64, f)).unwrap();
+ }
+ assert_eq!(mem.len(), 10);
+ }
+
+ #[test]
+ fn rejects_wrong_dimension() {
+ let mem = StreamingMemory::with_dimension(32).unwrap();
+ let err = mem.insert_keyframe(0, &synth(16, 0)).unwrap_err();
+ assert!(matches!(err, MemoryError::DimensionMismatch { .. }));
+ }
+
+ #[test]
+ fn retrieves_self_as_nearest() {
+ let dim = 128;
+ let mem = StreamingMemory::with_dimension(dim).unwrap();
+ for f in 0..200u64 {
+ mem.insert_keyframe(f, &synth(dim, f)).unwrap();
+ }
+ // Query with the exact features of frame 137; it should be the top hit.
+ let matches = mem.retrieve_context(&synth(dim, 137), 5).unwrap();
+ assert!(!matches.is_empty());
+ assert_eq!(matches[0].frame_id, 137);
+ }
+
+ #[test]
+ fn long_range_recall_beyond_sliding_window() {
+ // A frame 5000 steps in the past is still retrievable — the property a
+ // fixed sliding-window KV cache cannot provide.
+ let dim = 96;
+ let mem = StreamingMemory::with_dimension(dim).unwrap();
+ for f in 0..5_001u64 {
+ mem.insert_keyframe(f, &synth(dim, f)).unwrap();
+ }
+ let matches = mem.retrieve_context(&synth(dim, 3), 3).unwrap();
+ assert_eq!(matches[0].frame_id, 3);
+ }
+}
diff --git a/lingbot-map-rs/crates/lingbot-tensor/Cargo.toml b/lingbot-map-rs/crates/lingbot-tensor/Cargo.toml
new file mode 100644
index 0000000000..0a5a44e00a
--- /dev/null
+++ b/lingbot-map-rs/crates/lingbot-tensor/Cargo.toml
@@ -0,0 +1,25 @@
+[package]
+name = "lingbot-tensor"
+version.workspace = true
+edition.workspace = true
+rust-version.workspace = true
+license.workspace = true
+authors.workspace = true
+repository.workspace = true
+description = "Model config + safetensors weight loading for the LingBot-Map Rust port"
+
+[features]
+# candle backend is gated so the foundation builds fast in CI; enable for real
+# tensor ops + weight tensors.
+default = []
+candle = ["dep:candle-core", "dep:candle-nn"]
+
+[dependencies]
+anyhow.workspace = true
+thiserror.workspace = true
+serde.workspace = true
+serde_json.workspace = true
+safetensors.workspace = true
+half.workspace = true
+candle-core = { workspace = true, optional = true }
+candle-nn = { workspace = true, optional = true }
diff --git a/lingbot-map-rs/crates/lingbot-tensor/src/config.rs b/lingbot-map-rs/crates/lingbot-tensor/src/config.rs
new file mode 100644
index 0000000000..d68277329d
--- /dev/null
+++ b/lingbot-map-rs/crates/lingbot-tensor/src/config.rs
@@ -0,0 +1,121 @@
+//! Model configuration for the Geometric Context Transformer.
+
+use serde::{Deserialize, Serialize};
+
+/// Hyperparameters of the LingBot-Map Geometric Context Transformer.
+///
+/// Field defaults follow the upstream demo configuration (518x378 input,
+/// streaming inference). Load real values from the checkpoint's `config.json`
+/// via [`ModelConfig::from_file`].
+#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
+pub struct ModelConfig {
+ /// Hidden / model dimension.
+ #[serde(default = "default_hidden")]
+ pub hidden_dim: usize,
+ /// Number of transformer layers.
+ #[serde(default = "default_layers")]
+ pub num_layers: usize,
+ /// Number of attention heads.
+ #[serde(default = "default_heads")]
+ pub num_heads: usize,
+ /// Feed-forward inner dimension.
+ #[serde(default = "default_ffn")]
+ pub ffn_dim: usize,
+ /// Input image height in pixels.
+ #[serde(default = "default_height")]
+ pub image_height: usize,
+ /// Input image width in pixels.
+ #[serde(default = "default_width")]
+ pub image_width: usize,
+ /// Patch size for tokenization.
+ #[serde(default = "default_patch")]
+ pub patch_size: usize,
+ /// Dimensionality of the keyframe feature exported to the memory layer.
+ #[serde(default = "default_feature_dim")]
+ pub keyframe_feature_dim: usize,
+ /// Top-K anchors retrieved per frame for drift correction.
+ #[serde(default = "default_topk")]
+ pub anchor_top_k: usize,
+}
+
+fn default_hidden() -> usize {
+ 1024
+}
+fn default_layers() -> usize {
+ 24
+}
+fn default_heads() -> usize {
+ 16
+}
+fn default_ffn() -> usize {
+ 4096
+}
+fn default_height() -> usize {
+ 378
+}
+fn default_width() -> usize {
+ 518
+}
+fn default_patch() -> usize {
+ 14
+}
+fn default_feature_dim() -> usize {
+ 512
+}
+fn default_topk() -> usize {
+ 16
+}
+
+impl Default for ModelConfig {
+ fn default() -> Self {
+ Self {
+ hidden_dim: default_hidden(),
+ num_layers: default_layers(),
+ num_heads: default_heads(),
+ ffn_dim: default_ffn(),
+ image_height: default_height(),
+ image_width: default_width(),
+ patch_size: default_patch(),
+ keyframe_feature_dim: default_feature_dim(),
+ anchor_top_k: default_topk(),
+ }
+ }
+}
+
+impl ModelConfig {
+ /// Load from a `config.json`-style file.
+ pub fn from_file(path: impl AsRef) -> Result {
+ let bytes = std::fs::read(path)?;
+ Ok(serde_json::from_slice(&bytes)?)
+ }
+
+ /// Number of patch tokens per frame.
+ pub fn num_patches(&self) -> usize {
+ (self.image_height / self.patch_size) * (self.image_width / self.patch_size)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn defaults_are_sane() {
+ let c = ModelConfig::default();
+ assert!(c.hidden_dim > 0 && c.num_heads > 0);
+ assert_eq!(c.hidden_dim % c.num_heads, 0);
+ }
+
+ #[test]
+ fn patch_count() {
+ let c = ModelConfig::default();
+ assert_eq!(c.num_patches(), (378 / 14) * (518 / 14));
+ }
+
+ #[test]
+ fn partial_json_uses_defaults() {
+ let c: ModelConfig = serde_json::from_str(r#"{"hidden_dim": 768}"#).unwrap();
+ assert_eq!(c.hidden_dim, 768);
+ assert_eq!(c.num_layers, default_layers());
+ }
+}
diff --git a/lingbot-map-rs/crates/lingbot-tensor/src/lib.rs b/lingbot-map-rs/crates/lingbot-tensor/src/lib.rs
new file mode 100644
index 0000000000..b928067106
--- /dev/null
+++ b/lingbot-map-rs/crates/lingbot-tensor/src/lib.rs
@@ -0,0 +1,110 @@
+//! # lingbot-tensor
+//!
+//! Model configuration and **safetensors weight loading** for the LingBot-Map
+//! Rust port.
+//!
+//! The upstream checkpoint (`robbyant/lingbot-map`, ~4.63 GB, Apache-2.0) ships
+//! as safetensors. This crate provides:
+//!
+//! * [`ModelConfig`] — the Geometric Context Transformer hyperparameters,
+//! loadable from the upstream `config.json`.
+//! * [`WeightIndex`] — a header-only reader that maps tensor names to shapes /
+//! dtypes **without** loading the multi-GB payload, so we can validate a
+//! checkpoint and plan loading on machines that cannot hold it in RAM.
+//!
+//! Actual tensor materialization into `candle_core::Tensor` lives behind the
+//! `candle` feature (see [`load`]).
+
+use std::collections::BTreeMap;
+
+pub mod config;
+pub use config::ModelConfig;
+
+#[cfg(feature = "candle")]
+pub mod load;
+
+/// Errors from config / weight handling.
+#[derive(Debug, thiserror::Error)]
+pub enum TensorError {
+ /// I/O error reading a file.
+ #[error("io error: {0}")]
+ Io(#[from] std::io::Error),
+ /// JSON (config) parse error.
+ #[error("config parse error: {0}")]
+ Config(#[from] serde_json::Error),
+ /// safetensors parse error.
+ #[error("safetensors error: {0}")]
+ SafeTensors(String),
+}
+
+/// Metadata for a single tensor in a safetensors file (no payload).
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct TensorInfo {
+ /// Element dtype as reported by safetensors (e.g. `F32`, `BF16`).
+ pub dtype: String,
+ /// Tensor shape.
+ pub shape: Vec,
+}
+
+impl TensorInfo {
+ /// Number of elements.
+ pub fn numel(&self) -> usize {
+ self.shape.iter().product()
+ }
+}
+
+/// Header-only view of a safetensors checkpoint: tensor name -> [`TensorInfo`].
+#[derive(Debug, Clone, Default)]
+pub struct WeightIndex {
+ /// Tensor name -> metadata, ordered for stable iteration.
+ pub tensors: BTreeMap,
+}
+
+impl WeightIndex {
+ /// Parse a safetensors file's header without reading tensor data.
+ pub fn from_file(path: impl AsRef) -> Result {
+ let bytes = std::fs::read(path)?;
+ Self::from_bytes(&bytes)
+ }
+
+ /// Parse a safetensors header from an in-memory buffer.
+ pub fn from_bytes(bytes: &[u8]) -> Result {
+ let st = safetensors::SafeTensors::deserialize(bytes)
+ .map_err(|e| TensorError::SafeTensors(e.to_string()))?;
+ let mut tensors = BTreeMap::new();
+ for (name, view) in st.tensors() {
+ tensors.insert(
+ name.to_string(),
+ TensorInfo {
+ dtype: format!("{:?}", view.dtype()),
+ shape: view.shape().to_vec(),
+ },
+ );
+ }
+ Ok(Self { tensors })
+ }
+
+ /// Total parameter count across all tensors.
+ pub fn total_params(&self) -> usize {
+ self.tensors.values().map(TensorInfo::numel).sum()
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn tensorinfo_numel() {
+ let t = TensorInfo {
+ dtype: "F32".into(),
+ shape: vec![2, 3, 4],
+ };
+ assert_eq!(t.numel(), 24);
+ }
+
+ #[test]
+ fn empty_index_has_zero_params() {
+ assert_eq!(WeightIndex::default().total_params(), 0);
+ }
+}
diff --git a/lingbot-map-rs/docs/adr/ADR-0001-standalone-workspace-and-crate-topology.md b/lingbot-map-rs/docs/adr/ADR-0001-standalone-workspace-and-crate-topology.md
new file mode 100644
index 0000000000..3f31b16d35
--- /dev/null
+++ b/lingbot-map-rs/docs/adr/ADR-0001-standalone-workspace-and-crate-topology.md
@@ -0,0 +1,56 @@
+# ADR-0001: Standalone Workspace & Crate Topology
+
+- **Status**: Accepted
+- **Date**: 2026-06-27
+- **Context**: LingBot-Map Rust port
+
+## Context
+
+We are porting [LingBot-Map](https://huggingface.co/robbyant/lingbot-map) — a
+feed-forward streaming 3D reconstruction foundation model (PyTorch + FlashInfer)
+— to Rust. The port must be a *standalone* deliverable: its own workspace,
+buildable and splittable into its own repository, while currently living inside
+the `ruvnet/ruvector` monorepo (the only repository this effort has write access
+to).
+
+## Decision
+
+Create a self-contained Cargo workspace at `lingbot-map-rs/` with a focused set
+of single-responsibility crates:
+
+| Crate | Responsibility |
+|--------------------|----------------|
+| `lingbot-memory` | Streaming trajectory memory over `ruvector-core` HNSW (KV-cache replacement). Candle-free; operates on `&[f32]`. |
+| `lingbot-tensor` | `ModelConfig`, safetensors header indexing, candle weight materialization (feature-gated). |
+| `lingbot-model` | Geometric Context Transformer (candle): patch embedding, anchor cross-attention, drift-correction head. |
+| `lingbot-io` | Frame sources, PNG export, streaming MP4 muxing. |
+| `lingbot-pipeline` | Streaming inference orchestration; candle ⇄ memory bridge. |
+| `lingbot-cli` | Native demo: wgpu point-cloud viewer + headless render. |
+| `lingbot-wasm` | WebGPU/WASM bindings for the browser demo. |
+
+The workspace is added to the monorepo root `Cargo.toml` `exclude` list so it
+never participates in (or breaks) the parent build, and so it can be lifted out
+verbatim into its own repo.
+
+## Rationale
+
+- **Bounded contexts**: memory, tensors, model, IO, and presentation are
+ independent concerns with different dependency weights. Keeping
+ `lingbot-memory` candle-free means it compiles in seconds and is unit-testable
+ without a tensor backend.
+- **Fast CI**: heavy dependencies (candle, wgpu) are isolated to the crates that
+ need them and gated behind features where possible.
+- **Splittability**: path dependencies + `exclude` keep the port a clean island.
+
+## Consequences
+
+- `ruvector-core` is referenced by relative path (`../crates/ruvector-core`);
+ splitting the repo later means switching to a git/version dependency.
+- The crate list in `[workspace].members` grows as crates land; crates are added
+ to `members` only once they exist so `cargo build` is always green.
+
+## Build note
+
+The sandbox build environment blocks the crates.io **git** index protocol.
+`lingbot-map-rs/.cargo/config.toml` forces the **sparse** protocol
+(`index.crates.io`, allow-listed). See PROGRESS.md.
diff --git a/lingbot-map-rs/docs/adr/ADR-0002-ruvector-streaming-memory.md b/lingbot-map-rs/docs/adr/ADR-0002-ruvector-streaming-memory.md
new file mode 100644
index 0000000000..84c5c2f822
--- /dev/null
+++ b/lingbot-map-rs/docs/adr/ADR-0002-ruvector-streaming-memory.md
@@ -0,0 +1,55 @@
+# ADR-0002: ruvector-core Streaming Memory Replaces the Paged KV Cache
+
+- **Status**: Accepted
+- **Date**: 2026-06-27
+
+## Context
+
+LingBot-Map streams 3D reconstruction from video. The PyTorch original manages
+temporal frame representations in a **paged KV cache** (FlashInfer) resident in
+GPU VRAM. This cache grows linearly with frame count: past a few thousand frames
+the model exhausts VRAM and must switch to a **sliding window** (`--mode
+windowed` with keyframe overlap), which permanently forgets older geometry and
+reintroduces long-range trajectory drift.
+
+## Decision
+
+Replace the paged KV cache with a lock-free **HNSW** index backed by
+[`ruvector-core`], exposed through `lingbot-memory::StreamingMemory`:
+
+- `insert_keyframe(frame_id: u64, features: &[f32])` — ingest a keyframe's
+ flattened geometric feature vector. Lock-free, so it can run on a background
+ ingestion thread while inference proceeds.
+- `retrieve_context(query: &[f32], top_k)` — fetch the top-K structurally most
+ similar past keyframes (any distance back in time) for drift correction and
+ pose-reference windowing.
+
+Frame ids are stored as `VectorEntry` ids and parsed back on retrieval, so the
+database speaks the streaming timeline directly.
+
+### Complexity & capacity
+
+| | Paged KV (linear scan / window) | ruvector HNSW |
+|---|---|---|
+| Lookup cost | `O(N·d)` (or window-bounded, forgetful) | `O(log N · d)` |
+| Capacity | GPU VRAM | system RAM (mmap-backed when persisted) |
+| Long-range recall | lost beyond window | preserved for all N |
+
+## API reality
+
+Earlier sketches referenced a `VectorDb` / `IndexConfig` / `MetricType` surface.
+The **real** `ruvector-core` API is `VectorDB` driven by `DbOptions`,
+`VectorEntry`, `SearchQuery`, and `SearchResult`. `StreamingMemory` is the thin,
+intent-revealing adapter over that real API. We build it with
+`default-features = false, features = ["hnsw", "parallel"]` to get an in-memory,
+lock-free index without pulling redb persistence or AVX-512 (nightly).
+
+## Consequences
+
+- The windowed-mode code path of the original is eliminated; memory is global,
+ persistent (optionally), and dynamically retrieved.
+- Retrieval returns *candidate anchors* — the model still loads/attends to only
+ those K frames, bounding per-step attention cost regardless of total N.
+- HNSW is approximate; `ef_search` is tunable (`StreamingMemoryConfig`) to trade
+ recall vs latency. Verified: exact-feature query returns its own frame as the
+ top hit, including at a 5000-frame range (see crate tests).
diff --git a/lingbot-map-rs/docs/adr/ADR-0003-candle-tensor-backend-and-weights.md b/lingbot-map-rs/docs/adr/ADR-0003-candle-tensor-backend-and-weights.md
new file mode 100644
index 0000000000..cb3e1b1f80
--- /dev/null
+++ b/lingbot-map-rs/docs/adr/ADR-0003-candle-tensor-backend-and-weights.md
@@ -0,0 +1,45 @@
+# ADR-0003: candle Tensor Backend & safetensors Weight Loading
+
+- **Status**: Accepted
+- **Date**: 2026-06-27
+
+## Context
+
+The port needs a Rust tensor/NN framework to express the Geometric Context
+Transformer, plus a way to load the upstream checkpoint (~4.63 GB safetensors).
+
+## Decision
+
+Use **candle 0.9** (`candle-core`, `candle-nn`) — already a vendored dependency
+elsewhere in the monorepo (`ruvllm`, `timesfm`), so versions are consistent and
+the crates are cached.
+
+Weight handling is split in two:
+
+1. **Header-only indexing** (`lingbot-tensor::WeightIndex`) — parses the
+ safetensors header to map tensor name → shape/dtype **without** reading the
+ multi-GB payload. This validates a checkpoint and lets us plan loading on
+ machines that cannot hold the weights in RAM.
+2. **Materialization** (`lingbot-tensor::load`, behind the `candle` feature) —
+ loads named tensors into `candle_core::Tensor` on a chosen `Device`.
+
+`ModelConfig` is `serde`-loaded from the upstream `config.json` with sane
+defaults (1024 hidden, 24 layers, 16 heads, 518×378 input, patch 14).
+
+## Rationale
+
+- Pure-Rust (no libtorch) keeps the port portable and WASM-friendly.
+- Header-only indexing decouples "do we have a valid checkpoint" from "can we
+ fit it in memory" — essential in constrained/sandbox environments.
+- Feature-gating candle keeps `lingbot-tensor`'s default build fast for CI and
+ for crates (like `lingbot-memory`) that don't need tensors.
+
+## Consequences
+
+- candle 0.9 op coverage bounds what we can express; any missing op is
+ implemented manually on `Tensor` data.
+- bf16/f16 checkpoints are supported via `half`; dtype is surfaced by
+ `TensorInfo.dtype`.
+- The real checkpoint is *borrowed* from the upstream project at runtime (path
+ or HF download), never committed. See ADR-0006 for the synthetic fallback used
+ when weights are absent.
diff --git a/lingbot-map-rs/docs/adr/ADR-0004-rendering-and-deployment.md b/lingbot-map-rs/docs/adr/ADR-0004-rendering-and-deployment.md
new file mode 100644
index 0000000000..b89001bdad
--- /dev/null
+++ b/lingbot-map-rs/docs/adr/ADR-0004-rendering-and-deployment.md
@@ -0,0 +1,42 @@
+# ADR-0004: Rendering (wgpu native + WebGPU/WASM) & GitHub Pages Deploy
+
+- **Status**: Accepted
+- **Date**: 2026-06-27
+
+## Context
+
+The deliverable includes a demo UI that runs the streaming reconstruction and
+visualizes the resulting 3D point cloud, available both as a native app and in
+the browser, deployed to GitHub Pages.
+
+## Decision
+
+- **Single renderer, two targets** via [`wgpu`]. `wgpu` targets native (Vulkan/
+ Metal/DX12) and the browser (WebGPU) from one codebase, so the point-cloud
+ renderer is written once.
+ - Native: `lingbot-cli` opens a `winit` window (interactive) or runs headless,
+ rendering frames to an offscreen texture for PNG/MP4 export.
+ - Web: `lingbot-wasm` compiles to `wasm32-unknown-unknown`, exposes
+ wasm-bindgen entry points, and drives a `
diff --git a/lingbot-map-rs/demo/main.js b/streamcloud-rs/demo/main.js
similarity index 97%
rename from lingbot-map-rs/demo/main.js
rename to streamcloud-rs/demo/main.js
index 135f2b847a..073b60ba48 100644
--- a/lingbot-map-rs/demo/main.js
+++ b/streamcloud-rs/demo/main.js
@@ -1,10 +1,10 @@
-// LingBot-Map Rust port — WebGPU browser demo.
+// StreamCloud — WebGPU browser demo.
//
// Loads the Rust pipeline (compiled to WASM) and renders the streaming 3D
// reconstruction with WebGPU. Falls back to a 2D canvas renderer when WebGPU is
// unavailable so the page always shows something.
-import init, { LingbotDemo } from './pkg/lingbot_wasm.js';
+import init, { StreamCloudDemo } from './pkg/streamcloud_wasm.js';
const SCENE_W = 256, SCENE_H = 192, TOP_K = 16;
const STRIDE = 6; // floats per point: x,y,z,r,g,b
@@ -173,7 +173,7 @@ function fallback2D(canvas) {
async function main() {
await init();
- const demo = new LingbotDemo(SCENE_W, SCENE_H, TOP_K);
+ const demo = new StreamCloudDemo(SCENE_W, SCENE_H, TOP_K);
const canvas = el('gpu');
const renderer = (await tryWebGPU(canvas)) || fallback2D(canvas);
ui.backend.textContent = renderer.name;
diff --git a/lingbot-map-rs/demo/style.css b/streamcloud-rs/demo/style.css
similarity index 100%
rename from lingbot-map-rs/demo/style.css
rename to streamcloud-rs/demo/style.css
diff --git a/lingbot-map-rs/docs/adr/ADR-0001-standalone-workspace-and-crate-topology.md b/streamcloud-rs/docs/adr/ADR-0001-standalone-workspace-and-crate-topology.md
similarity index 64%
rename from lingbot-map-rs/docs/adr/ADR-0001-standalone-workspace-and-crate-topology.md
rename to streamcloud-rs/docs/adr/ADR-0001-standalone-workspace-and-crate-topology.md
index 3f31b16d35..3a82401540 100644
--- a/lingbot-map-rs/docs/adr/ADR-0001-standalone-workspace-and-crate-topology.md
+++ b/streamcloud-rs/docs/adr/ADR-0001-standalone-workspace-and-crate-topology.md
@@ -2,7 +2,7 @@
- **Status**: Accepted
- **Date**: 2026-06-27
-- **Context**: LingBot-Map Rust port
+- **Context**: StreamCloud
## Context
@@ -15,18 +15,18 @@ to).
## Decision
-Create a self-contained Cargo workspace at `lingbot-map-rs/` with a focused set
+Create a self-contained Cargo workspace at `streamcloud-rs/` with a focused set
of single-responsibility crates:
| Crate | Responsibility |
|--------------------|----------------|
-| `lingbot-memory` | Streaming trajectory memory over `ruvector-core` HNSW (KV-cache replacement). Candle-free; operates on `&[f32]`. |
-| `lingbot-tensor` | `ModelConfig`, safetensors header indexing, candle weight materialization (feature-gated). |
-| `lingbot-model` | Geometric Context Transformer (candle): patch embedding, anchor cross-attention, drift-correction head. |
-| `lingbot-io` | Frame sources, PNG export, streaming MP4 muxing. |
-| `lingbot-pipeline` | Streaming inference orchestration; candle ⇄ memory bridge. |
-| `lingbot-cli` | Native demo: wgpu point-cloud viewer + headless render. |
-| `lingbot-wasm` | WebGPU/WASM bindings for the browser demo. |
+| `streamcloud-memory` | Streaming trajectory memory over `ruvector-core` HNSW (KV-cache replacement). Candle-free; operates on `&[f32]`. |
+| `streamcloud-tensor` | `ModelConfig`, safetensors header indexing, candle weight materialization (feature-gated). |
+| `streamcloud-model` | Geometric Context Transformer (candle): patch embedding, anchor cross-attention, drift-correction head. |
+| `streamcloud-io` | Frame sources, PNG export, streaming MP4 muxing. |
+| `streamcloud-pipeline` | Streaming inference orchestration; candle ⇄ memory bridge. |
+| `streamcloud-cli` | Native demo: wgpu point-cloud viewer + headless render. |
+| `streamcloud-wasm` | WebGPU/WASM bindings for the browser demo. |
The workspace is added to the monorepo root `Cargo.toml` `exclude` list so it
never participates in (or breaks) the parent build, and so it can be lifted out
@@ -36,7 +36,7 @@ verbatim into its own repo.
- **Bounded contexts**: memory, tensors, model, IO, and presentation are
independent concerns with different dependency weights. Keeping
- `lingbot-memory` candle-free means it compiles in seconds and is unit-testable
+ `streamcloud-memory` candle-free means it compiles in seconds and is unit-testable
without a tensor backend.
- **Fast CI**: heavy dependencies (candle, wgpu) are isolated to the crates that
need them and gated behind features where possible.
@@ -52,5 +52,5 @@ verbatim into its own repo.
## Build note
The sandbox build environment blocks the crates.io **git** index protocol.
-`lingbot-map-rs/.cargo/config.toml` forces the **sparse** protocol
+`streamcloud-rs/.cargo/config.toml` forces the **sparse** protocol
(`index.crates.io`, allow-listed). See PROGRESS.md.
diff --git a/lingbot-map-rs/docs/adr/ADR-0002-ruvector-streaming-memory.md b/streamcloud-rs/docs/adr/ADR-0002-ruvector-streaming-memory.md
similarity index 97%
rename from lingbot-map-rs/docs/adr/ADR-0002-ruvector-streaming-memory.md
rename to streamcloud-rs/docs/adr/ADR-0002-ruvector-streaming-memory.md
index 84c5c2f822..c083ebde6c 100644
--- a/lingbot-map-rs/docs/adr/ADR-0002-ruvector-streaming-memory.md
+++ b/streamcloud-rs/docs/adr/ADR-0002-ruvector-streaming-memory.md
@@ -15,7 +15,7 @@ reintroduces long-range trajectory drift.
## Decision
Replace the paged KV cache with a lock-free **HNSW** index backed by
-[`ruvector-core`], exposed through `lingbot-memory::StreamingMemory`:
+[`ruvector-core`], exposed through `streamcloud-memory::StreamingMemory`:
- `insert_keyframe(frame_id: u64, features: &[f32])` — ingest a keyframe's
flattened geometric feature vector. Lock-free, so it can run on a background
diff --git a/lingbot-map-rs/docs/adr/ADR-0003-candle-tensor-backend-and-weights.md b/streamcloud-rs/docs/adr/ADR-0003-candle-tensor-backend-and-weights.md
similarity index 83%
rename from lingbot-map-rs/docs/adr/ADR-0003-candle-tensor-backend-and-weights.md
rename to streamcloud-rs/docs/adr/ADR-0003-candle-tensor-backend-and-weights.md
index cb3e1b1f80..7907ee275f 100644
--- a/lingbot-map-rs/docs/adr/ADR-0003-candle-tensor-backend-and-weights.md
+++ b/streamcloud-rs/docs/adr/ADR-0003-candle-tensor-backend-and-weights.md
@@ -16,11 +16,11 @@ the crates are cached.
Weight handling is split in two:
-1. **Header-only indexing** (`lingbot-tensor::WeightIndex`) — parses the
+1. **Header-only indexing** (`streamcloud-tensor::WeightIndex`) — parses the
safetensors header to map tensor name → shape/dtype **without** reading the
multi-GB payload. This validates a checkpoint and lets us plan loading on
machines that cannot hold the weights in RAM.
-2. **Materialization** (`lingbot-tensor::load`, behind the `candle` feature) —
+2. **Materialization** (`streamcloud-tensor::load`, behind the `candle` feature) —
loads named tensors into `candle_core::Tensor` on a chosen `Device`.
`ModelConfig` is `serde`-loaded from the upstream `config.json` with sane
@@ -31,8 +31,8 @@ defaults (1024 hidden, 24 layers, 16 heads, 518×378 input, patch 14).
- Pure-Rust (no libtorch) keeps the port portable and WASM-friendly.
- Header-only indexing decouples "do we have a valid checkpoint" from "can we
fit it in memory" — essential in constrained/sandbox environments.
-- Feature-gating candle keeps `lingbot-tensor`'s default build fast for CI and
- for crates (like `lingbot-memory`) that don't need tensors.
+- Feature-gating candle keeps `streamcloud-tensor`'s default build fast for CI and
+ for crates (like `streamcloud-memory`) that don't need tensors.
## Consequences
diff --git a/lingbot-map-rs/docs/adr/ADR-0004-rendering-and-deployment.md b/streamcloud-rs/docs/adr/ADR-0004-rendering-and-deployment.md
similarity index 84%
rename from lingbot-map-rs/docs/adr/ADR-0004-rendering-and-deployment.md
rename to streamcloud-rs/docs/adr/ADR-0004-rendering-and-deployment.md
index b89001bdad..0ff52b29cb 100644
--- a/lingbot-map-rs/docs/adr/ADR-0004-rendering-and-deployment.md
+++ b/streamcloud-rs/docs/adr/ADR-0004-rendering-and-deployment.md
@@ -14,14 +14,14 @@ the browser, deployed to GitHub Pages.
- **Single renderer, two targets** via [`wgpu`]. `wgpu` targets native (Vulkan/
Metal/DX12) and the browser (WebGPU) from one codebase, so the point-cloud
renderer is written once.
- - Native: `lingbot-cli` opens a `winit` window (interactive) or runs headless,
+ - Native: `streamcloud-cli` opens a `winit` window (interactive) or runs headless,
rendering frames to an offscreen texture for PNG/MP4 export.
- - Web: `lingbot-wasm` compiles to `wasm32-unknown-unknown`, exposes
+ - Web: `streamcloud-wasm` compiles to `wasm32-unknown-unknown`, exposes
wasm-bindgen entry points, and drives a `` WebGPU context.
- **Static site** in `demo/`: HTML/JS shell + the wasm bundle + a small set of
bundled synthetic frames so the page is interactive without the 4.63 GB model.
-- **Deploy** via `.github/workflows/lingbot-pages.yml`:
- - Triggers: `workflow_dispatch` + push filtered to `lingbot-map-rs/**` (so it
+- **Deploy** via `.github/workflows/streamcloud-pages.yml`:
+ - Triggers: `workflow_dispatch` + push filtered to `streamcloud-rs/**` (so it
never runs on unrelated monorepo changes).
- Builds wasm with `wasm-pack`, assembles `demo/`, publishes with
`actions/deploy-pages`.
diff --git a/lingbot-map-rs/docs/adr/ADR-0005-streaming-mp4-png-output.md b/streamcloud-rs/docs/adr/ADR-0005-streaming-mp4-png-output.md
similarity index 93%
rename from lingbot-map-rs/docs/adr/ADR-0005-streaming-mp4-png-output.md
rename to streamcloud-rs/docs/adr/ADR-0005-streaming-mp4-png-output.md
index 0ff853313c..17ea8c1589 100644
--- a/lingbot-map-rs/docs/adr/ADR-0005-streaming-mp4-png-output.md
+++ b/streamcloud-rs/docs/adr/ADR-0005-streaming-mp4-png-output.md
@@ -11,7 +11,7 @@ reconstruction.
## Decision
-`lingbot-io` owns all encoding:
+`streamcloud-io` owns all encoding:
- **PNG**: per-frame export via the `image` crate (`RgbaImage::save`). Used for
keyframe snapshots and the final still.
@@ -30,7 +30,7 @@ reconstruction.
- The `image` crate is pure-Rust and trivial for PNG.
- Piping raw frames to ffmpeg is the simplest robust path to broadly-compatible
H.264 MP4; the pure-Rust fallback keeps CI hermetic.
-- A `FrameSink` trait keeps `lingbot-pipeline` independent of the sink and makes
+- A `FrameSink` trait keeps `streamcloud-pipeline` independent of the sink and makes
the encoders unit-testable (write a 2-frame clip to a temp dir).
## Consequences
diff --git a/lingbot-map-rs/docs/adr/ADR-0006-synthetic-fallback-and-provenance.md b/streamcloud-rs/docs/adr/ADR-0006-synthetic-fallback-and-provenance.md
similarity index 93%
rename from lingbot-map-rs/docs/adr/ADR-0006-synthetic-fallback-and-provenance.md
rename to streamcloud-rs/docs/adr/ADR-0006-synthetic-fallback-and-provenance.md
index 9052250956..261c64f0a2 100644
--- a/lingbot-map-rs/docs/adr/ADR-0006-synthetic-fallback-and-provenance.md
+++ b/streamcloud-rs/docs/adr/ADR-0006-synthetic-fallback-and-provenance.md
@@ -13,7 +13,7 @@ inference → 3D point cloud → PNG/MP4 → native + WebGPU demos.
## Decision
-Provide two interchangeable backends behind one `lingbot-model::Reconstructor`
+Provide two interchangeable backends behind one `streamcloud-model::Reconstructor`
interface:
1. **`SyntheticReconstructor`** (default, pure-Rust, `wasm32`-safe) — derives a
@@ -35,7 +35,7 @@ the trained model**. It is a harness, not a reconstruction claim.
- The upstream model is Apache-2.0; this port is an independent reimplementation
and carries the same license. Model weights remain the original authors'
property under their license.
-- `lingbot-tensor::WeightIndex` validates a checkpoint's tensor inventory
+- `streamcloud-tensor::WeightIndex` validates a checkpoint's tensor inventory
(names/shapes/dtype) without loading the payload, so provenance/compatibility
can be checked on constrained machines.
diff --git a/lingbot-map-rs/rust-toolchain.toml b/streamcloud-rs/rust-toolchain.toml
similarity index 100%
rename from lingbot-map-rs/rust-toolchain.toml
rename to streamcloud-rs/rust-toolchain.toml