Context
We were evaluating examples/ruvLLM/esp32-flash as a candidate set of primitives (HNSW vector index, RAG, anomaly detection, on-device inference) for an embedded agent harness running on an ESP32-S3-class board. We cloned ruvnet/ruvector at commit 20aca12 and tried both the documented host-side test path and the documented "1-click web flasher" path.
Both paths failed before any code ran on the device. Filing this so the gap is visible.
Observation 1 — host-test feature does not build
Cargo.toml advertises a host-test feature ("for development testing only", per src/main.rs:732). Out of the box, cargo build --no-default-features --features host-test fails for two distinct reasons.
1a. build.rs unconditionally calls an espidf-only API:
// build.rs
fn main() {
embuild::espidf::sysenv::output();
}
embuild::espidf is gated behind the espidf feature on embuild, which is not enabled in host-test mode, so the build script itself fails to compile:
error[E0433]: cannot find `espidf` in `embuild`
--> build.rs:2:14
|
2 | embuild::espidf::sysenv::output();
| ^^^^^^ could not find `espidf` in `embuild`
A #[cfg(target_os = "espidf")] guard on that call lets the build script proceed in host mode.
1b. After fixing 1a, src/main.rs does not compile against src/lib.rs: 27 errors. The example is using an API that the library no longer exports. Examples (line numbers in src/main.rs):
main.rs reference |
Actual signature in lib.rs / submodules |
LoRAConfig { rank, alpha, input_dim, output_dim } (L242) |
LoRAConfig { rank, dim, scale, frozen } (src/optimizations/micro_lora.rs:9) |
MicroLoRA::new(c) (L197) |
MicroLoRA::new(config, seed) -> Result<Self> (micro_lora.rs:31) |
lora.forward(&attn_out) (L207) |
method is apply(&mut self, input, output) (micro_lora.rs:62) |
PQConfig { dim, num_subspaces, num_centroids } (L249–251) |
PQConfig does not have num_subspaces / num_centroids |
DraftVerifyConfig { draft_length, max_rejections, temperature, verify_all } (L340–344) |
DraftVerifyConfig has none of those last three fields |
BinaryVector::new() / ProductQuantizer::new() |
both are generic structs requiring const generics; no zero-arg new() |
SparseAttention::get_mask(seq_pos) (L125) |
method does not exist on SparseAttention |
LayerPruner::is_pruned(idx) (L166) |
method does not exist on LayerPruner |
MemoryType::Factual (L417) |
variant does not exist on MemoryType |
engine.add_knowledge(...)? (L417) |
underlying error type does not implement From<…> for ruvllm_esp32::Error, so ? does not compile |
Full error count from cargo build --no-default-features --features host-test --target x86_64-unknown-linux-gnu: 27 errors, 2 warnings.
Observation 2 — No ESP32 firmware exists in any GitHub release
npm/web-flasher/index.html advertises a 1-click flasher and downloads firmware from:
const FIRMWARE_BASE_URL = 'https://github.com/ruvnet/ruvector/releases/latest/download';
const firmwareUrl = `${FIRMWARE_BASE_URL}/ruvllm-esp32-${target}`;
Querying the GitHub API for all 28 releases (gh api repos/ruvnet/ruvector/releases), zero of them contain any asset whose name matches esp32 or ruvllm. Latest release v2.2.0 (2026-04-20) only ships ruvector-attention-* and ruvector-math-wasm archives. The web flasher's fetch URL therefore 404s for every supported target (esp32, esp32s2, esp32s3, esp32c3, esp32c6).
The fallback in npm/bin/cli.js's flash command is to build from source first — which fails per Observation 1.
Observation 3 — README/docs vs. code
src/main.rs is presented as a "Full-Feature LLM v0.2" with "INT8/Binary quantized transformer inference", "MicroLoRA on-device adaptation", "Sparse attention patterns", and "Speculative decoding". Reading the example as written, those claims don't hold up:
- Weights are never loaded; they're generated from index arithmetic.
QuantizedWeights::new (L62–70) initializes every weight to ((i * 17 + 31) % 256) - 64. EmbeddingTable::new (L82–90) is the same shape. The LoRA a_weights PRNG (micro_lora.rs:38–44) is also seeded deterministically. There is a MicroLoRA::from_weights constructor (micro_lora.rs:53) and a from_weights-style entry would be the natural place to load a checkpoint, but nothing in the example crate calls it and there is no checkpoint format / loader / weight file in tree. So the "model" running on the device is a fixed function of source code, not learned parameters.
MicroAttention::forward (L123–139) is not attention. No Q·Kᵀ, no softmax, no V multiply. The body is output[i] = (input[i] * weight[i % len]) >> 7 gated by a sparse mask — i.e. a single elementwise multiply, not scaled-dot-product attention over a sequence.
FeedForward::forward (L161–176) is not a 2-layer MLP. It does one elementwise multiply against w1, ReLU, and writes out — no expansion to 4*EMBED_DIM, no second projection through w2. w2 is allocated and never read.
TinyModel::forward (L269–299) takes a single token and returns a single token deterministically. No KV cache, no sequence context beyond the sparse-mask seq_pos index. As a result, gen <text> produces the same byte sequence on every call for a given input.
If the intent is that this file is a structural skeleton / sizing demo rather than a working inference path, that's fine, but the README and the in-source doc comment ("Full-featured LLM inference engine for ESP32 with INT8/Binary quantized transformer inference") read as a real model. A one-line note in the example README ("this example demonstrates the on-device control surface and memory layout; weights are placeholders, not a trained model") would prevent people from going down the same evaluation path we did.
Reproduction
git clone https://github.com/ruvnet/ruvector.git
cd ruvector/examples/ruvLLM/esp32-flash
# Path A — host test (per Cargo.toml feature comment)
cargo build --no-default-features --features host-test
# => build.rs E0433, then 27 example errors after patching build.rs
# Path B — web flasher
# Open npm/web-flasher/index.html, click flash → 404 on ruvllm-esp32-* asset
# Path C — npm cli (compiles from source first)
node npm/bin/cli.js flash --target esp32s3
# => same 27 errors as Path A
Related
May overlap with the recently filed series #399, #400, #401, #402 reporting that other published demo/CLI surfaces are missing assets or out of sync with the library. Filing separately because those are about ruvector-cli, not examples/ruvLLM/esp32-flash.
Environment
- Linux x86_64, rustc 1.95.0
ruvnet/ruvector at 20aca12 (latest main at time of filing)
- ESP32-S3 device present and detected at
/dev/ttyACM0 (USB ID 303a:1001); not flashed because no firmware could be produced.
What would unblock evaluation
- A
host-test build that compiles end-to-end (or removal of the feature if it's no longer supported).
- Either a published ESP32 firmware asset matching the URL pattern in
npm/web-flasher/index.html, or an updated flasher that points at where firmware actually lives.
- A note in
examples/ruvLLM/esp32-flash/README.md clarifying whether the in-tree main.rs is meant to demonstrate inference behaviour or is a structural placeholder pending a separate model-loader path.
Happy to test fixes against the same hardware.
Context
We were evaluating
examples/ruvLLM/esp32-flashas a candidate set of primitives (HNSW vector index, RAG, anomaly detection, on-device inference) for an embedded agent harness running on an ESP32-S3-class board. We clonedruvnet/ruvectorat commit20aca12and tried both the documented host-side test path and the documented "1-click web flasher" path.Both paths failed before any code ran on the device. Filing this so the gap is visible.
Observation 1 —
host-testfeature does not buildCargo.tomladvertises ahost-testfeature ("for development testing only", persrc/main.rs:732). Out of the box,cargo build --no-default-features --features host-testfails for two distinct reasons.1a.
build.rsunconditionally calls an espidf-only API:embuild::espidfis gated behind theespidffeature onembuild, which is not enabled inhost-testmode, so the build script itself fails to compile:A
#[cfg(target_os = "espidf")]guard on that call lets the build script proceed in host mode.1b. After fixing 1a,
src/main.rsdoes not compile againstsrc/lib.rs: 27 errors. The example is using an API that the library no longer exports. Examples (line numbers insrc/main.rs):main.rsreferencelib.rs/ submodulesLoRAConfig { rank, alpha, input_dim, output_dim }(L242)LoRAConfig { rank, dim, scale, frozen }(src/optimizations/micro_lora.rs:9)MicroLoRA::new(c)(L197)MicroLoRA::new(config, seed) -> Result<Self>(micro_lora.rs:31)lora.forward(&attn_out)(L207)apply(&mut self, input, output)(micro_lora.rs:62)PQConfig { dim, num_subspaces, num_centroids }(L249–251)PQConfigdoes not havenum_subspaces/num_centroidsDraftVerifyConfig { draft_length, max_rejections, temperature, verify_all }(L340–344)DraftVerifyConfighas none of those last three fieldsBinaryVector::new()/ProductQuantizer::new()new()SparseAttention::get_mask(seq_pos)(L125)SparseAttentionLayerPruner::is_pruned(idx)(L166)LayerPrunerMemoryType::Factual(L417)MemoryTypeengine.add_knowledge(...)?(L417)From<…>forruvllm_esp32::Error, so?does not compileFull error count from
cargo build --no-default-features --features host-test --target x86_64-unknown-linux-gnu: 27 errors, 2 warnings.Observation 2 — No ESP32 firmware exists in any GitHub release
npm/web-flasher/index.htmladvertises a 1-click flasher and downloads firmware from:Querying the GitHub API for all 28 releases (
gh api repos/ruvnet/ruvector/releases), zero of them contain any asset whose name matchesesp32orruvllm. Latest releasev2.2.0(2026-04-20) only shipsruvector-attention-*andruvector-math-wasmarchives. The web flasher's fetch URL therefore 404s for every supported target (esp32,esp32s2,esp32s3,esp32c3,esp32c6).The fallback in
npm/bin/cli.js'sflashcommand is to build from source first — which fails per Observation 1.Observation 3 — README/docs vs. code
src/main.rsis presented as a "Full-Feature LLM v0.2" with "INT8/Binary quantized transformer inference", "MicroLoRA on-device adaptation", "Sparse attention patterns", and "Speculative decoding". Reading the example as written, those claims don't hold up:QuantizedWeights::new(L62–70) initializes every weight to((i * 17 + 31) % 256) - 64.EmbeddingTable::new(L82–90) is the same shape. The LoRAa_weightsPRNG (micro_lora.rs:38–44) is also seeded deterministically. There is aMicroLoRA::from_weightsconstructor (micro_lora.rs:53) and afrom_weights-style entry would be the natural place to load a checkpoint, but nothing in the example crate calls it and there is no checkpoint format / loader / weight file in tree. So the "model" running on the device is a fixed function of source code, not learned parameters.MicroAttention::forward(L123–139) is not attention. No Q·Kᵀ, no softmax, no V multiply. The body isoutput[i] = (input[i] * weight[i % len]) >> 7gated by a sparse mask — i.e. a single elementwise multiply, not scaled-dot-product attention over a sequence.FeedForward::forward(L161–176) is not a 2-layer MLP. It does one elementwise multiply againstw1, ReLU, and writes out — no expansion to4*EMBED_DIM, no second projection throughw2.w2is allocated and never read.TinyModel::forward(L269–299) takes a single token and returns a single token deterministically. No KV cache, no sequence context beyond the sparse-maskseq_posindex. As a result,gen <text>produces the same byte sequence on every call for a given input.If the intent is that this file is a structural skeleton / sizing demo rather than a working inference path, that's fine, but the README and the in-source doc comment ("Full-featured LLM inference engine for ESP32 with INT8/Binary quantized transformer inference") read as a real model. A one-line note in the example README ("this example demonstrates the on-device control surface and memory layout; weights are placeholders, not a trained model") would prevent people from going down the same evaluation path we did.
Reproduction
Related
May overlap with the recently filed series #399, #400, #401, #402 reporting that other published demo/CLI surfaces are missing assets or out of sync with the library. Filing separately because those are about
ruvector-cli, notexamples/ruvLLM/esp32-flash.Environment
ruvnet/ruvectorat20aca12(latestmainat time of filing)/dev/ttyACM0(USB ID303a:1001); not flashed because no firmware could be produced.What would unblock evaluation
host-testbuild that compiles end-to-end (or removal of the feature if it's no longer supported).npm/web-flasher/index.html, or an updated flasher that points at where firmware actually lives.examples/ruvLLM/esp32-flash/README.mdclarifying whether the in-treemain.rsis meant to demonstrate inference behaviour or is a structural placeholder pending a separate model-loader path.Happy to test fixes against the same hardware.