Persistent memory search server with neural reranking and hybrid search (BM25 + vector).
- Hybrid search: BM25 keyword search + vector semantic search
- Neural reranking: Cross-encoder reranking for higher quality results
- Persistent models: Keeps embedding and reranker models loaded in memory
- File watching: Automatically re-indexes changed files
- Embedding cache: Avoids re-embedding unchanged text
- MMR diversity: Ensures result variety
- Temporal decay: Prioritizes recent files (configurable)
- Bun runtime
- LM Studio running locally on
localhost:1234withtext-embedding-qwen3-embedding-4bloaded - Reranker GGUF (optional):
~/.cache/qmd/models/hf_ggml-org_qwen3-reranker-0.6b-q8_0.gguf
bun installEdit config.json or set environment variables:
{
"port": 7420,
"lmstudio": {
"baseUrl": "http://localhost:1234/v1",
"embeddingModel": "text-embedding-qwen3-embedding-4b"
},
"models": {
"reranker": "~/.cache/qmd/models/hf_ggml-org_qwen3-reranker-0.6b-q8_0.gguf"
},
"collections": [
{
"name": "memory",
"path": "~/.lobs/workspace",
"pattern": ["MEMORY.md", "memory/**/*.md"]
}
]
}Environment variables:
PORT- Server port (default: 7420)LMSTUDIO_URL- LM Studio base URLEMBEDDING_MODEL- Embedding model nameRERANKER_MODEL- Path to reranker GGUF
bun run start
# or with auto-reload during development:
bun run devcurl -X POST http://localhost:7420/search \
-H "Content-Type: application/json" \
-d '{"query": "github issues", "maxResults": 5}'Response:
{
"results": [
{
"path": "/path/to/file.md",
"startLine": 10,
"endLine": 50,
"score": 0.85,
"snippet": "...",
"source": "memory",
"citation": "/path/to/file.md:10-50"
}
],
"query": "github issues",
"timings": {
"totalMs": 150,
"bm25Ms": 2,
"vectorMs": 45,
"rerankMs": 98
}
}curl http://localhost:7420/healthcurl http://localhost:7420/statuscurl -X POST http://localhost:7420/index- server/config.ts - Configuration loading
- server/db.ts - SQLite database with FTS5 and sqlite-vec
- server/chunker.ts - Markdown chunking
- server/embedder.ts - LM Studio embedding client
- server/reranker.ts - node-llama-cpp reranker
- server/search.ts - Full search pipeline
- server/indexer.ts - File indexing and watching
- server/index.ts - HTTP server
- BM25 search - Keyword search via SQLite FTS5
- Vector search - Semantic search via sqlite-vec
- Weighted merge - Combine scores (default: 70% vector, 30% text)
- Neural reranking - Cross-encoder scoring (if available)
- Temporal decay - Exponential decay based on file date
- MMR diversity - Maximal marginal relevance filtering
- Return top-K - Default 8 results
- Cold start: ~3-5s (loads reranker GGUF)
- Search latency: 100-200ms (with reranking)
- Embedding: ~25ms per chunk (LM Studio)
- Reranking: ~50-100ms for 20 candidates
# Install dependencies
bun install
# Run with auto-reload
bun run dev
# Check database
sqlite3 ~/.lobs/plugins/lobs-memory/index.db "SELECT COUNT(*) FROM documents;"LM Studio connection errors:
- Make sure LM Studio is running on localhost:1234
- Check that
text-embedding-qwen3-embedding-4bis loaded in LM Studio
Reranker not loading:
- Check that the GGUF file exists at the configured path
- The server will work without reranking if the model is missing (degrades gracefully)
Slow initial startup:
- First run indexes all files (can take a few minutes for large collections)
- Subsequent starts are fast (~3s) because files are cached
- The server is responsive immediately; indexing runs in background
Private - Part of the lobs-ai project.