lorekeeper-devlisted
Install: claude install-skill Jessinra/Lorekeeper
# Lorekeeper Dev
Practices and conventions for developing the Lorekeeper MCP server.
## Architecture
Two vector store backends (switch via `LORE_VECTOR_STORE`):
- **LanceDB** (default) — concurrent multi-process, no lock files. `LanceDBEngine` in `lancedb_engine.py`. Uses sentence-transformers directly, no Mem0 for vectors.
- **Chroma** (fallback, `LORE_VECTOR_STORE=chroma`) — Mem0-backed `ChromaDBEngine` in `chromadb_engine.py`. Single-process only.
- **SQLite sidecar** — memory metadata (`score`, `confidence`, `soft_deleted`, `usage_count`), all `MemoryLink` rows, BM25 index source. Shared by both backends.
Engine factory: `engine_factory.py` → `build_engine()`. Orchestrator: `MemoryService` in `orchestrator.py`.
Canonical identity: `lore_id` UUID lives in the vector store's metadata. All app logic uses `lore_id`.
## Hybrid Scoring Formula
```
combined = 0.45·semantic + 0.30·keyword + 0.15·(score/10) + 0.10·log_usage_norm
```
Weights are env-configurable (`LORE_W_*`). Dedup threshold: `0.6·semantic + 0.4·keyword >= 0.85`.
## Known Quirks
**Chroma distance vs. similarity (critical):** Mem0 v2 `score_and_rank` receives Chroma cosine _distances_ but treats them as similarities. **Fix**: bypass mem0 pipeline — embed directly with `SentenceTransformer`, query directly, return `score = 1.0 - distance`.
**LanceDB:** Always returns cosine distance (lower=better). `normalize_score()` converts to similarity: `1.0 - distance`.
**`infer=False` on every `mem0.add()` call**