Apache-2.0 · v0.6.5 · runs on your machine
WARM
Hybrid search, graph indexing, and vector-symbolic memory.
Search and memory that run entirely on your machine.
WARM is a local-first document search engine and a vector-symbolic associative memory in one store. Hybrid BM25 and exact-cosine retrieval, byte-offset hits, crash-safe persistence, and superposed memory you can bind, bundle and query. No service calls and no telemetry.
- Rust
- Python
- Node
What are you building?
Choose a path, run an example, then inspect the evidence it returns.
Memory for an editor
Connect an MCP host to a local store. Remember, recall and inspect memories across sessions.
Search inside an app
Choose Rust, Node or a Python HTTP client, with clear package and storage boundaries.
Evaluate your results
Check known answers, inspect source passages and compare retrieval on your own questions.
Already installing? Troubleshoot setup and retrieval.
Install, ingest, search
The code below is read from the quickstart examples that CI runs on every pull request.
cargo add warm-rust --features security
// 1. Ingest. A store is a directory (`None` would use the current directory); it persists
// there and reopens with the same arguments.
let store_dir = tempfile::tempdir()?;
let warm = WarmCore::new(
DIMENSIONS,
Some(store_dir.path().display().to_string()),
None,
)?;
let start = Instant::now();
let inputs: Vec<DocumentInput> = corpus.iter().map(to_input).collect();
warm.memorize_documents(inputs)?;
println!(
"ingested {} documents in {:.1?}",
corpus.len(),
start.elapsed()
);
// Hits carry the passage and its byte range in the source text.
let hit = &warm.search_documents("asylum from persecution", &SearchOptions::default())?[0];
println!(
"\n{} bytes {}..{} score {:.3}: {}",
hit.document_id,
hit.start_byte,
hit.end_byte,
hit.score,
hit.text.as_deref().unwrap_or("")
);
The engine itself. Every other runtime is a surface over it.
uv pip install warm-sdk
# 1. Ingest. The server keeps one store per tenant; you send the text and a vector per document.
docs = [
{"id": d["id"], "vector": toy_embed(d["text"]), "text": d["text"], "metadata": {"title": d["title"]}}
for d in corpus
]
client = WarmClient(url=URL, api_key=API_KEY, tenant_id=tenant)
started = time.perf_counter()
client.add_documents(docs)
print(f"ingested {len(docs)} documents in {(time.perf_counter() - started) * 1000:.1f} ms")
# Hits carry the stored text, metadata and the exact cosine score.
top = client.query(toy_embed("asylum from persecution"), top_k=1)["matches"][0]
print(f"\n{top['id']} score {top['score']:.3f}: {top['text']}")
An HTTP client for warm-server. The warm-python wheel provides native vector search and phase vectors.
npm install writerslogic-warm
// 1. Ingest. A store is a directory; it persists there and reopens with the same arguments.
const memory = new DocumentMemory(new WarmMemorySystem(4096, mkdtempSync(join(tmpdir(), 'warm-quickstart-'))))
const started = performance.now()
await memory.ingest(corpus.map(toInput))
console.log(`ingested ${corpus.length} documents in ${(performance.now() - started).toFixed(1)} ms`)
// Hits carry the passage and its byte range in the source text.
const [hit] = await memory.search('asylum from persecution')
console.log(`\n${hit.documentId} bytes ${hit.startByte}..${hit.endByte} score ${hit.score.toFixed(3)}: ${hit.text}`)
The npm package installs a native binary for your platform. Building from source requires Rust.
Measured, and traceable
Both results are read from committed files under benchmarks/results/ each time the site is built.
BEIR SciFact test split, 300 queries over 5,183 documents, MiniLM-L6-v2 embeddings (384 dimensions). The published BM25 figure (0.665, Thakur et al. 2021) is quoted from the BEIR paper, not re-run here.
Source: benchmarks/results/public_scifact.json · Apple M4 · benchmark page
- At recall@10 of 0.90: the fastest WARM configuration (WARM VGraph (8-bit codes, rerank)) ran at 4,409 QPS, slower than the fastest other system (SymphonyQG (qb=0), 5,913 QPS).
- Not reached at 0.90 by: SymphonyQG (qb=4).
- At recall@10 of 0.95: no WARM configuration reached it. Reached by: FAISS HNSW M=16, FAISS HNSW M=32, Lucene HNSW M=16, Lucene HNSW M=32, RaBitQ IVF 1+8, hnswlib M=16.
- † WARM VGraph (4-bit codes, rerank): opt-in encoding that ran at lower machine load than the other rows; the benchmark page treats it as unconfirmed.
Source: benchmarks/results/public_qgraph_nytimes-256-angular.json · Apple M4 · load gate met by 0 of 107 configurations (limit 3.0), so throughput is indicative · benchmark page
One engine, two layers
Document search is a conventional hybrid retriever. The vector-symbolic layer is the associative memory. Both sit on one crash-safe store. Module map →
Why holographic
A hologram stores the whole picture in every fragment. A hypervector memory does the same: many facts are superposed into one long vector, no single bit holds any one fact, and damage is spread thinly over all of them.
- Bind a key to a value with XOR. The result looks like neither, and binding again with the key gives the value back.
- Bundle many bound pairs by majority vote into one vector that stays a little similar to each of them.
- Resonate: unbind with a key and compare against known values. The right one stands out from the noise, even after you corrupt the memory.
The demo uses dense binary vectors so the algebra is easy to see. The engine uses sparse binary vectors, and its document search does not rank with hypervectors; the concepts page says exactly which parts do.
A memory in one vector
4,096 bits hold every key-value pair at once. Pick how many pairs, damage the memory, and ask for one value back.
Similarity of the unbound memory to each known value
What is being computed
Each key and each value is a random 4,096-bit vector. A pair is key XOR value. The memory is the bitwise majority of all pairs, then damage flips the chosen share of its bits. To ask, XOR the memory with a key and measure the fraction of matching bits against every value. Unrelated vectors match about half their bits, with a spread near 0.8 percentage points, so a match well above 0.5 is the stored value. More pairs shrink the signal; more damage shrinks it too. Past some point the answer is wrong, and the demo says so.
Retrieval quality on SciFact
| System | nDCG@10 | Recall@100 |
|---|---|---|
| WARM hybrid (BM25 + exact cosine) | 0.729 | 0.953 |
| WARM lexical (stemmed BM25) | 0.688 | 0.925 |
| WARM dense (exact cosine) | 0.645 | 0.925 |
| NumPy exact cosine, same embeddings | 0.645 | 0.925 |
| WARM sparse vector path | 0.470 | 0.779 |
Same embeddings for every dense row. The benchmark pages carry the full comparison, including where WARM loses. Source: benchmarks/results/public_scifact.json.
What is in the box
Hybrid search
Stemmed BM25 fused with exact cosine over embeddings you supply. Hits carry the passage and its byte range.
Vector-symbolic memory
Sparse binary hypervectors with bind, bundle and permute, a triple store with multi-hop queries, Hopfield cleanup and a resonator network.
Crash-safe storage
Atomic batches, a mmap segmented log with generations, and replay. A store is a directory.
Hardening you opt into
AES-256-GCM stores, signed audit logs, credential-gated agents and COSE/SCITT provenance behind Cargo features.
Local by construction
The engine makes no network calls and sends no telemetry. The optional HTTP server is yours to run.
Measured, including losses
Every number on this site traces to a committed results file, and the benchmark pages say where another system wins.
How to read this site¶
The document pipeline is conventional retrieval: stemmed BM25 fused with exact cosine over embeddings you supply. The vector-symbolic layer powers the meaning memory, composition and the experimental vector index. Where WARM loses to another system on a measured benchmark, the benchmark pages say so, and every number on this site traces to a committed file under benchmarks/results/.
New here? Start with the quickstart, then read what "holographic" means in this code. Looking something up? Use the search box, the glossary or the FAQ. The version selector in the header switches between latest (the newest tagged release that carries these docs), dev (the main branch) and each tagged release. How the site is built and checked is on its own page.
The standards and provenance page names the W3C, C2PA, CAWG, DIF, and Trust over IP features, their interoperability checks, and the limits on current claims.