⚡ NanoVector
The SQLite of Vector Search & Episodic Memory for AI Agents
Bare-metal C99 · AVX2+FMA · ARM NEON · FASM x64 · Zero Dependencies · ~120 KB
🤝 Community, Issues & Support
- 🐛 Found a bug, accuracy issue, or vector index edge case? Please Open an Issue — reports are tracked and resolved quickly!
- 💬 Questions, episodic memory architectures, or feature requests? Join our GitHub Discussions.
- ⭐ Find NanoVector useful? Give it a star on GitHub — it helps more AI agent engineers discover the engine!
- ☕ Support development (USDT TRC-20):
TDVbEdnpgNgoAhNcn1EwXxWHiR3RKLit5P(Verify on TronScan)
Quickstart • Compatibility • Google Colab • Why NanoVector? • Benchmarks • Architecture • Ecosystem
📦 Multi-Platform Installation
| Platform / Manager | Installation Command |
|---|---|
| PyPI (pip) | pip install nanovector |
| PyPI (uv) | uv add nanovector |
| Conda (Anaconda.org) | conda install -c m_n_nik nanovector |
| Ubuntu / Debian (APT PPA) | curl -sS https://eminsk.github.io/ppa/setup.sh | sudo bashsudo apt install python3-nanovector |
| Ubuntu / Debian (.deb) | sudo dpkg -i python3-nanovector_0.1.6-1_amd64.deb |
pip install nanovector
# or with uv
uv add nanovector
🧩 Universal Compatibility Matrix
| Runtime / Implementation | Supported Versions | Execution Mode | Status |
|---|---|---|---|
| CPython (Standard) | 3.8, 3.9, 3.10, 3.11, 3.12, 3.13, 3.14, 3.15, 3.16 (Alpha) | Native C AVX2 / NEON extension + Buffer Protocol | ✅ Fully Supported |
| CPython (Free-Threaded) | 3.13t, 3.14t, 3.15t, 3.16t (Alpha) | Multi-core No-GIL (Py_BEGIN_ALLOW_THREADS) |
✅ Fully Supported |
| PyPy (JIT Accelerated) | 3.8, 3.9, 3.10, 3.11, 3.12 | High-speed JIT tracing / C-API & ctypes | ✅ Fully Supported |
| Operating Systems | Windows (7, 8, 10, 11), Linux, macOS (Intel & Apple Silicon) | x86_64 (AVX2/FMA), ARM64 (NEON) | ✅ Fully Supported |
🚀 Why NanoVector?
Modern AI agents and local LLM pipelines are plagued by vector database bloat:
- ChromaDB, Pinecone clients, and FAISS pull hundreds of megabytes of dependencies (
torch,onnxruntime,pydantic,fastapi,duckdb). - Cold Start Penalty: Importing Chroma takes 1.5 to 2.5 seconds, crippling CLI tools, serverless workers (AWS Lambda), and autonomous agent loops.
- The Small-to-Medium Vector Trap: Over 95% of AI agents store between 50 and 50,000 vectors (conversation turns, tool execution history, episodic facts). At this scale, graph traversal (HNSW) incurs heavy pointer indirection, high memory overhead, and non-deterministic recall.
NanoVector solves this by delivering exact, sub-millisecond, brute-force SIMD search directly in CPU cache with zero external dependencies.
| Feature | NanoVector ⚡ | ChromaDB 🐢 | FAISS ⚖️ |
|---|---|---|---|
| Distribution Wheel Size | 38 KB (~120 KB unpacked) | ~120 MB+ | ~50 MB+ |
| External Dependencies | 0 (Zero) | 35+ packages | OpenMP, BLAS |
| Python Cold Import Overhead | < 1 ms (3,000x faster) | ~1,850 ms | ~120 ms |
| Search Latency (N=2,000, 384D) | 0.13 ms (7,478 QPS) | 8.2 ms | 0.22 ms |
| Batch Ingestion Throughput | 1,414,000 vectors/sec | ~25,000 vectors/sec | ~400,000 vectors/sec |
| Storage Format | Single file (.nvec) |
SQLite + DuckDB dirs | Custom binary |
| Zero-Copy NumPy | Yes (Buffer Protocol) | No (copies memory) | Partial |
| GIL Release during Search | Yes (Py_BEGIN_ALLOW_THREADS) |
Partial | Partial |
⚡ Installation
Install the zero-dependency pre-compiled binary wheel in under 1 second:
pip install nanovector
🏁 Quickstart
import nanovector
import numpy as np
# 1. Initialize an index (dim=384 for all-MiniLM-L6-v2, 768 for BERT, 1536 for OpenAI)
index = nanovector.Index(dim=384, metric="cosine")
# 2. Add single embeddings with metadata dict or string
vec = np.random.randn(384).astype(np.float32)
index.add("doc_1", vec, metadata={"author": "eminsk", "tag": "ai", "views": 1500})
# 3. Batch addition (Zero-Copy directly from 2D NumPy array)
batch_vecs = np.random.randn(5000, 384).astype(np.float32)
batch_ids = [f"turn_{i}" for i in range(5000)]
batch_metas = [{"turn_id": i, "role": "agent", "category": "tech" if i % 2 == 0 else "general"} for i in range(5000)]
index.add_batch(batch_ids, batch_vecs, metadatas=batch_metas)
# 4. Search top-k nearest neighbors with metadata filtering (~0.15 ms)
query = np.random.randn(384).astype(np.float32)
results = index.search(query, top_k=5, filter={"role": "agent", "category": "tech"})
for r in results:
print(f"[{r.id}] Score: {r.score:.4f} | Meta: {r.meta}")
# 5. Single-file instant persistence (.nvec)
index.save("agent_memory.nvec")
# 6. Instant reload from disk
loaded_index = nanovector.load("agent_memory.nvec")
print(f"Reloaded {len(loaded_index)} vectors in {loaded_index.dim}D")
AI Agent Episodic Memory Pattern
Give your LLM agents lightning-fast, persistent long-term memory:
import nanovector
import numpy as np
class AgentEpisodicMemory:
def __init__(self, filepath="agent_brain.nvec", dim=384):
self.filepath = filepath
try:
self.index = nanovector.load(filepath)
except Exception:
self.index = nanovector.Index(dim=dim, metric="cosine")
def remember(self, fact_id: str, embedding: np.ndarray, fact_text: str):
self.index.add(fact_id, embedding, metadata=fact_text)
self.index.save(self.filepath)
def recall(self, query_embedding: np.ndarray, top_k=3):
return self.index.search(query_embedding, top_k=top_k)
# Usage in Agent Loop
memory = AgentEpisodicMemory(filepath="agent_brain.nvec")
# Store facts if brain is empty
if len(memory.index) == 0:
memory.remember("mem_1", np.random.randn(384).astype(np.float32), "User prefers Python, C, and FASM.")
memory.remember("mem_2", np.random.randn(384).astype(np.float32), "NanoVector achieves sub-millisecond search.")
memory.remember("mem_3", np.random.randn(384).astype(np.float32), "Episodic memory saves state in single .nvec file.")
query_vec = np.random.randn(384).astype(np.float32)
recalled_facts = memory.recall(query_vec, top_k=3)
for match in recalled_facts:
print(f"Score: {match.score:.4f} -> Memory: {match.metadata}")
🔍 Metadata Filtering & Query Operators
NanoVector supports expressive, zero-overhead metadata filtering without external query engines.
# Exact match
index.search(query, top_k=5, filter={"author": "eminsk", "published": True})
# Comparison operators: $eq, $ne, $in, $nin, $gt, $gte, $lt, $lte
index.search(query, top_k=5, filter={
"views": {"$gte": 500},
"category": {"$in": ["ai", "systems"]},
"archived": {"$ne": True}
})
# Custom lambda predicates
index.search(query, top_k=5, filter=lambda meta: meta and meta.get("priority", 0) > 3)
🦜 1-Line Drop-in LangChain Integration
Replace ChromaDB or FAISS with NanoVector for instant <1ms cold starts and zero dependency bloat:
from nanovector import NanoVectorStore
from langchain_openai import OpenAIEmbeddings
embeddings = OpenAIEmbeddings()
# 1. Create VectorStore from raw texts (dim automatically inferred)
vectorstore = NanoVectorStore.from_texts(
texts=[
"NanoVector is 3,000x faster to import than ChromaDB.",
"Episodic memory runs in bare-metal C99 AVX2 SIMD.",
"Pure zero-dependency lightweight vector search engine."
],
embedding=embeddings,
metadatas=[{"source": "benchmark"}, {"source": "architecture"}, {"source": "design"}]
)
# 2. Similarity search with metadata filtering
docs = vectorstore.similarity_search("cold start latency", k=1, filter={"source": "benchmark"})
print(docs[0].page_content)
# -> "NanoVector is 3,000x faster to import than ChromaDB."
# 3. Use directly in LCEL (LangChain Expression Language) Chains & Agents
retriever = vectorstore.as_retriever(search_kwargs={"k": 2})
# 4. Save & reload single-file persistence
vectorstore.save("agent_brain.nvec")
reloaded_store = NanoVectorStore.load("agent_brain.nvec", embedding=embeddings)
🤖 Native MCP (Model Context Protocol) Server
NanoVector includes a built-in, zero-dependency MCP JSON-RPC 2.0 Server (nanovector-mcp) with a multilingual (RU/EN) feature-hashing + char n-gram embedder. Connect it to Claude Desktop, Cursor, Windsurf, or Antigravity to give your AI assistant sub-millisecond persistent .nvec episodic memory (nanovector_remember, nanovector_recall, nanovector_stats):
{
"mcpServers": {
"nanovector-memory": {
"command": "nanovector-mcp",
"args": ["--db", "~/.nanovector/memory.nvec", "--dim", "384"]
}
}
}
Or launch directly from terminal:
nanovector-mcp --db agent_memory.nvec
# or
python -m nanovector --mcp --db agent_memory.nvec
🚀 Interactive Google Colab Demo
Run NanoVector interactively in your browser with zero local setup:
The Interactive Colab Notebook demonstrates:
- Zero-Setup Installation & Hardware SIMD Detection: Compiles native C/AVX2 on Colab CPU in seconds.
- 10-line Cosine Similarity Search: Indexing and querying embeddings with JSON metadata.
- Real-World AI Agent Episodic Memory: Recalling instructions and preferences using
sentence-transformersembeddings (all-MiniLM-L6-v2). - Single-File
.nvecBrain Persistence: Instant binary save and zero-overhead reload. - Live 50,000-Vector Benchmark: Measuring ingestion throughput (1M+ vectors/sec) and search latency (~0.13 ms at 2k vectors, ~6.7 ms at 50k vectors) directly on Colab VM hardware.
📊 Benchmarks
Real-world benchmarks measured on Intel/AMD x86_64 CPU (AVX2+FMA) using standard 384-dimensional sentence embeddings (all-MiniLM-L6-v2) against NumPy 2.x / OpenBLAS:
Single-Threaded Exact Search Latency
| Dataset Size ($N$) | Metric | NanoVector Latency | NanoVector QPS | NumPy Baseline | Speedup |
|---|---|---|---|---|---|
| 500 vectors | Cosine | 0.0347 ms (34.7 µs) | 28,854 QPS | 0.0828 ms | 2.39x faster |
| 2,000 vectors | Cosine | 0.1337 ms (133.7 µs) | 7,478 QPS | 0.1876 ms | 1.40x faster |
| 10,000 vectors | Cosine | 1.4021 ms | 713 QPS | 1.1617 ms | Comparable (1 thread vs multi-core OpenBLAS) |
| 50,000 vectors | Cosine | 6.7479 ms | 148 QPS | 4.8132 ms | Exact 100% Recall |
High-Throughput Batch Ingestion & Persistence
- Ingestion Throughput: 1,414,447 vectors/sec (20,000 512D vectors ingested in 14.14 ms via Zero-Copy Buffer Protocol).
- Multi-Threaded Concurrency (8 threads): 14,300 QPS (400 concurrent queries executed in 27.97 ms with zero lock contention).
- Persistence Serialization: Save 2,000 vectors in 1.71 ms, load in 3.92 ms (single binary
.nvecfile).
🏛️ Architecture & Acceleration
NanoVector is written in standard C99 with a multi-tiered hardware acceleration pipeline:
┌───────────────────────────────┐
│ Python C-API │
│ (Buffer Protocol / No-GIL) │
└───────────────┬───────────────┘
│
┌───────────────▼───────────────┐
│ NanoVector C99 Core │
│ Top-K In-Place Heap $O(N\log K)$ │
└───────────────┬───────────────┘
│
┌────────────────────────┼────────────────────────┐
│ │ │
┌────────▼────────┐ ┌────────▼────────┐ ┌────────▼────────┐
│ x86_64 AVX2 │ │ ARM64 NEON │ │ FASM x64 │
│ 256-bit FMA │ │ 128-bit FMA │ │ Bare-Metal ASM │
│ (32 floats/iter)│ │ (16 floats/iter)│ │ (Windows x64) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
- 256-bit AVX2 + FMA (
src/nanovector_avx2.c):- 4-way unrolled kernel processing 32 single-precision floats per loop iteration across 4 YMM accumulators.
- Fused multiply-accumulate (
_mm256_fmadd_ps) eliminates intermediate register spills. - Tail handling handles arbitrary vector dimensions with zero padding penalties.
- ARM NEON (
src/nanovector_neon.c):- 128-bit vectorization for Apple Silicon (M1/M2/M3/M4) and AWS Graviton processors.
- 4-way unrolling processing 16 floats per iteration using
vfmaq_f32andvaddvq_f32.
- Pure FASM Assembly (
src/asm/nanovector_x64.asm):- Hand-crafted Windows x64 assembly routines adhering strictly to Microsoft x64 ABI calling conventions (volatile register allocation
ymm0..ymm5, shadow store handling). - Assembles cleanly into a 629-byte object file using Flat Assembler (FASM).
- Hand-crafted Windows x64 assembly routines adhering strictly to Microsoft x64 ABI calling conventions (volatile register allocation
- In-Place Top-$K$ Heap:
- Min-heap / Max-heap maintains the best $K$ matches in $O(N \log K)$.
- Branch-predicted pruning: candidate items with scores worse than the current $K$-th element are discarded in a single CPU clock cycle.
.nvecBinary Specification:- 64-byte aligned header with magic bytes
NVEC\x01. - Contiguous $N \times D \times 4$ raw float block (zero-copy memory-mappable).
- Compact length-prefixed ID and JSON metadata string tables.
- 64-byte aligned header with magic bytes
🐍 Python API Reference
nanovector.Index(dim: int, metric: str = "cosine", normalize: bool = False)
Initializes an embedded vector index.
dim(int): Vector dimensionality (e.g. 384, 768, 1536).metric(str): Distance metric:"cosine": Cosine similarity ($\frac{u \cdot v}{|u| |v|}$), higher is closer. Range $[-1.0, 1.0]$."dot"or"ip": Inner Product ($u \cdot v$), higher is closer."l2"or"euclidean": Squared Euclidean distance ($\sum (u_i - v_i)^2$), lower is closer.
normalize(bool): IfTrue, vectors are automatically L2-normalized upon insertion and search.
Methods
| Method | Description |
|---|---|
add(id: str, vector: Any, metadata: Optional[Union[str, dict]] = None) |
Adds a single 1D vector (NumPy array, list, or buffer) with unique ID and optional metadata dict/string. |
add_batch(ids: List[str], vectors: Any, metadatas: Optional[Sequence[Union[str, dict]]] = None) |
Adds multiple vectors in batch directly from 2D numpy.ndarray (Zero-Copy). Releases GIL. |
search(query: Any, top_k: int = 10, filter: Optional[Union[dict, callable]] = None) -> List[Match] |
Searches Top-$K$ nearest neighbors with optional metadata filter ($gte, $in, exact, lambda). Releases GIL. |
save(filepath: str) -> None |
Serializes the entire index to a single .nvec binary file on disk. |
load(filepath: str) -> Index |
Classmethod / function loading an index from a .nvec file in sub-millisecond time. |
Properties
index.dim(int): Dimensionality of indexed vectors.index.count(int) orlen(index): Total number of indexed vectors.index.metric(str): Active distance metric.match.id(str): ID of the matching item.match.score(float): Similarity score or distance.match.meta(dict or Any): Automatically parses JSON metadata string into a Python dict or primitive.nanovector.NanoVectorStore: Drop-in LangChainVectorStoreclass compatible with LCEL chains and agents.nanovector.version()(str): Library version string (e.g."0.1.6").nanovector.simd_backend()(str): Active hardware acceleration backend ("AVX2+FMA (x86_64)","ARM NEON", etc.).
🧪 Testing & Verification
Run the full test suite covering bare-metal SIMD indexing, FASM standalone executables & ctypes bindings, query filtering, LangChain LCEL integration, and multi-threaded concurrency:
# Run pytest with uv
uv run pytest -v
# Run under Free-Threaded Python 3.16t (No-GIL)
python -X gil=0 -m unittest discover -s tests -v
# Build and verify native FASM 64-bit & 32-bit suites
cd asm && build.bat
All 46 test cases pass with 100% success rate across Python 3.8 through 3.16 (including No-GIL free-threaded 3.13t–3.16t), PyPy 3.8 through 3.12, and native Flat Assembler (FASM).
🌐 High-Performance Systems Ecosystem
nanovector is developed by @eminsk as part of an open-source performance ecosystem:
- 🧠 AgentJIT — Just-In-Time Compiler for AI Agent Trajectories with speculative de-optimization guards (
pip install agentjit). - ⚡ NanoGEMM — Bare-metal AVX2+FMA SIMD matrix multiplication engine in ~100KB for sub-microsecond CPU neural network inference (
pip install nanogemm). - 🖥️ NanoRecall — 100% Private, offline desktop memory & semantic screen search engine powered by NanoVector (
pip install nanorecall). - 🛒 avito-sdk — High-performance headless Avito scraping & data extraction SDK with price tracking, Playwright cookies, and Telegram/VK bots (
pip install avito-sdk). - 📈 yfinance-ta-patterns — Institutional-grade technical pattern scanner with AI Confluence Scoring and LLM prompt generation (
pip install yfinance-ta-patterns). - 📊 xlsx_vievers — Headless Excel formula engine (129+ functions) & desktop spreadsheet processor with SSE2 SIMD math (
pip install xlsx-viewer-pro). - 🎥 screenvideo — Desktop screen recorder with WASAPI audio and standalone pure x64 FASM edition.
- 🔍 StackOverflowAPI — Bilingual desktop client with native FASM x64 search client.
☕ Support, Community & Donations
If you find this project valuable and would like to support ongoing development:
- ⭐ Star the Repository: If NanoVector speeds up your similarity searches and embeddings, give us a star on GitHub — it helps more developers discover bare-metal vector search!
- 💬 Join Discussions: Have ideas, use cases, or vector indexing benchmarks? Start or join a thread in GitHub Discussions!
- ☕ Donate (USDT TRC-20):
TDVbEdnpgNgoAhNcn1EwXxWHiR3RKLit5P
(Network: TRON / TRC-20 | Verify on TronScan)
📄 License
MIT License. See LICENSE for details.
Metadata
Release files for nanovector 0.1.8
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| nanovector-0.1.8.tar.gz | 75.8 kB | Without provenance | Details |
Release files / nanovector-0.1.8.tar.gz
| Download URL | nanovector-0.1.8.tar.gz |
|---|---|
| Size | 75.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
37495fe17d8efe6cecbb127927a2f757a68a2834d0fded7336936b57aa692acc
|
|
BLAKE2b-256 checksum How to use checksums |
ad756a2289140b6f339262e72968f057901fec9325d09ef4fae874816d3372fb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Security for nanovector 0.1.8
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.