[](https://github.com/jose-compu/logosdb/actions/workflows/ci.yml)
[](https://github.com/jose-compu/logosdb/actions/workflows/python.yml)
[](https://pypi.org/project/logosdb/)
[](https://pypi.org/project/logosdb/)
LogosDB is the SQLite for AI Agents.
LogosDB is a fast semantic vector database written in C/C++ that provides approximate nearest-neighbor search over embedding vectors with associated text metadata.
Authors: Jose ([@jose-compu](https://github.com/jose-compu))
**Contributing**: See [CONTRIBUTING.md](CONTRIBUTING.md) for build instructions, style guide, and PR workflow.
# Features
* Vectors and metadata are stored as flat binary files, memory-mapped for zero-copy reads.
* Approximate nearest-neighbor search via [HNSW](https://arxiv.org/abs/1603.09320) (hnswlib), O(log n) query time.
* Each vector row carries optional text and ISO 8601 timestamp metadata (JSONL sidecar).
* The basic operations are `Put(embedding, text, timestamp)` and `Search(query, top_k)`.
* **Timestamp range filtering**: search within a time window (e.g., "last 24 hours").
* **Multiple distance metrics**: inner product, cosine similarity (auto-normalized), or L2 Euclidean.
* Bulk vector access for direct tensor construction (e.g. loading into GPU memory).
* Thread-safe API on a single open handle: an internal mutex serializes operations that touch the index and metadata (including search).
* Crash recovery: HNSW index is automatically backfilled from the append-only vector store on open.
* Scales to millions of vectors.
* **Framework integrations**: LangChain and LlamaIndex VectorStore adapters.
* **MCP server**: first-class [Claude Code](https://docs.anthropic.com/en/docs/claude-code/overview) integration via `logosdb-mcp-server`.
# Documentation
The public interface is in `include/logosdb/logosdb.h`. Callers should not include or rely on the details of any other header files in this package. Those internal APIs may be changed without warning.
**Planning a deployment?** See [docs/sizing.md](docs/sizing.md) for disk/RAM estimates based on N×dim, or run `python -m logosdb.sizing --rows 1_000_000 --dim 768`.
Guide to header files:
* **include/logosdb/logosdb.h**: Main interface to the DB. Start here. Contains:
- C API with opaque handles and `errptr` convention (RocksDB/LevelDB style)
- C++ convenience wrapper (`logosdb::DB`) with RAII and exceptions
- `logosdb::Options` for HNSW tuning and distance metric selection
- `logosdb::SearchHit` result struct
- `logosdb_search_ts_range()` for timestamp-filtered search
# Limitations
* This is not a general-purpose vector database. It is purpose-built for embedding-based memory retrieval in LLM inference ([funes.cpp](../funes.cpp)).
* Only a single process (possibly multi-threaded) can access a particular database at a time.
* There is no client-server support built into the library. An application that needs such support will have to wrap their own server around the library.
* For inner-product distance (`LOGOSDB_DIST_IP`, the default), vectors must be L2-normalized before insertion. Use `LOGOSDB_DIST_COSINE` for automatic normalization.
* Embedding generation is external — the caller provides pre-computed float vectors.
# Roadmap
Work is tracked in [open issues](https://github.com/jose-compu/logosdb/issues?q=is%3Aissue+is%3Aopen). **1.0.0** shipped on 2026-05-17; the public C API and supported language bindings follow [Semantic Versioning](https://semver.org/) on the `1.x` line:
| Bump | When |
|------|------|
| **Patch** (`1.0.Z`) | Bug fixes, security fixes, documentation, CI/build-only changes, and internal tooling that does **not** alter the supported contract of the public C API in [`include/logosdb/logosdb.h`](include/logosdb/logosdb.h) or the stable surface of language bindings. |
| **Minor** (`1.Y.z`) | Backward-compatible additions: new functions or options, new storage or index behaviors behind explicit settings, new integrations, new platforms, and additive file-format upgrades with automatic or guided migration. |
| **Major** (`2.0.0`) | Breaking changes to the public C API, on-disk format without a migration path, or binding contracts that cannot remain compatible. |
Target versions and issue assignment match **[GitHub milestones](https://github.com/jose-compu/logosdb/milestones)** (each open roadmap issue has exactly one milestone).
## Milestones → issues
Past releases are summarized in the [CHANGELOG](CHANGELOG) and the [closed milestones](https://github.com/jose-compu/logosdb/milestones?state=closed).
### **SHIPPED** [0.9.0](https://github.com/jose-compu/logosdb/milestone/8) — minor — throughput and scale
* [#87](https://github.com/jose-compu/logosdb/issues/87) — Streaming NDJSON import/export (`logosdb_export_ndjson` / `logosdb_import_ndjson` in C / C++ / Python) with `chunk_size`, byte-offset `--checkpoint`, and `--resume`. Parquet output is a follow-up.
* [#80](https://github.com/jose-compu/logosdb/issues/80) — Batch ingest v2: `logosdb_put_batch` is now chunked and WAL-aware (`LOGOSDB_BATCH_CHUNK_SIZE`, default 1024). Durability matches per-row `logosdb_put`; speed-up vs single put is workload-dependent (≈1.4× at dim=64 on the bench; HNSW per-row cost dominates at larger dims).
### **SHIPPED** [0.10.0](https://github.com/jose-compu/logosdb/milestone/9) — minor — search and metadata
* [#85](https://github.com/jose-compu/logosdb/issues/85) — Hybrid retrieval mode: ANN score + lexical score fusion
* [#84](https://github.com/jose-compu/logosdb/issues/84) — Filter API v2: structured metadata predicates beyond timestamp range
### **SHIPPED** [0.11.0](https://github.com/jose-compu/logosdb/milestone/10) — minor — multi-tenancy and tooling
* [#86](https://github.com/jose-compu/logosdb/issues/86) — Multi-tenant namespaces: quota and isolation within one DB root
* [#89](https://github.com/jose-compu/logosdb/issues/89) — Recall benchmarking utility for HNSW tuning
### **SHIPPED** [0.12.0](https://github.com/jose-compu/logosdb/milestone/11) — minor — integrations
* [#78](https://github.com/jose-compu/logosdb/issues/78) — Feature: Codex plugin marketplace integration for LogosDB
### **SHIPPED** [1.0.0](https://github.com/jose-compu/logosdb/milestone/13) — first stable release
* Smart chunking, UTF-8/NFC policy, path-hardening, and expanded security tests (#98, #108–#112). See [CHANGELOG](CHANGELOG) `1.0.0`.
### **SHIPPED** [1.0.1](https://github.com/jose-compu/logosdb/issues/116) — patch — release hygiene
* [#116](https://github.com/jose-compu/logosdb/issues/116) — Sync `CHANGELOG`, version macros, package metadata, and post-1.0 docs.
### Open — platform / hardening (post-1.0)
* [#10](https://github.com/jose-compu/logosdb/issues/10) — Windows support: abstract POSIX file I/O behind a portable layer
* [#111](https://github.com/jose-compu/logosdb/issues/111) — Finish Python integration-adapter security audit (partially addressed in 1.0.0 for `vibe.py`)
## Stability (since 1.0.0)
As of **1.0.0**, the project commits to stable semver for the public C API and supported language bindings:
* Breaking changes to `include/logosdb/logosdb.h` or on-disk layout require a future major version, with migration notes.
* Tier-1 platforms for 1.x are **Linux and macOS**; Windows remains tracked in [#10](https://github.com/jose-compu/logosdb/issues/10).
* Backup/restore and doctor tooling shipped in earlier 0.x releases; further hardening continues on the 1.x line.
# Getting the Source
```bash
git clone --recurse-submodules
cd logosdb
```
# Building
This project supports [CMake](https://cmake.org/) out of the box.
Quick start:
```bash
mkdir -p build && cd build
cmake -DCMAKE_BUILD_TYPE=Release .. && cmake --build .
```
This builds:
| Target | Description |
|--------|-------------|
| `logosdb` | Static library (`liblogosdb.a`) |
| `logosdb-cli` | Command-line tool for put, search, info |
| `logosdb-bench` | Benchmark: HNSW vs brute-force, with ChromaDB comparison |
| `logosdb-test` | Unit tests |
# Usage (C API)
```c
#include
char *err = NULL;
logosdb_options_t *opts = logosdb_options_create();
logosdb_options_set_dim(opts, 2048);
logosdb_t *db = logosdb_open("/tmp/mydb", opts, &err);
logosdb_options_destroy(opts);
float vec[2048] = { /* ... unnormalized vector ... */ };
// L2-normalize for inner-product distance (returns 0 on success, -1 if zero norm)
if (logosdb_l2_normalize(vec, 2048) == 0) {
logosdb_put(db, vec, 2048, "My commute is 42 minutes",
"2025-06-25T10:00:00Z", &err);
}
logosdb_search_result_t *res = logosdb_search(db, query_vec, 2048, 5, &err);
for (int i = 0; i < logosdb_result_count(res); i++) {
printf("#%d score=%.4f text=%s\n", i,
logosdb_result_score(res, i),
logosdb_result_text(res, i));
}
logosdb_result_free(res);
logosdb_close(db);
```
## Search with timestamp range filter
```c
#include
char *err = NULL;
logosdb_options_t *opts = logosdb_options_create();
logosdb_options_set_dim(opts, 2048);
logosdb_t *db = logosdb_open("/tmp/mydb", opts, &err);
// Search for top-5 matches within the last 24 hours
logosdb_search_result_t *res = logosdb_search_ts_range(
db, query_vec, 2048, 5,
"2025-04-21T10:00:00Z", // from (inclusive), NULL for no lower bound
"2025-04-22T10:00:00Z", // to (inclusive), NULL for no upper bound
50, // candidate_k: internal fetch multiplier (10x top_k recommended)
&err);
for (int i = 0; i < logosdb_result_count(res); i++) {
printf("#%d score=%.4f ts=%s text=%s\n", i,
logosdb_result_score(res, i),
logosdb_result_timestamp(res, i),
logosdb_result_text(res, i));
}
logosdb_result_free(res);
logosdb_close(db);
```
## Using different distance metrics
```c
#include
char *err = NULL;
logosdb_options_t *opts = logosdb_options_create();
logosdb_options_set_dim(opts, 2048);
// Use cosine similarity (automatically normalizes vectors)
logosdb_options_set_distance(opts, LOGOSDB_DIST_COSINE);
// Or use L2 Euclidean distance
// logosdb_options_set_distance(opts, LOGOSDB_DIST_L2);
// Default is LOGOSDB_DIST_IP (inner product on L2-normalized vectors)
logosdb_t *db = logosdb_open("/tmp/mydb", opts, &err);
logosdb_options_destroy(opts);
// For cosine: vectors are automatically normalized on put/search
float vec[2048] = { /* ... unnormalized vector ... */ };
logosdb_put(db, vec, 2048, "entry", "2025-04-22T10:00:00Z", &err);
logosdb_close(db);
```
# Usage (C++ wrapper)
```cpp
#include
#include
// Basic usage with default inner-product distance
logosdb::DB db("/tmp/mydb", {.dim = 2048});
// L2-normalize your vectors before insertion (required for inner-product distance)
std::vector embedding = load_some_vector(); // unnormalized
if (logosdb::l2_normalize(embedding)) {
db.put(embedding, "My commute is 42 minutes", "2025-06-25T10:00:00Z");
}
// Or use l2_normalized() to get a normalized copy
auto normalized = logosdb::l2_normalized(query);
auto results = db.search(normalized, 5);
for (auto &r : results) {
printf("id=%llu score=%.4f text=%s\n", r.id, r.score, r.text.c_str());
}
```
## C++: Search with timestamp filter
```cpp
#include
logosdb::DB db("/tmp/mydb", {.dim = 2048});
// Search within a time window
auto results = db.search_ts_range(
query, 5,
"2025-04-21T00:00:00Z", // from timestamp
"2025-04-22T00:00:00Z", // to timestamp
50); // candidate_k (optional, defaults to 10x top_k)
for (auto &r : results) {
printf("id=%llu score=%.4f ts=%s\n", r.id, r.score, r.timestamp.c_str());
}
```
## C++: Using cosine or L2 distance
```cpp
#include
// Cosine similarity - vectors are automatically normalized
logosdb::DB db("/tmp/mydb", {.dim = 2048, .distance = LOGOSDB_DIST_COSINE});
// Put unnormalized vectors - they will be normalized automatically
db.put(unnormalized_embedding, "entry", "2025-04-22T10:00:00Z");
auto results = db.search(query, 5);
// scores are cosine similarities in [0, 1]
// L2 Euclidean distance
// logosdb::DB db("/tmp/mydb", {.dim = 2048, .distance = LOGOSDB_DIST_L2});
```
# Python
LogosDB ships Python bindings built with [pybind11](https://pybind11.readthedocs.io/) and [scikit-build-core](https://scikit-build-core.readthedocs.io/).
Install from PyPI (binary wheels provided for Linux x86_64/aarch64 and macOS x86_64/arm64 on CPython 3.9–3.13):
```bash
pip install logosdb
```
Or build from source in a clone:
```bash
pip install .
```
Usage:
```python
import logosdb
from sentence_transformers import SentenceTransformer
# Local Hugging Face embeddings model (runs on your machine)
model = SentenceTransformer("sentence-transformers/all-MiniLM-L6-v2")
dim = model.get_sentence_embedding_dimension()
# Use cosine distance so LogosDB auto-normalizes vectors
db = logosdb.DB("/tmp/agent_memory", dim=dim, distance=logosdb.DIST_COSINE)
# Three learnings captured by an AI agent
learnings = [
("Retrying API calls with exponential backoff reduced transient failures by 42%.", "2026-05-06T09:00:00Z"),
("Splitting long tasks into smaller batches improved throughput and lowered memory spikes.", "2026-05-06T09:05:00Z"),
("Adding idempotency keys prevented duplicate writes during network retries.", "2026-05-06T09:10:00Z"),
]
for text, ts in learnings:
emb = model.encode(text).astype("float32")
db.put(emb, text=text, timestamp=ts)
# Ask a natural-language question
question = "How can we avoid duplicate writes when retries happen?"
q_emb = model.encode(question).astype("float32")
hits = db.search(q_emb, top_k=3)
for h in hits:
print(f"{h.score:.4f} {h.text}")
```
## Python: Using cosine distance (no manual normalization needed)
```python
import numpy as np
import logosdb
# With cosine distance, vectors are automatically normalized
db = logosdb.DB("/tmp/mydb", dim=128, distance=logosdb.DIST_COSINE)
# No need to normalize - just put raw vectors
v = np.random.randn(128).astype(np.float32)
rid = db.put(v, text="unnormalized vector", timestamp="2025-04-22T10:00:00Z")
# Search also works with unnormalized queries
query = np.random.randn(128).astype(np.float32)
hits = db.search(query, top_k=5)
```
## Python: Batch ingest and streaming NDJSON (0.9.0)
```python
import numpy as np
import logosdb
db = logosdb.DB("/tmp/mydb", dim=128, distance=logosdb.DIST_COSINE)
# Chunked, WAL-aware batch insert (LOGOSDB_BATCH_CHUNK_SIZE controls fsync cadence).
embeddings = np.random.randn(10_000, 128).astype(np.float32)
ids = db.put_batch(embeddings, texts=[f"row {i}" for i in range(10_000)])
# Bounded-memory NDJSON export/import; --resume from a checkpoint on interruption.
db.export_ndjson("/tmp/rows.ndjson")
restored = logosdb.DB("/tmp/restored", dim=128, distance=logosdb.DIST_COSINE)
restored.import_ndjson("/tmp/rows.ndjson", chunk_size=1024,
checkpoint_path="/tmp/rows.cp", resume=False)
```
Run the Python tests and examples:
```bash
pip install ".[test]"
pytest tests/python/
python examples/python/basic_usage.py
# sentence-transformers demo (optional heavy dep)
pip install ".[examples]"
python examples/python/sentence_transformers_demo.py
```
## Memory-Efficient On-Prem RAG
LogosDB is designed for memory-efficient retrieval-augmented generation (RAG) that runs entirely on your hardware.
### RAM Model
LogosDB uses `mmap()` for zero-copy access. Your RAM usage scales with **query patterns**, not dataset size:
| Dataset | Dim | Disk | Typical Query RAM |
|---------|-----|------|-------------------|
| 100K | 384 | 153 MB | <20 MB |
| 1M | 384 | 1.5 GB | <100 MB |
| 10M | 384 | 15 GB | <200 MB |
The OS caches hot index pages; cold data stays on disk. No explicit loading/unloading needed.
### Quick RAG Example
```python
import numpy as np
import logosdb
from sentence_transformers import SentenceTransformer
# 1. Load model (runs locally)
model = SentenceTransformer("sentence-transformers/all-MiniLM-L6-v2")
dim = model.get_sentence_embedding_dimension()
# 2. Create DB with cosine distance (auto-normalizes)
db = logosdb.DB("/data/knowledge", dim=dim, distance=logosdb.DIST_COSINE)
# 3. Index documents
for text in documents:
emb = model.encode(text)
db.put(emb, text=text) # Auto-normalized with cosine distance
# 4. Query (only touched pages load into RAM)
query_emb = model.encode("What is HNSW?")
for hit in db.search(query_emb, top_k=3):
print(f"{hit.score:.4f} {hit.text}")
```
See [docs/rag-on-prem.md](docs/rag-on-prem.md) for complete guide including:
- Time-sharding for infinite retention
- External quantization patterns
- Architecture patterns for production
See [docs/sizing.md](docs/sizing.md) for detailed disk/RAM formulas and the `python -m logosdb.sizing` calculator.
Run the memory-efficient RAG example:
```bash
pip install ".[examples]"
python examples/python/memory_efficient_rag.py
```
## Python: LlamaIndex VectorStore
```bash
pip install 'logosdb[llama-index]'
```
```python
from logosdb import LogosDBIndex
from llama_index.core import Document
from llama_index.core.schema import TextNode
from llama_index.core.vector_stores import VectorStoreQuery
import numpy as np
# Create the vector store
db = LogosDBIndex(uri="/tmp/mydb", dim=128)
# Add nodes with pre-computed embeddings
node = TextNode(
text="My commute is 42 minutes",
embedding=np.random.randn(128).astype(np.float32).tolist(),
metadata={"timestamp": "2025-04-28T10:00:00Z"}
)
db.add([node])
# Query
query_emb = np.random.randn(128).astype(np.float32).tolist()
query = VectorStoreQuery(query_embedding=query_emb, similarity_top_k=5)
results = db.query(query)
for node, score in zip(results.nodes, results.similarities):
print(f"Score: {score:.4f}, Text: {node.text}")
# Timestamp range filtering
results = db.query(query, ts_from="2025-04-01T00:00:00Z", ts_to="2025-04-30T23:59:59Z")
```
The `LogosDBIndex` class implements LlamaIndex's `VectorStore` interface, supporting:
- `add(nodes)` - Add nodes with embeddings
- `delete(node_id)` - Delete by node ID
- `query(VectorStoreQuery)` - Similarity search by vector
- `count()` / `len(store)` - Number of live documents
- Timestamp filtering via `ts_from` and `ts_to` kwargs
# CLI
```bash
# Database info
logosdb-cli info /tmp/mydb
# Search with a binary query vector file
logosdb-cli search /tmp/mydb --query-file q.bin --top-k 5
# Streaming NDJSON export / import (#87) — bounded memory, optional resume
logosdb-cli export /tmp/mydb --output rows.ndjson [--start-id N --end-id M]
logosdb-cli import /tmp/mydb --dim 768 --input rows.ndjson \
--chunk-size 1024 --checkpoint rows.cp [--resume]
```
# Node.js
## MCP Server — Claude Code integration
`logosdb-mcp-server` is a [Model Context Protocol](https://modelcontextprotocol.io/) server that
exposes LogosDB to **Claude Code** (and any other MCP client) over stdio. It lets Claude index
files, persist knowledge across sessions, and do semantic search without leaving the conversation.
### Claude Code: complete recipe
Follow these steps in order. Claude Code spawns the MCP server with **working directory = your project root** (the folder you opened); paths in `mcp.json` and `LOGOSDB_PATH` are resolved relative to that cwd unless you use absolute paths.
#### 1. Prerequisites
- **Node.js** 18 or newer on your `PATH` (`node -v`, `npm -v`). For the published package you also need **`npx`**.
- **Claude Code** installed and signed in ([overview](https://docs.anthropic.com/en/docs/claude-code/overview)).
- Decide **where the DB lives**: `LOGOSDB_PATH` (default `./.logosdb`) is created under the project root; add the directory to `.gitignore` if you do not want it committed.
#### 2. Install the server (pick one)
**Option A — This repository (local `node`, no `npx`).** From the **repository root**:
```bash
npm install
```
That installs the `mcp` workspace and runs **`prepare`**, which compiles TypeScript to [`mcp/dist/index.js`](mcp/dist/index.js). After you change MCP sources, run `npm run mcp:build` at the root or `npm run build` inside `mcp/`.
**Option B — Any other project (published [`logosdb-mcp-server`](https://www.npmjs.com/package/logosdb-mcp-server)).** In your app’s root:
```bash
npm install logosdb-mcp-server
```
You can still invoke it without a project dependency via `npx -y logosdb-mcp-server` (see Option C).
#### 3. Register the MCP server in Claude Code
Project-local config lives in **`.claude/mcp.json`** at the repository root. User-wide config is **`~/.claude.json`** (same `mcpServers` shape). Only one definition named `logosdb` is needed.
**If you use Option A (this clone):** the repo already contains [`.claude/mcp.json`](.claude/mcp.json):
```json
{
"mcpServers": {
"logosdb": {
"command": "node",
"args": ["./mcp/dist/index.js"],
"env": {
"LOGOSDB_PATH": "./.logosdb"
}
}
}
}
```
Open **this folder** as the Claude Code project so `./mcp/dist/index.js` resolves. If the client’s cwd is **not** the repo root, set `"args"` to an **absolute** path to `mcp/dist/index.js` (see [Installing locally — Option C](#installing-locally-without-npx)).
**If you use Option B or prefer always-latest from npm (Option C):** create or merge `.claude/mcp.json`:
```json
{
"mcpServers": {
"logosdb": {
"command": "npx",
"args": ["-y", "logosdb-mcp-server"],
"env": {
"LOGOSDB_PATH": "./.logosdb"
}
}
}
}
```
Default embeddings are **local Transformers.js** (no API keys); first run may download model weights. Optional **Ollama / OpenAI / Voyage** env vars are documented in [`mcp/README.md`](mcp/README.md#configure).
#### 4. Path rules for `logosdb_index_file`
The server only indexes files that resolve under **`process.cwd()`** or **`LOGOSDB_INDEX_ROOT`** (if set). Symlinks that escape those roots are rejected. Keep indexing paths inside the project you opened, or set `LOGOSDB_INDEX_ROOT` to an absolute allowed root (details in [`mcp/README.md` — Path confinement](mcp/README.md#path-confinement-logosdb_index_file)).
#### 5. Reload Claude Code and verify
- **Restart** Claude Code or reload MCP configuration after editing `mcp.json`.
- The **logosdb** server starts on **first tool use** (stdio).
- Ask the agent to run **`logosdb_list`** (or check the MCP tools panel). You should see namespaces (possibly empty) rather than a spawn error.
#### 6. Index, search, delete
- **Natural language:** e.g. “Index `src/` into the `code` namespace”, “Search the codebase for JWT validation”.
- **Slash commands (optional):** if `.claude/commands/` is present in the project (this repo ships them), use `/index`, `/search`, `/forget` — see the table below.
- **Snippet memory:** the agent can call **`logosdb_index`** for short text; **`logosdb_index_file`** chunks files and directories.
Use **one embedding backend consistently** per namespace on disk (do not change model dimension on existing data). See [Environment variables](#environment-variables) and [`mcp/README.md`](mcp/README.md).
#### 7. Optional: agent instructions
Copy the **`CLAUDE.md`** template block from [Agent instructions (`CLAUDE.md` and similar)](#agent-instructions-claudemd-and-similar) into your project so the agent indexes and searches without being reminded every session.
#### 8. Troubleshooting
| Symptom | What to try |
|--------|----------------|
| MCP fails to start / “Cannot find module” | From the same cwd Claude uses, run `node ./mcp/dist/index.js` (Option A) or `npx -y logosdb-mcp-server` (Option C) in a terminal; fix missing `npm install` or broken path. |
| Relative `./mcp/dist/index.js` not found | Use an **absolute** `args` path to `index.js`, or open the correct folder as the project root. |
| `logosdb_index_file` rejects a path | Path is outside cwd / `LOGOSDB_INDEX_ROOT`; use a path inside the project or set `LOGOSDB_INDEX_ROOT`. |
| Search looks wrong after changing model | New embeddings must use a **fresh** `LOGOSDB_PATH` or new namespace; dimensions must match. |
**Google Antigravity:** same stdio MCP pattern (`node` + local script, or `npx` + package). Step-by-step: [`mcp/README.md` — Google Antigravity](mcp/README.md#google-antigravity).
### Claude Code slash commands
This repo ships **project slash commands** under [.claude/commands/](.claude/commands/) (in addition to [`.claude/mcp.json`](.claude/mcp.json) for the MCP server):
| Command | Role |
|---------|------|
| `/index` | Index a **file or directory** via `logosdb_index_file` with **`incremental: true`** (new/changed files only; `commands/index.md`) |
| `/search` | Semantic search; optional ISO `ts_from` / `ts_to` on the MCP tool (`commands/search.md`) |
| `/forget` | Delete by row `id` **or** by natural-language `query` (`commands/forget.md`) |
### Agent instructions (`CLAUDE.md` and similar)
The MCP server does not index the repository by itself: **the agent must call the tools** (or you rely on slash commands / hooks). To make LogosDB feel automatic without typing `/index` every time, add a block like the following to your project’s **`CLAUDE.md`** (or any instructions file your agent reads on every session). Adjust namespaces and paths to your repo.
````markdown
## LogosDB (semantic memory via MCP)
The **logosdb** MCP server is configured. Data lives on disk under `LOGOSDB_PATH` (see `.claude/mcp.json`); it **persists across sessions**.
**Namespaces:** Use separate namespaces for different concerns (e.g. `code` for `src/`, `docs` for `docs/`, `decisions` for short architectural notes). Search only the namespace that matches the user’s task.
**When starting substantive work on this codebase:**
1. If the user has not indexed recently and you need broad code context, call **`logosdb_index_file`** with **`incremental: true`** on the smallest useful path (e.g. `src/` or a package directory), not the whole monorepo unless asked.
2. Before answering “where is X implemented?” or similar, call **`logosdb_search`** with a tight natural-language `query`, `namespace` set appropriately, and `top_k` between **3** and **8**. Do not paste entire trees into the chat—retrieve, then read only the cited files.
3. For “what did we decide recently?” style questions, use **`logosdb_search`** with optional **`ts_from` / `ts_to`** (ISO 8601 inclusive bounds) on the `decisions` or `docs` namespace when timestamps matter.
4. When the user states a durable fact worth remembering (API contract, policy, workaround), call **`logosdb_index`** into the right namespace with concise text (timestamps are stored automatically; optional **`metadata`** can label the source).
**After large refactors or dependency upgrades:** Re-run **`logosdb_index_file`** with **`incremental: true`** on affected paths so search stays aligned without duplicating chunks for unchanged files.
**Deletion:** Use **`logosdb_delete`** with **`id`** from a prior search hit, or with **`query`** + optional **`match_rank`** / **`search_top_k`** to remove a semantically matched row when the user asks to forget something.
````
### Environment variables
| Variable | Default | Description |
|---|---|---|
| `LOGOSDB_PATH` | `./.logosdb` | Root directory for all namespace databases |
| `EMBEDDING_PROVIDER` | *(local)* | Omit for Transformers.js on-device; or `ollama`, `openai`, `voyage` |
| `TRANSFORMERS_MODEL` | `Xenova/all-MiniLM-L6-v2` | Local embedding model (bundled MCP path) |
| `OLLAMA_*` | — | See `mcp/README.md` when using Ollama |
| `OPENAI_API_KEY` | — | Required when `EMBEDDING_PROVIDER=openai` |
| `VOYAGE_API_KEY` | — | Required when `EMBEDDING_PROVIDER=voyage` |
| `LOGOSDB_CHUNK_SIZE` | `800` | Target characters per chunk for `"legacy"` and `"section"` chunking modes |
| `LOGOSDB_CHUNK_MODE` | `auto` | Chunking strategy: `auto` (per-extension), `line` (code), `section` (markdown/rst), `legacy` (original paragraph/char). See [`mcp/README.md` — Chunking strategies](mcp/README.md#chunking-strategies). |
Voyage AI (`voyage-3`, dim=1024) is Anthropic's recommended cloud embedding model:
```json
"env": {
"LOGOSDB_PATH": "./.logosdb",
"EMBEDDING_PROVIDER": "voyage",
"VOYAGE_API_KEY": ""
}
```
### Available tools
| Tool | Description |
|---|---|
| `logosdb_index` | Embed and store a text snippet in a namespace |
| `logosdb_index_file` | Chunk, embed, and store a file or tree; optional **`incremental: true`** (skip unchanged, replace changed, prune deleted under a directory). When the path lives inside a Git working tree the walker honours `.gitignore` (root + nested + `.git/info/exclude` + global excludes) by default; disable with `respect_gitignore: false` or `LOGOSDB_RESPECT_GITIGNORE=0`. |
| `logosdb_search` | Semantic search; optional `ts_from` / `ts_to` (ISO 8601) for timestamp-window filter |
| `logosdb_list` | List all namespaces |
| `logosdb_info` | Stats for a namespace (count, dimension, path) |
| `logosdb_delete` | Delete by row `id`, or by natural-language `query` (`search_top_k`, `match_rank`) |
### Installing locally (without npx)
**Option A — global CLI on your machine**
```bash
npm install -g logosdb-mcp-server
```
In `.claude/mcp.json`, point the server at the global binary:
```json
"logosdb": {
"command": "logosdb-mcp-server",
"args": [],
"env": { "LOGOSDB_PATH": "./.logosdb" }
}
```
Ensure the directory containing the global npm binaries is on your `PATH` when Claude Code spawns the process (same shell you use for `npm install -g`).
**Option B — project-local `node_modules` (no global install)**
From your app repo:
```bash
npm install logosdb-mcp-server
```
Then use `npx` so the binary resolves from `./node_modules`:
```json
"logosdb": {
"command": "npx",
"args": ["-y", "logosdb-mcp-server"],
"env": { "LOGOSDB_PATH": "./.logosdb" }
}
```
Omit `-y` if you prefer a fixed local install only. You can also call the entry script explicitly:
```json
"command": "node",
"args": ["./node_modules/logosdb-mcp-server/dist/index.js"],
"env": { "LOGOSDB_PATH": "./.logosdb" }
```
**Option C — development build from a LogosDB clone**
```bash
cd mcp && npm install && npm run build
```
This repository’s checked-in [`.claude/mcp.json`](.claude/mcp.json) uses a **relative** path `./mcp/dist/index.js` after **`npm install` from the repo root** (workspace `prepare`). For **other** clients or if the process cwd is not the repo root, use an **absolute** path to `mcp/dist/index.js`:
```json
"logosdb": {
"command": "node",
"args": ["/absolute/path/to/logosdb/mcp/dist/index.js"],
"env": { "LOGOSDB_PATH": "./.logosdb" }
}
```
The same `env` block (`LOGOSDB_PATH`, embedding variables) applies to every option. Restart Claude Code or reload MCP config after editing `.claude/mcp.json`.
# Performance
Here is a performance report from the included `logosdb-bench` program. The results are somewhat noisy, but should be enough to get a ballpark performance estimate.
## Setup
We use databases with 1K, 10K, and 100K vectors. Each vector has 2048 dimensions (matching typical LLM embedding sizes). Vectors are L2-normalized random unit vectors.
*(Numbers below are illustrative ballparks; absolute values depend on hardware and build flags. Relative HNSW vs brute-force behavior is what to focus on.)*
LogosDB: version 1.0.1
CPU: Apple M-series (ARM64)
Dim: 2048
HNSW M: 16, ef_construction: 200, ef_search: 50
## Write performance
put (1K vectors): ~50 µs/op (~20,000 inserts/sec)
put (10K vectors): ~80 µs/op (~12,500 inserts/sec)
put (100K vectors): ~120 µs/op (~8,300 inserts/sec)
Each "op" above corresponds to a write of a single vector + metadata + HNSW index update.
## Search performance
HNSW top-5 (1K): ~0.1 ms/query
HNSW top-5 (10K): ~0.3 ms/query
HNSW top-5 (100K): ~1.2 ms/query
Brute-force top-5 (1K): ~0.3 ms/query
Brute-force top-5 (10K): ~2.5 ms/query
Brute-force top-5 (100K): ~25 ms/query
HNSW maintains sub-linear scaling while brute-force grows linearly with database size. At 100K vectors, HNSW is roughly 20x faster.
## VectorDB Bench
[VectorDB Bench](https://github.com/zilliztech/VectorDBBench) is the standard open-source harness for comparing vector databases at realistic scale (load, optimize, serial/concurrent search, recall). LogosDB is integrated as a first-class backend:
| Location | Role |
|----------|------|
| `vectordb_bench/backend/clients/logosdb/` | Client: `config.py`, `logosdb.py`, `cli.py` |
| `vectordb_bench/backend/clients/__init__.py` | `DB.LogosDB` enum + `init_cls` / `config_cls` / `case_config_cls` mappings |
| `vectordb_bench/cli/vectordbbench.py` | CLI subcommand `logosdb` |
| `pyproject.toml` | Optional extra `logosdb` (installs the Python bindings used by the client) |
### Results — `Performance1536D50K` (2026-05-17)
OpenAI embeddings, **50K** vectors, **1536** dimensions, **cosine** distance. Serial search only (`--skip-search-concurrent`). Absolute timings depend on hardware; recall/NDCG are the primary cross-database comparators.
| Metric | Value |
|--------|-------|
| Load duration | 340.4 s |
| Insert duration | 339.6 s |
| Optimize duration | 0.8 s |
| Serial latency p99 | 4.6 ms |
| Serial latency p95 | 4.0 ms |
| Recall@100 | **0.9347** |
| NDCG | **0.9464** |
Raw JSON: `vectordb_bench/results/LogosDB/result_20260517_*.json` (under your VectorDB Bench checkout).
### Re-run
From a VectorDB Bench tree with the LogosDB client installed (`pip install -e '.[logosdb]'` or equivalent):
```bash
.venv/bin/python3.12 -m vectordb_bench.cli.vectordbbench logosdb \
--uri /tmp/vectordbbench_logosdb \
--case-type Performance1536D50K \
--skip-search-concurrent
```
Use a fresh `--uri` directory per run. Set `OPENAI_API_KEY` (or the embedding provider your case expects) before starting.
## Results — `glove-25-angular` (qdrant/vector-db-benchmark)
Standard [qdrant/vector-db-benchmark](https://github.com/qdrant/vector-db-benchmark) harness, **1.18M × 25** vectors, **cosine** distance (angular). Serial search.
| Metric | Value |
|--------|-------|
| Upload time | 345 s |
| Mean precision@10 | 0.939 |
| RPS | 9,401 |
| Mean latency | 0.092 ms |
| p99 latency | 0.146 ms |
Source: [qdrant/vector-db-benchmark](https://github.com/qdrant/vector-db-benchmark).
## Benchmark vs ChromaDB
```bash
logosdb-bench --dim 2048 --counts 1000,10000,100000
```
| Metric | ChromaDB | LogosDB |
|--------|----------|---------|
| Language | Python + C (hnswlib) | Pure C/C++ |
| Search algorithm | HNSW | HNSW (same hnswlib) |
| Storage | SQLite + Parquet | Binary mmap + JSONL |
| Startup overhead | Python runtime + deps | Zero (linked library) |
| Embedding generation | Built-in (Sentence Transformers) | External (caller provides vectors) |
| Target use case | General-purpose vector store | Embedded LLM inference memory |
| Search latency (100K, dim=2048) | ~5-10 ms | ~1-3 ms |
| Memory footprint (100K, dim=2048) | ~1.5 GB (Python + SQLite) | ~800 MB (mmap) |
| Cold start | ~2-5 s (Python imports) | <10 ms |
| Dependencies | Python, NumPy, SQLite, hnswlib | hnswlib (header-only, vendored) |
LogosDB uses the same HNSW implementation as ChromaDB (hnswlib) but eliminates Python overhead, SQLite serialization, and Sentence Transformer coupling. The result is a leaner library optimized for the single use case of embedded semantic memory for LLM inference.
# Repository contents
include/logosdb/logosdb.h Public C/C++ API (start here)
src/logosdb.cpp Core engine: wires storage + index + metadata
src/storage.h / storage.cpp Fixed-stride binary vector file with mmap
src/metadata.h / metadata.cpp Append-only JSONL text + timestamp store
src/hnsw_index.h / .cpp Thin wrapper around hnswlib
tools/logosdb-cli.cpp Command-line interface
tools/logosdb-bench.cpp Benchmark tool
tests/test_doctest.cpp C++ unit tests (doctest, incl. CLI integration)
tests/test_stress.cpp Stress/property tests (opt-in via --test-suite=stress)
tests/python/test_smoke.py Python smoke tests (pytest)
python/src/bindings.cpp pybind11 Python bindings
python/logosdb/ Python package (logosdb._core + stubs)
examples/python/ Python usage examples
pyproject.toml Python build/config (scikit-build-core)
third_party/hnswlib/ Vendored hnswlib (header-only)
package.json / package-lock.json Private npm workspace (MCP + `nodejs` logosdb); `npm install` at repo root only
mcp/ MCP server (logosdb-mcp-server npm package)
.claude/mcp.json Claude Code MCP config (local `node ./mcp/dist/index.js`)
.claude/commands/ Slash command prompts (/index, /search, /forget)
CHANGELOG Release history
LICENSE MIT license text
# Contributing
We welcome contributions. See [CONTRIBUTING.md](CONTRIBUTING.md) for:
- Building from source
- Running tests and benchmarks
- Code style and PR workflow
Please review our [Code of Conduct](CODE_OF_CONDUCT.md) and [Security Policy](SECURITY.md).
# License
MIT — see [LICENSE](LICENSE) for the full text.