The security-first vector database. Client-side-encryptable, memory-frugal approximate-nearest-neighbour search that runs on a laptop — with a retro terminal cockpit.
Status:
v0.33.0released.v0.33.0— Unburdened: the streaming index build reaches the live path (ADR-0071, completing ADR-0070 Increment B). The IVF rebuild — the server's off-lock path and the embedded open path — no longer materializes the wholen·dimcorpus in a residentflatarray (~51 GiB at 100M×128):Store::capture_vector_sourcereopens the referenced segments' immutable.vecmmaps as owned, lock-free handles a concurrent checkpoint cannot disturb, and both rebuild entry points feedIvf::build_streaming, so the build reads each row from disk in two bounded passes and holds only the sample, codebooks, PQ codes, and postings resident — peak build memory for the vectors drops fromO(n·dim)toO(sample + nlist·dim + n·m_bytes). The resident primary index (~316 B/point) is the remaining O(n) build cost (the sequenced Increment C), and the reference-hardware RSS measurement is deferred to the dedicated box — no number is claimed; the change lands on correctness tests (a rebuild spanning a reopened sealed segment and the active buffer). No on-disk or wire format change; the single node is unchanged at zero overhead.v0.32.0— Streaming: foundational work toward a single-box 100M build, plus a cluster-search latency win. The streaming, memory-bounded index-build primitive (ADR-0070) —Ivf::build_streamingbuilds an IVF+PQ index by streaming vectors from a re-iterable source in two bounded passes (a deterministic reservoir-sample train pass, then a stream-encode pass) instead of materializing the wholen·dimcorpus in RAM, byte-identical to the batchIvf::buildwithin the training sample (parity-tested over L2 and Cosine); it is the core primitive that lifts the batch build'sO(n·dim)RAM ceiling toward 100M, with the embedded scan→build wiring the next increment — this release ships the primitive and the accepted ADR, not yet the end-to-end memory win. And concurrent cluster scatter-gather: a cluster search fans out to its shards withtry_join_allso its latency tracks the slowest shard instead of the sum of all shards, with each shard's local top-k merged into the identical exact global result. No on-disk or wire format change; the single node is unchanged at zero overhead.v0.31.0— Reinforced: an adversarial-audit remediation, hardening, and scale pass. A full audit found and fixed 18 confirmed bugs + one plausible (each regression-tested) — headlined by a critical Raft state-machine durability fix (a voter restart re-applied its whole committed log and a post-compaction cold restart couldn't recover; the applied-state and snapshot are now persisted and reloaded, crash-window idempotent),next_collection_idWAL recovery (closing an id-reuse / silent-data-loss window after a crash before checkpoint), and an IVF-PQ metric-orientation fix (it reported the raw ordering value, inverting cosine ranking under MVCC) — plus cluster-router mutation auditing and honest501s for un-routed ops, durable raft-log-dir fsync and atomic coordinator writes, exact large-integer payload filters, and security/robustness hardening (authorize-before-write-guard, Admin-gatedGET /cluster/map, decrypted-DEK zeroize, percent-encoded Python-SDK paths). And IVF scale to 10M on a laptop: codebooks train on a deterministic 262k sample (~15× faster build),nlist ≈ √nreplaces the fixed 64 (1M query p50 66 ms → 13.8 ms, ~10× at scale), the redundant L2/Dot build copy is elided viaCow(letting 10M fit in 15 GiB), and a large bulk load auto-checkpoints (QUIVER_CHECKPOINT_BYTES, default 256 MiB) to stay memory-frugal — 10M vectors built and served at query p50 75.8 ms, 529 B/vector on disk (IVF-Flat exact recall@10 = 0.998), with the honest 100M ceiling (a streaming index build) named in the roadmap and not claimed to have been run. No on-disk or wire format change; the single node is unchanged at zero overhead.v0.30.2— an internal refactor (no behavior/API change):quiver-embed'slib.rssplit into a module tree that isolates the lock-free MVCC code (snapshot/mvcc), the on-disk index envelopes, and the multi-vector token machinery — public API and tests unchanged.v0.30.1— a security & dependency patch (no engine change): supply-chain hardening (aquasecurity/trivy-action→ v0.36.0, GHSA-69fq-xp46-6x23), a verifiedroaring0.10 → 0.11 bump (the on-disk.deltombstone-bitmap format round-trips — thekill -9crash gate stays green), and dependabot scoped todevelopand configured to skip trait-linked / hardware-validated majors.v0.30.0— Fortified: an audit-remediation and robustness pass. Streaming, memory-bounded segment compaction (ADR-0068) — aBlockWriterstreams the.vec/.paycolumns page-by-page (byte-identical towrite_blocks) socompact_collectionholds one row at a time rather than the whole live set, andauto_compactis bounded to one collection per checkpoint so compaction stays off the checkpoint's critical path (old segments stay valid until the atomic manifest swap — crash contract preserved and tested). Lock-free MVCC read fixes — the snapshot search now widens the basek/efso overlay tombstones can't thin the result below a true top-k, and a batch upsert coalesces into one atomic overlay republish. Collection-name validation, a length-independent constant-time API-key comparison and a cached HKDF PRK on the at-rest codec, and an automated OWASP ZAP DAST gate (ADR-0069) that boots a live, production-configured server and blocks the release on any FAIL-level finding. A single canonical cross-language cipher known-answer test is now asserted from Rust, Python, and TypeScript and gated in CI, so cipher drift fails the build. No on-disk or wire format change; the single node is unchanged at zero overhead.v0.29.1— a documentation & tooling patch (no engine change): a complete set of per-subsystem architecture diagrams (docs/diagrams.md— 18 Mermaid sources rendered to committed SVGs viajust diagrams, covering storage, indexing, retrieval, distributed, security, and operability) and a release-timevisual-recapworkflow that montages the cockpit screenshots and appends a gallery to each release's notes. The single node and every published crate are byte-for-byte unchanged.v0.29.0— Hardened: a finalization and production-readiness pass. A documented security audit (audit-0.29.0.md) — a static OWASP-style review plus a dynamic OWASP ZAP scan of a live server (0 failures across 119 rules) and thecargo-fuzztargets re-run clean — with every finding fixed and regression-tested: an authenticated cluster coordinator (its membership API now enforces default-deny RBAC, closing an unauthenticated-reshape gap in cluster mode), baseline security response headers, and a crash-recovery fix (a torn WAL header on akill -9during rotation now recovers cleanly rather than failingStore::open). Plus the complete API/CLI/configuration reference — a committed OpenAPI 3.1 spec pinned to the router by a coverage test, a CLI reference, and an exhaustive configuration reference for everyQUIVER_*variable — a richerquiver demo, and field-guide §6.5 on the security-robustness evidence. No engine behavior change; the single node is unchanged at zero overhead.v0.28.0— Autopilot: the cluster scales itself and borrows a GPU's muscle where one exists. Coordinator autoscaling — automatic scale-out (ADR-0065 increment 5, opt-in): when enabled the coordinator samples each shard's point count and, when the busiest crosses a configuredhigh_water_points, grows the cluster into a standby on its own — the same safe online migration as a manual grow, no operator and no lost data, bounded by a cooldown, a never-interrupt-a-migration rule, and amax_shardscap (scale-in stays a manual, drained remove). GPU-accelerated distance (ADR-0052, behind the off-by-defaultcudabuild feature): the batch distance kernel runs on a CUDA GPU when one is present (gpu::batch_l2_sq) and falls back to the CPU SIMD kernel with identical results — cudarc loads the driver dynamically and compiles the kernel with NVRTC, so a normal build links zero CUDA and the feature even compiles without a toolchain (validated on real hardware; CI builds the feature, only the CPU path runs). Both opt-in and off by default; the single node is byte-for-byte unchanged at zero overhead. The "Quiver, Explained" field guide gains §9.12 (autoscaling) + §9.13 (GPU) and two figures (59 pages).v0.27.0— Resilient: per-shard write high availability (ADR-0067, increment 4, opt-in via theraftbuild feature +QUIVER_RAFT_NODE_ID/QUIVER_RAFT_MEMBERS). Each shard runs one Raft group on the auditedopenraftcore, with its replicas as voters: a write is acknowledged only after a quorum commits it, so a leader can fail and a replica is promoted automatically with no lost acknowledged write and no split-brain — a write that reaches a non-leader gets a "not the leader" redirect and the router routes to the current leader. The Raft log is durable and crash-safe (a restarted voter recovers its log and vote and rejoins), log-compacting (a far-behind or newly added voter catches up by installing a snapshot), and elastic (voters added or removed online viaPOST/DELETE /cluster/raft/voters). Proven by a correctness suite — no-lost-acknowledged-write under continuous load through the router while the leader is killed, a minority that cannot reach a quorum refuses writes, partition/rejoin, and a durable-log replay property test. Off by default: a normal build links zeroopenraftand the single node is byte-for-byte unchanged at zero overhead. The "Quiver, Explained" field guide gains §9.11 (surviving a node failure) and a write-HA figure (57 pages).v0.26.0— Elastic: the cluster grows and replicates. Per-shard read replicas (ADR-0065 increment 2, opt-in viaQUIVER_CLUSTER_REPLICAS) — each shard can declare follower replicas (reusing leader-follower replication, ADR-0030); writes/gets/deletes still go to the single primary, while searches round-robin across{primary} ∪ replicasand fall back to a live copy if one is down, so reads scale out within the cluster. Dynamic, elastic membership (ADR-0066 increment 3) — a thin, off-the-data-path coordinator owns a monotonically versioned shard map; routers refresh it into theirArcSwapso a membership change propagates with no restart. Shard ids become an immutable HRW key (decoupled from position), so removing a shard moves only its~1/Nslice. And one call —POST /cluster/shards/grow— adds a shard to a live cluster and runs the whole online migration in the background: the donor serves the slice and every new write is dual-written to both while the coordinator copies the slice across (get-if-absent, so a concurrent write is never clobbered), then ownership flips at the next map version and the donor drops its copy — no downtime, no lost writes, only the moved slice changes hands (proven by tests that grow under concurrent load and assert the slice is queryable throughout and every acknowledged write survives). Single-node and a statically configured cluster are unchanged at zero overhead. The "Quiver, Explained" field guide gains §9.9 (read replicas) + §9.10 (dynamic scaling) and two figures (now 55 pages).v0.25.0— Scale Out: cluster mode — sharding + scatter-gather (ADR-0065, increment 1, opt-in viaQUIVER_CLUSTER_SHARDS). A non-empty list of shard URLs makes the same binary a stateless router: it shards writes by point id with rendezvous (HRW) hashing — so adding or removing a shard remaps only ~1/N of ids, the basis for the dynamic, elastic scaling the cluster is designed for — and scatter-gathers searches across all shards, merging the exact global top-k (each shard returns its local top-k, so the merge is provably correct). Each shard is an ordinary single-writer Quiver engine with its ownkill -9crash gate; the cluster is composition, not a rewrite, and strictly opt-in — with no shards configured the server is the same single node at zero overhead. A newquiver-clustercrate holds the pure primitives; an end-to-end test boots two shards + a router + a single-node baseline and proves the router returns the same top-k distances, that writes shard across nodes, and that routed delete works. Later increments: read replicas, online elastic membership + rebalancing + a coordinator, per-shard Raft write-HA, autoscaling. The "Quiver, Explained" field guide gains §9.10 + a scatter-gather figure (now 53 pages).v0.24.0— Reads Without Waiting: lock-free MVCC reads (ADR-0064) — built end to end in three increments behind an off-by-defaultQUIVER_MVCC_READSflag. The single writer publishes an immutable per-collectionarc-swapsnapshot (the base index plus a small copy-on-write overlay of recent writes + tombstones); a reader loads it with no lock, searches the base, merges the overlay, and drops tombstones — so reads proceed during writes instead of blocking on the writer's exclusive lock. Filtered and hybrid reads serve from the snapshot too, and at the server the snapshot cell is cached outside the database lock so a pure-vector query is fully lock-free. A measured before/after on the same box (read-during-write.md) shows the multi-writer read collapse disappear — retained read-QPS under two small-upsert writers goes from 0.00× (RwLock) to 0.79× (MVCC) — with the ratio the honest signal and absolute QPS reference-hardware-pending. Durability and thekill -9crash gate are untouched (MVCC changes visibility, not durability); it ships opt-in, the provenRwLockpath staying the default until validated on dedicated hardware, and the "Quiver, Explained" field guide gains a plain-English §5.5 (now 51 pages).v0.23.0— Durable Frugality: the durable on-disk DiskVamana index (ADR-0063) — adisk_vamanacollection now loads its frugalmmapbase on open (mmap the immutable base graph, reconstruct the small in-memory FreshDiskANN delta from the store, and replay the post-checkpoint WAL tail) instead of anO(N)full-RAM rebuild on every restart; the base is published by atomic rename with a tiny checkpoint blob, and any problem falls back to the authoritative rebuild, so the artifact is never load-bearing for correctness and thekill -9crash gate is preserved by construction — this is what finally lets a restarted server serve from the PQ-codes-resident path (the memory-frugality wedge) where earlier releases rebuilt from every full-precision vector on open, the cause of the benchmark's unrepresentative post-build RSS; cold-reopen-honest frugality evidence — the disk-path wedge benchmark now closes and cold-reopens the server before sampling RSS, with a one-command Windows runner (scripts/bench-disk-frugality.ps1), and a read-during-write contention sweep (read-during-write.md) measuring the read-QPS retained under one concurrent writer (0.73× on the shared dev box — the measure-first gate for MVCC; absolute RAM/QPS stay reference-hardware-pending, never fabricated); and the lock-free MVCC reads implementation design (ADR-0064) — a per-collection arc-swap snapshot plus a small copy-on-write overlay published on commit, staged in three increments behind a default-offQUIVER_MVCC_READSflag (design only this release) — alongside a security pass (a ReDoS fix in the TypeScript SDK and documented-by-design DCPE crypto findings).v0.22.0— Complete Quiver: the off-lock index rebuild (ADR-0062) — a deferred index rebuild no longer stalls concurrent readers; the server serves the prior snapshot while the new index builds with no lock held, then swaps it in under a brief write lock, with a per-collection write-generation guard so no write is lost (a measured ~77 s reader stall at 100k vectors collapses to the sub-millisecond tail; nounsafe, noloom); the interactive TUI cockpit (ADR-0060) — a/query runner with a payload inspector and recent-searches, a?keybinding overlay, and aCtrl-tBronze↔Slate theme toggle; an opt-in OpenTelemetry traces exporter (ADR-0059) behind theotlpbuild feature andQUIVER_OTLP_ENDPOINT(off by default, no new deps in a normal build); MCP text toolsupsert_text/search_text(ADR-0058) via a sharedquiver-providerscrate, bringing the agent surface to provider parity with REST, gRPC, and the SDKs; thequiverdb-*publish namespace (ADR-0056) (each crate isquiverdb-<name>while its library/extern name and thequiverbinary are unchanged); and four new benchmark dimensions (ADR-0061) on SIFT1M — recall@{1,10,100}, a saturated-concurrency sweep (1-thread vs 8-thread QPS, up to 1.76× at ef=256), a quantization tradeoff (the recall@100 tail collapse of disk-Vamana + PQ), and a filtered-selectivity sweep (the planner's recall valley) — every figure traced to a committed CSV incomparison-v0.22.0, with the expanded "Quiver, Explained" field guide (committed figures underdocs/assets/explained-figures/).v0.21.0— Close the Gaps: concurrent reads (ADR-0057) — the server now serves searches behind a reader–writer lock instead of a single mutex, so reads run in parallel; the engine gains&selfsearch_snapshotreads andensure_indexed, the single-writer model and crash gate unchanged, with the fully lock-free arc-swap snapshot path staged as the successor; a packaging & distribution pipeline (ADR-0056) — aCHANGELOG.md, crate publish metadata, secret-gated crates.io / PyPI / npm publish jobs, and a Helm chart + Kubernetes manifests underinfra/for one-command self-hosting; and SDK parity — the TypeScript client reaches full method parity with the Python async client (upsertIterover a sync or async iterable, an async-generatorscroll,deleteByFilter), and the Go client gains the same bulk/maintenance helpers (UpsertBatch/Scroll/DeleteByFilter, all context-aware).v0.20.1— a documentation & evidence patch (no engine change): the SIFT1M + GIST1M multi-DB benchmark re-run on the v0.20.0 engine (comparison-v0.20.0, ADR-0055) — Quiver is second only to FAISS on SIFT1M (1222 QPS / p95 1.0 ms at recall ≥ 0.95) and matches FAISS on GIST recall (0.923 vs 0.919), with the build column now measured through the bulk-ingest path as honest time-until-queryable — folded into the README, methodology, and the "Quiver, Explained" field guide, plus PDF layout polish.v0.20.0— RAG batteries + operability: server-side embedding & reranking hooks (ADR-0047) — opt-in, provider-agnostic (OpenAI/Cohere/Ollama/HTTP), per collection, withupsert_text/search_texton REST, gRPC, and the SDKs; BM25 full-text over the sparse path (ADR-0046) with a dependency-free tokenizer, a Snowball stemmer (ADR-0048), andquery_texton every surface; online snapshot & restore (ADR-0050) — a consistent whole-database backup over the engine, REST (POST /v1/snapshot), the MCP server, and every SDK; a client-streaming gRPCUpsertStream(the ADR-0045 fast-ingest fast-follow); opt-in per-key rate limiting (ADR-0049) — a token bucket withRateLimit-*headers and 429 across REST and gRPC; real Prometheus/metrics+ request tracing + a Grafana dashboard (ADR-0054); a standard-library Go SDK; richer MCP management tools (database_stats,delete_collection,snapshot); and design ADRs for the big bets — distributed/sharded mode (ADR-0051), GPU acceleration (ADR-0052), and lock-free MVCC reads (ADR-0053).v0.19.0— hybrid everywhere + fast ingest (ADR-0045): a derived sparse inverted index replaces the per-query store scan on the sparse half of hybrid search (built from the store, maintained incrementally on upsert/delete, with a store-scan fallback — no on-disk change, crash gate untouched); hybrid search now reaches every surface — a gRPCHybridSearchRPC, an MCPhybrid_searchtool, and a TypeScripthybridSearchmethod join the REST endpoint and the Python SDK; and a bulk-ingest endpoint (POST /v1/collections/{name}/points:bulk) commits a large batch with one WAL fsync and a single index-build pass (the path that addresses the benchmark's build-time column), bounded byQUIVER_MAX_BULK_BATCH_SIZE.v0.18.1is a release-packaging patch: the release workflow now builds and publishes the Windows binary automatically on every tagged release (it was previously uploaded by hand, sov0.18.0shipped with no assets andquiver updatecould not fetchquiver-windows-x86_64.exe— see ADR-0044).v0.18.0is the post-launch correctness, benchmark, and RAG pass (opened by a full state-of-Quiver assessment): query cost limits enforced at the op layer (closing an authenticated-DoS and the one docs/code mismatch); a real SIFT1M / GIST1M multi-DB benchmark — Quiver is second only to FAISS on SIFT1M (QPS + tail latency at recall ≥ 0.95) and matches FAISS on GIST recall (tables below); hybrid dense + sparse search with RRF fusion (engine + REST + Python SDK); an async Python SDK, a HaystackDocumentStore(joining LangChain + LlamaIndex), arerankhelper, an MCPcollection_infotool, and complete RAG / agentic / tuning usage guides with a runnable example; plus a cockpit that shows the release version beside the wordmark with richer vitals.v0.17.0delivered two Phase 5 hardening items: a 35× build-time speedup (batch WAL sync — 65.4s → 1.86s for 10k SIFTSMALL vectors, from dead last to middle-of-field) and a one-command install (scripts/install.sh/install.ps1, SHA-256 verified pre-built binaries,quiver updateself-update subcommand). Full benchmark comparison against 7 competitors (FAISS, Qdrant, Milvus Lite, Chroma, pgvector, LanceDB, Weaviate) indocs/benchmarks/results/comparison-v0.17.0. Phase 1 (v0.1.0) shipped the single-node core — an encrypted, crash-safe storage engine, HNSW, SIMD kernels, REST/gRPC, the TUI, and the Python SDK. Phase 2 (v0.2.0) delivered memory frugality: the disk-resident DiskANN/Vamana and IVF indexes with product/scalar/binary quantization, a row-addressed storage engine (stride-addressed vector columns, paged payload heaps, roaring tombstones, compaction, secondary indexes), hybrid filtered search, the TypeScript SDK, the MCP server, and LangChain/LlamaIndex adapters. Phase 3 (v0.3.0) added security depth and cockpit polish: client-side payload encryption, RBAC with scoped API keys and optional mTLS, an append-only audit log, per-collection-DEK encryption with crypto-shredding, master-key-file secret handling, the 2-D constellation view, andcargo-fuzztargets. Phase 4 ships the advanced backlog incrementally:v0.4.0added incremental in-place index updates (SpFresh/LIRE for IVF) and migration importers (quiver admin importfor Qdrant/Chroma/pgvector);v0.5.0added HNSW incremental delete, a neighbor-bounded IVF reassignment, a unified secure database-open path across the server/MCP/CLI, and the design for a durable on-disk incremental index.v0.6.0made that durable index real — the IVF index now loads on open (snapshot + WAL-tail replay) instead of anO(N)rebuild, crash-gated — and added a live Qdrant migration connector (quiver admin import --qdrant-url).v0.7.0adds multi-vector / late-interaction (ColBERT) retrieval: a collection can store each document as a set of token vectors and rank documents by MaxSim — reusing the row store (so the crash gate is untouched) and the IVF+PQ frugality path — reachable from the embeddable database, REST/gRPC, the MCP server, and the SDKs.v0.8.0extends migration to live Chroma and Postgres connectors (quiver admin import --chroma-url/--postgres-url), so all three supported sources can import directly from a running instance — no export step.v0.9.0adds asynchronous leader-follower read replicas (point a follower at a leader withQUIVER_LEADER_URL) — scaling reads and giving warm standbys without consensus or failover.v0.10.0adds an experimental, opt-in DCPE vector-encryption mode (vector_encryption="dcpe"): a client encrypts embeddings with a published distance-comparison-preserving scheme so an untrusted server can rank ciphertexts by approximate L2 distance without ever holding the plaintext vectors or the key — honestly labelled, since it is L2-only, not semantically secure, and leaks the approximate distance ordering by design.v0.11.0adds a semantically secure client-side mode (vector_encryption="client_side"): the server stores only XChaCha20-Poly1305 ciphertext plus a zero placeholder, learns nothing about the vectors (genuinely IND-CPA), and does no ranking — so the client fetches the (optionally pre-filtered) set and ranks locally, with native Rust/Python/TypeScript ciphers validated by a bit-exact cross-language test.v0.12.0is a documentation & packaging fix — it corrects the install guidance (build from source; thequiver-cliname on crates.io is an unrelated project, and publishing the SDKs is a roadmap item) and the README rendering, with no functional change.v0.13.0brings incremental updates to the last index family that still rebuilt on every write: the Vamana and disk-resident DiskVamana graphs now use FreshDiskANN's StreamingMerge — a read-only base graph plus a small in-memory delta graph and anO(1)deletion set, searched together and consolidated by a derived rebuild past a churn threshold — so graph writes become size-independent while the index stays derived and thekill -9crash gate is untouched.v0.14.0takes two of the multi-vector / ColBERT follow-ups: document upsert/delete now maintain the token-pool index incrementally (no full rebuild), and an opt-incolbertindex adds ColBERTv2 residual compression + PLAID centroid pruning formultivectorcollections — both derived, so the crash gate stays untouched; native variable-stride document rows are deferred pending a reference-hardware locality measurement.v0.15.0ships the documentation polish before launch: an mdBook documentation site underapps/docs(concepts → quickstart → self-hosting → features → API/SDKs → security → architecture), a verified clean-clone quickstart, a native TypeScript DCPE cipher (closing the last SDK gap), and the two deferred DCPE Scale-And-Perturb hardening steps — a key-derived component shuffle and an ordering-preserving global normalisation — shipped as a breaking cipher v2 across Rust/Python/TypeScript with a cross-language known-answer test, honest about the one limit it cannot cross (per-axis whitening would break searchable ordering).v0.16.0makes the terminal cockpit the headline: a coherent Bronze Quiver retro brand (bronze chrome, leather borders, parchment text, a verdigris accent, on oak-black), a logo whose V is a 3-D arrowhead, and a vocabulary of minimalist retro decorations — framed panels, a database drum icon, a collections table with per-row load bars, a points-trend sparkline, a relationship tree, status badges, and a severity-tagged activity log — so an operator grasps the data, its structure, and what is happening at a glance; the view code is decoupled behind a render-to-buffer API, and a workspace-isolated generator renders each screen to a committed PNG (just tui-shots) for the README and docs from the real render, so the screenshots never go stale. Every performance/memory claim in this README is backed by a reproducible benchmark on documented reference hardware — until those numbers are recorded, that table stays empty rather than guess.
Native-Rust vector databases already exist; Quiver is not trying to out-scale Milvus or out-feature Qdrant. Its defensible edge is the combination of three things, executed well:
- Security-first, by default — encryption-at-rest is on out of the box, sealing every durable byte (segments, manifest, and the write-ahead log) with XChaCha20-Poly1305; payloads can be client-side-encrypted so the server never sees them; API-key scopes, RBAC, tenant isolation, audit, and crypto-shredding. Only audited cryptography (RustCrypto AEAD/KDF +
rustls) — never a home-grown primitive. The parsers that touch untrusted input (the search-filter wire format and the on-disk page/WAL decoders) are fuzzed, and the whole codebase is reviewed in a documented security audit — a static OWASP-style review plus a dynamic OWASP ZAP scan of a live server and the fuzzers re-run — with every finding fixed and regression-tested and the residual risks stated honestly. - Memory frugality — a disk-resident graph index (DiskANN/Vamana) plus quantization (product / scalar / binary) serve large datasets from a laptop's RAM budget. The headline metric is memory at a fixed recall.
- Developer experience — a single static binary; embeddable and server modes; a
ratatuicockpit with a 2-D constellation view of the vector space; idiomatic Python/TypeScript SDKs; an MCP server so agents can drive it.
We say plainly what we do not do: client-side payload encryption protects payloads, not vectors (the experimental, opt-in DCPE mode addresses vectors — a published scheme that, by design, leaks the approximate distance-comparison relation and is not semantically secure); billion-scale needs a server, while a laptop comfortably serves tens-to-hundreds of millions; there is no homomorphic search in core. See the honest threat model.
The name. A quiver holds arrows, and an arrow is a vector — apt for a database of them. And in mathematics a quiver is a directed graph, which is exactly what an HNSW or Vamana index is. The cockpit wears that identity in bronze — the colour of a quiver, with the logo's V drawn as a 3-D arrowhead.
A retro terminal cockpit ships in the box (quiver tui): a live dashboard in the Bronze Quiver theme — connection health and an ONLINE/OFFLINE badge, a collections table with per-collection load bars, points-trend and ingest-rate sparklines, the relationship view of the selected collection, and a severity-tagged activity log.
Press v/enter on a collection for the constellation view — a 2-D projection of its vector space with the query's nearest neighbour highlighted and an interactive cursor that re-queries around any point:
Press / for the query runner — type a query, run a server-side embed-and-search (ADR-0047), inspect any result's payload, and recall recent searches:
? opens a keybinding overlay and Ctrl-t toggles a cool Slate palette. The whole UI renders to a buffer behind a render-to-buffer API, so every screen is unit-tested with ratatui's TestBackend and the screenshots are generated from the real render of seeded demo data with just tui-shots (a dev-only, workspace-isolated tool) — they regenerate in one command and never go stale (ADR-0036, ADR-0060).
A complete, beginner-to-expert walkthrough of how Quiver works — embeddings and approximate-nearest-neighbour search from first principles, the engine block by block (SIMD kernels, HNSW / Vamana-DiskANN / IVF, quantization, hybrid search), durability and the kill -9 crash gate, the security model (envelope encryption, crypto-shredding, encrypted vectors), and the benchmark results with the verdict on Quiver's value. Written for people who know nothing about vector databases and engineers who want the depth — illustrated with diagrams and charts, typeset in the Bronze Quiver theme.
→ Read the PDF field guide · 60 pages, fully illustrated · also available as Markdown
A Cargo workspace: a from-scratch storage engine, index structures, SIMD distance kernels, and query planner, with a thin gRPC/REST shell and a TUI client. One binary runs the server, the cockpit, and the MCP server.
→ System context · Container view · Overview & crate map · ADRs · State of Quiver (assessment)
Full documentation lives in the docs site (an mdBook; build it with
just docs, or read the chapters underapps/docs/src) — concepts, self-hosting, every feature, the API/MCP/SDK references, the security docs, and an architecture deep dive.
Install (Linux / macOS) — one command, no Rust toolchain required:
curl -fsSL https://raw.githubusercontent.com/achref-soua/quiver/main/scripts/install.sh | shWindows (PowerShell 5.1+):
irm https://raw.githubusercontent.com/achref-soua/quiver/main/scripts/install.ps1 | iexBoth scripts detect your OS and architecture, download the pre-built binary for
your platform from the latest GitHub Release,
verify its SHA-256 checksum before touching your disk, and install to ~/.local/bin
(Linux/macOS) or %LOCALAPPDATA%\quiver\bin (Windows). On Linux the installer also
creates a .desktop entry and app-launcher icon. On macOS it creates a Quiver.app
bundle with the custom icon so you can pin it to the Dock. The Windows binary has the
icon embedded natively. To pin a specific version, set QUIVER_VERSION=0.17.0 before running.
Once installed, keep Quiver up to date with:
quiver update # downloads, verifies, and atomically replaces the binary
quiver update --check # just check if a newer version existsZero-config first run:
quiver demoSeeds two collections — a text-searchable articles set and 1 000 synthetic vectors
for the constellation — starts the REST server on :7333, and opens the retro
cockpit, where every op (browse, constellation, text search) works offline against the
seeded data. No config files, no env vars, no external downloads.
Full server quick start:
quiver serve # gRPC + REST on :6333, encrypted by default
quiver tui # the retro cockpit
quiver mcp # MCP server (stdio) so AI agents can drive QuiverOr install from a package registry:
cargo install quiverdb-cli # the `quiver` binary, from crates.io
pip install quiver-client # the Python SDK, from PyPI
npm install quiver-client # the TypeScript SDK, from npmThe crates publish under the quiverdb-* namespace (ADR-0056) — cargo install quiverdb-cli installs the same quiver binary the script above downloads. (The pre-built binary is the fastest path; cargo install compiles from source.)
Build from source (requires rustup stable + just + uv):
git clone https://github.com/achref-soua/quiver
cd quiver
just demo # build, start an encrypted server, seed a demo collection
# then, in another terminal:
quiver tui --api-key quiver-demo-key # the retro cockpitjust demo brings up a server with encryption-at-rest on, seeds a small
collection through the Python SDK, and prints how to open the cockpit. In the
cockpit, press v (or enter) on a collection to open the constellation
view — a 2-D random-projection scatter of its vector space with the query's
nearest neighbour highlighted; move the cursor and press enter to re-query
around any point. (The recorded cockpit cast lands in docs/assets/; produce
it on a real terminal with scripts/record-cockpit-cast.sh.) To build and
exercise the workspace directly:
just build # compile the workspace
just verify # the full local quality gate (lint · test · doc · deny · audit)
cargo run -p quiverdb-cli -- --helpHeads-up: Quiver's CLI publishes as
quiverdb-cli(cargo install quiverdb-cli) — thequiver-cliname on crates.io is an unrelated third-party project, which is why thequiverdb-*namespace is used (ADR-0056).
The MCP server exposes create_collection, upsert, search,
get, delete, and the multi-vector upsert_document / search_multi_vector /
delete_document tools over JSON-RPC stdio, operating an encrypted in-process
database.
All developer tasks run through just:
| Command | What it does |
|---|---|
just build |
build the workspace (all targets) |
just test |
run the test suite |
just lint |
cargo fmt --check + clippy -D warnings |
just verify |
the gate — lint · test · doc · deny · audit |
just test-py |
Python SDK test suite (via uv) |
just run / just tui |
run the server / the cockpit |
just demo |
encrypted server + seeded demo collection |
just bench *ARGS |
run the benchmark harness (e.g. just bench --synthetic) |
just coverage |
HTML coverage report |
just docker |
build the container image |
The ci (fmt · clippy · test · doc) and security (deny · audit · gitleaks) workflows under .github/workflows run automatically on every pull request and on pushes to main/develop; the heavier build workflow stays manual (workflow_dispatch). Local just verify runs the same steps as the fast pre-commit gate, so the two never drift (ADR-0015).
The Python SDK is on PyPI as quiver-client (pip install quiver-client; or pip install ./sdks/python from a checkout):
from quiver import Client, Point
with Client("http://127.0.0.1:6333", api_key="…") as q:
q.create_collection("items", dim=3, metric="cosine")
q.upsert("items", [Point("a", [0.1, 0.2, 0.3], {"tag": "x"})])
hits = q.search("items", [0.1, 0.2, 0.3], k=5)The TypeScript SDK is on npm as quiver-client (npm install quiver-client; or pnpm add ./sdks/typescript from a checkout), dependency-free over the global fetch, and can pick the memory-frugal disk index:
import { Client } from "quiver-client";
const q = new Client("http://127.0.0.1:6333", { apiKey: "…" });
await q.createCollection("items", 3, { metric: "cosine", index: "disk_vamana", pqSubspaces: 1 });
await q.upsert("items", [{ id: "a", vector: [0.1, 0.2, 0.3], payload: { tag: "x" } }]);
const hits = await q.search("items", [0.1, 0.2, 0.3], { k: 5 });A LangChain VectorStore adapter ships in quiver.langchain (pip install "quiver-client[langchain]"), and a LlamaIndex VectorStore in quiver.llamaindex (pip install "quiver-client[llamaindex]") — so any Quiver index, including the memory-frugal disk path, backs a LangChain or LlamaIndex retriever. The LlamaIndex adapter maps MetadataFilters onto Quiver's hybrid pre-filter. A synchronous Client and an async AsyncClient share one contract, with batched-upsert/scan/delete-by-filter helpers for ingestion and erasure.
Using Quiver in RAG / agents. End-to-end guides — RAG (chunk → embed → filtered search → rerank → answer), agentic patterns over MCP, and tuning for RAG (index/quantizer/recall-RAM) — plus a runnable examples/rag/quickstart.py that needs no API key.
Client-side payload encryption (ADR-0012): seal payload fields with a key the server never sees, so it stores and returns only ciphertext, while cleartext sibling fields stay server-filterable. The PayloadCipher helper ships in both SDKs (quiver.encryption / quiver-client/encryption) and a Rust reference (quiver_crypto::payload), sharing one XChaCha20-Poly1305 envelope byte-for-byte. The trust boundary is honest — it protects payloads, not vectors — and proven by a test that runs a server with at-rest encryption off and shows the sealed field never appears in plaintext over the API or on disk.
An ann-benchmarks-style harness lives in bench/. On SIFT1M (1M × 128, L2), in-memory HNSW (M=16, efC=200), Quiver's own recall ↔ throughput ↔ latency curve:
ef_search |
16 | 32 | 64 | 128 | 256 |
|---|---|---|---|---|---|
| recall@10 | 0.793 | 0.895 | 0.958 | 0.986 | 0.995 |
| QPS (1 thread) | 1539 | 1424 | 1222 | 955 | 701 |
| p95 latency (ms) | 0.8 | 0.8 | 1.0 | 1.3 | 1.7 |
Head-to-head on SIFT1M, every system on the same box (i7-12700H · 20 threads · 15.5 GB), peak single-thread QPS at recall@10 ≥ 0.95 (full method, sweeps, and the wins/losses matrix: comparison-v0.20.0):
| System | recall@10 | QPS (1T) | p95 (ms) | RSS (MB) | build |
|---|---|---|---|---|---|
| FAISS 1.14 | 0.968 | 3842 | 0.4 | 1234 ¹ | 82 s |
| Quiver v0.20 | 0.958 | 1222 | 1.0 | 2069 | 581 s ² |
| Chroma 1.5 | 0.977 | 1009 | 1.1 | 3752 ¹ | 153 s |
| Weaviate 1.27 | 0.983 | 663 | 1.7 | 2218 | 38 min |
| Milvus 2.5 (server) | 0.986 | 649 | 1.9 | 2075 | 26 s |
| Qdrant 1.13 | 0.974 | 358 | 4.5 | 258 ³ | 98 s |
| pgvector 0.7 | 0.980 | 118 | 11.8 | 1291 | 132 s |
| LanceDB 0.33 | 0.557 ⁴ | 219 | 5.3 | 2475 ¹ | 15 s |
Quiver is second only to FAISS on both throughput and tail latency at this recall bar, with recall on par with the field — and on the v0.20.0 engine its single-thread QPS rose ~40% over v0.18.0 (870 → 1222 at recall ≥ 0.95) while p95 dropped from 1.5 ms to 1.0 ms.
The honesty that makes the table trustworthy: this is an in-memory HNSW comparison for every system, so RSS here is full-vectors-in-RAM — Quiver's memory-frugality wedge is its disk-resident path (only PQ codes resident; ~32× less RAM, see disk-path.md), not this table. ¹ FAISS/Chroma/LanceDB run in-process so their RSS includes the Python harness + the resident 512 MB dataset (inflated; only Quiver/Milvus/Qdrant/Weaviate report the isolated DB). ² Quiver's "build" is now the bulk-ingest path (POST …/points:bulk, ADR-0045) — one WAL fsync per request plus a single deferred index pass, with the first query forcing the rebuild so the number is the honest time-until-queryable (581 s, down from v0.18.0's 854 s REST-upload path). In-process FAISS still builds fastest as it skips the network entirely. ³ Qdrant mmaps vectors to disk by default. ⁴ LanceDB's IVF-PQ config doesn't reach 0.95 recall in this sweep (shown at its best). Numbers are dev-box, indicative — comparative standings on the identical box are real (per the methodology); absolute RSS, saturated multi-thread QPS, and the 10M disk path are reference-hardware-pending; we never fabricate. Milvus is benchmarked as the server (Docker), not the in-process Lite build.
GIST1M (1M × 960, L2) is the harder, higher-dimensional test. Same box, each system at its most efficient config reaching recall@10 ≥ 0.95, or its best point at ef_search ≤ 256 (960-d needs a wide beam, so most plateau below 0.95 in this sweep):
| System | recall@10 | QPS (1T) | p95 (ms) | RSS (MB) | ef/nprobe |
|---|---|---|---|---|---|
| Quiver v0.20 | 0.923 | 268 | 4.4 | 10117 | 256 |
| FAISS 1.14 | 0.919 | 471 | 2.7 | 7526 ¹ | 256 |
| Chroma 1.5 | 0.790 | 577 | 2.1 | 8156 ¹ | 16 ⁵ |
| Weaviate 1.27 | 0.828 | 418 | 2.8 | 8880 | 64 ⁵ |
| Qdrant 1.13 | 0.955 | 185 | 6.3 | 391 ³ | 128 |
| Milvus 2.5 (server) | 0.961 | 53 | 29.4 | 6821 | 64 |
| pgvector 0.7 | 0.980 | 8 | 194 | 4393 | 64 |
On 960-d, Quiver matches FAISS on recall (0.923 vs 0.919) and on the v0.20.0 engine is markedly faster than v0.18.0 at the same recall (182 → 268 QPS, p95 7.7 → 4.4 ms). The three systems that clear 0.95 here — Qdrant (185 QPS), Milvus (53), pgvector (8) — pay heavily for it in throughput and tail latency. ⁵ Chroma and Weaviate plateau well below 0.95 — their ef_search does not widen recall in this config. LanceDB did not complete GIST1M: building a 960-d/1M IVF-PQ index in-process exhausts memory (an honest DNF even with 27 GB of swap, not a fabricated row). Same RSS caveats as above (¹ in-process = inflated; ³ Qdrant disk-backed; Quiver's in-memory HNSW holds vectors in RAM — the disk path is the memory wedge). Full sweeps + the wins/losses matrix: comparison-v0.20.0.
New in v0.22.0 — four measurement dimensions (ADR-0061) on SIFT1M, every number traced to a committed CSV in comparison-v0.22.0 (dev-box · indicative). The headline is saturated concurrency — the payoff of the v0.21.0 reader–writer lock and the v0.22.0 off-lock rebuild: QPS under 8 client threads (NT) vs one (1T), per ef_search:
| ef_search | 16 | 32 | 64 | 128 | 256 |
|---|---|---|---|---|---|
| recall@10 | 0.793 | 0.895 | 0.958 | 0.986 | 0.995 |
| QPS (1T) | 1131 | 1001 | 855 | 673 | 506 |
| QPS (8T) | 949 | 968 | 928 | 938 | 892 |
| speed-up | 0.84× | 0.97× | 1.08× | 1.39× | 1.76× |
Read honestly: a single-process Python client (GIL + one HTTP socket) is itself a ceiling, so light queries are client-bound (NT ≤ 1T); the server-side win shows on heavier queries, where parallel readers pull ahead — up to 1.76× at ef=256, not a fabricated “8×”. The run also reports recall at depth 1/10/100 (recall@100 needs a wider beam: 0.918 → 0.983 as ef grows), a quantization tradeoff (in-memory HNSW recall@100 0.944 vs disk-Vamana + PQ16 0.709 — PQ trades the deep tail; absolute serving-RAM stays reference-hardware-pending), and a filtered-selectivity sweep (the planner's pre-filter/post-filter recall valley: 1.0 at 1%, 0.62 at 5%, recovering to 0.99). A walkthrough of all four, with figures, is in the "Quiver, Explained" field guide (Part 7).
The per-collection recall ↔ latency ↔ memory knobs — quantizers (scalar/product/binary), the disk-resident DiskANN path, and IVF — are documented with a tradeoff table in docs/benchmarks/quantization-tradeoffs.md.
Every index supports incremental updates, so streaming workloads avoid an O(N) rebuild on each write. The IVF index applies inserts, in-place updates, and deletes to the live index with SpFresh-style LIRE rebalancing (cell split/merge) (ADR-0023); HNSW soft-deletes in O(1) with an amortized rebuild (ADR-0026); and the Vamana / disk-resident graph family uses FreshDiskANN's StreamingMerge — a read-only base graph plus a small in-memory delta graph and an O(1) deletion set, consolidated by a derived rebuild past a churn threshold (ADR-0033). All indexes stay derived and the disk artifact keeps its write-once contract, so the kill -9 crash gate is untouched.
The disk-resident path is the memory-frugality wedge. On SIFTSMALL (128-d), it serves recall@10 up to 1.000 while holding only PQ codes in RAM — a 32× smaller RAM-resident footprint than full-precision vectors (the graph and vectors live in the encrypted on-disk index). That reduction is exact arithmetic and scales (e.g. a 10M × 768-d collection: ~1 GB resident vs ~31 GB). As of v0.23.0 the disk index is also durable (ADR-0063): a restart now loads the mmap'd base instead of rebuilding it from every full-precision vector, so a running server actually serves from the frugal path after a restart — earlier releases paid an O(N) full-RAM rebuild on open, which is what made the benchmark's post-build RSS unrepresentative. The head-to-head RSS vs Qdrant/LanceDB at 10M scale stays reference-hardware-pending; a Windows one-command frugality runner (scripts/bench-disk-frugality.ps1) measures the wedge on hardware you control. Numbers and method: docs/benchmarks/results/disk-path.md.
Multi-vector / late interaction (ColBERT). Create a collection multivector and each document is stored as a set of token vectors and ranked by MaxSim — for each query token, its best-matching document token, summed. Quiver models a document as a group of ordinary rows over the same row-addressed store, so there is no on-disk format change and the kill -9 crash gate is untouched; the token pool is the set the ANN index serves (candidate generation), then candidates are re-ranked by exact MaxSim with an optional payload filter. A ColBERT corpus is exactly the large, low-dimensional pool the IVF+PQ / disk path was built to compress, so late interaction showcases the memory-frugality wedge. Reachable from the embeddable database, REST + gRPC, the MCP server, and the Python/TypeScript SDKs (ADR-0028). v0.14.0 adds two follow-ups (ADR-0034): document upsert/delete now maintain the token-pool index incrementally (no full rebuild, so a document write is size-independent), and an opt-in colbert index applies ColBERTv2 residual compression + PLAID centroid pruning — coarse centroids plus per-token quantized residual codes in RAM, with the exact token vectors on the encrypted store for the re-rank. Both stay derived (rebuilt on open), so the crash gate is untouched; native variable-stride document rows are deferred pending a reference-hardware locality measurement.
Move an existing collection out of Qdrant, Chroma, or pgvector with one command — from an export file, or live from a running instance (no export step):
# from an export file
quiver admin import --source qdrant --input qdrant.jsonl \
--collection my_collection --data-dir ./data --metric cosine
# or live, straight from a running source
quiver admin import --source chroma --chroma-url http://localhost:8000 \
--collection docs --data-dir ./data --metric cosine
quiver admin import --source pgvector \
--postgres-url postgresql://user:pass@localhost/db \
--table items --collection items --data-dir ./data --metric l2The importer preserves ids, vectors, and payloads, optionally declares --filterable path:type fields for hybrid search, and writes the same encrypted format the server reads — so the result is an ordinary Quiver store you can quiver serve immediately. Live connectors for all three sources share the offline path's normalization (ADR-0027, ADR-0029). Per-source recipes and the full option reference are in docs/migration.md (ADR-0024).
Run asynchronous read replicas (ADR-0030): point a follower at a leader with QUIVER_LEADER_URL and it continuously applies the leader's committed operations and serves reads, lagging by the replication delay. Followers refuse writes; the leader exposes an admin-scoped Replicate stream that ships a logical snapshot, then the live commit tail. This scales reads and gives warm standbys without consensus or failover — single-node stays the primary topology, and this is a clearly-labelled advanced feature.
QUIVER_LEADER_URL=http://leader-host:6334 QUIVER_LEADER_API_KEY=<admin key> quiver serveSee docs/replication.md for the topology, guarantees, and limits.
Search your embeddings on a server you don't fully trust, choosing per collection (vector_encryption) where you sit on the confidentiality/performance spectrum — because no scheme gives fast server-side ranking, zero leakage, and practical performance all at once.
DCPE (vector_encryption: "dcpe", experimental). The client encrypts vectors with distance-comparison-preserving encryption — the published Scale-And-Perturb scheme, built only from audited RustCrypto primitives — so the server can rank ciphertexts by approximate L2 distance without ever holding the plaintext vectors or the key (ADR-0031). It is not semantically secure: L2-only, and it leaks the approximate distance-comparison relation by design (that is how the server ranks), so it carries real, documented caveats and is broken by known-plaintext or strong-prior adversaries. The v2 cipher (ADR-0035) adds the paper's two hardening steps — a key-derived component shuffle (an exact L2 isometry) and an ordering-preserving global normalisation — and ships native ciphers in Rust, Python, and TypeScript, validated against each other by a cross-language known-answer test. Read docs/security/dcpe.md before using it.
Client-side opaque vectors (vector_encryption: "client_side", semantically secure). The server stores only XChaCha20-Poly1305 ciphertext (no new cryptography — the same audited AEAD as at-rest) plus a zero placeholder, does no distance math, and learns nothing about the vectors — no coordinates, no distances, no geometry (genuinely IND-CPA). The honest cost: the server doesn't rank, so the client fetches the (optionally pre-filtered) set and ranks locally — best for small/medium or server-pre-filtered collections. Ships as a native VectorCipher in Rust/Python/TypeScript with a bit-exact cross-language test, plus a search-style helper that hides the fetch-and-rank round-trip (ADR-0032). Read docs/security/client-side-vectors.md.
Both modes are opt-in and off by default, and complement encryption-at-rest rather than replacing it.
Every option is an environment variable with a secure default; see .env.example and ADR-0013. Encryption-at-rest is on by default: the server requires a 256-bit key in QUIVER_ENCRYPTION_KEY (generate one with openssl rand -hex 32) unless QUIVER_INSECURE=true, and seals segments, the manifest, and the WAL alike. That key is a master key that wraps a per-collection data-encryption key (envelope encryption, ADR-0010), so dropping a collection crypto-shreds it — its key is destroyed and its data becomes unrecoverable, even from a backup (details). TLS is required for any non-loopback bind.
Access control (ADR-0011): authentication is by API key and authorization is default-deny RBAC. A bare QUIVER_API_KEYS secret is an all-collections admin key; for least privilege, define scoped keys in quiver.toml with a role (read ⊆ write ⊆ admin) and a collections scope (exact names or a trailing-* prefix, e.g. acme.*, for per-namespace isolation). A key may only perform its role's actions within its scope — over-scope and cross-namespace access return 403, and listing hides collections outside the scope. For an extra factor, set QUIVER_TLS_CLIENT_CA to require mutual TLS: both transports then demand a client certificate chaining to that CA. Set QUIVER_AUDIT_LOG to record every mutating/administrative operation and every denial to an append-only audit log — the acting key, the action, the resource, and the outcome, never the secret.
- Documentation site —
apps/docs(mdBook;just docs) - Roadmap & Definitions of Done —
docs/roadmap.md - Changelog —
CHANGELOG.md - Security policy —
SECURITY.md· Threat model —docs/security/threat-model.md· Security audit (OWASP ZAP + static + fuzz) —docs/security/audit-0.29.0.md - Contributing —
CONTRIBUTING.md - License — AGPL-3.0-only




