The goal: similarity search + graph hopping + decay = working product. Then MCP server + plugins for different harnesses.
- Memory add endpoint (
POST /api/memory/add) - Embedding generation (Google text-embedding-004, 768d)
- HNSW index (add + search + persistence from SQLite)
- Sector classification via LLM (reuses existing sectors)
- Waypoint creation via LLM (fire-and-forget)
- Decay schedule row on memory add
- Sector memory_count tracking
- Vector bytes stored in
vector_indextable - HNSW index rebuilt from DB on startup
- DB schema (7 tables, indexes, constraints, relations)
- HMD v2 decay algorithm (implemented, not wired into retrieval yet)
- Parallel embedding + sector classification during add
- Dockerfile + docker-compose
Current: 20 LLM calls per memory add. Slow, expensive, noisy. Target: HNSW similarity first, LLM only for high-sim pairs.
-
Rewrite
CreateWaypointsto use embedding similarity- HNSW search for top-10 similar memories to the new one (instant, ~1ms)
- Filter: only pairs with cosine similarity >= 0.70
- For remaining (typically 2-5): LLM call to get relationship TYPE
- Waypoint strength = actual similarity score (not flat 0.8)
- LLM fallback only for high-similarity pairs, not every memory
-
Build in-memory adjacency map for graph traversal
- On startup: load all waypoints into a
Map<memoryId, [{targetId, strength, type}]> - Query BOTH directions (source and target) since connection is implicit bidirectional
- Update map when new waypoints are inserted
- Graph traversal becomes Map lookups (microseconds, no DB queries)
- On startup: load all waypoints into a
-
Build the retrieval function (
src/utils/retrieve.ts)query -> embed -> HNSW top-K -> hydrate from DB -> decay score -> graph expand -> rank -> returnSteps:
GenerateEmbedding(query)-> query vectorsearchMemories(vector, k=20)-> candidate memoryIds + distances- Fetch full memory rows from DB (batch by IDs)
HMDDecay.calculateQueryScore(memory, similarity)for each- Graph expand: for each top result, follow waypoints 1-2 hops via adjacency map
- Hop score = parent_score * waypoint_strength
- Only follow if hop score > 0.3
- Deduplicate
- Re-rank all results by composite score
- Return top-K
-
Wire reinforcement on retrieval
HMDDecay.reinforceMemory()for accessed memories- Update
access_count,last_accessedin DB - Boost waypoint strength by +0.05 for traversed edges
- Log to
memory_access_log
-
POST /api/memory/queryendpoint- Input:
{ query, userId, k?, filters? } - Returns:
{ results: [{ id, content, score, similarity, strength, sector, relationships }] }
- Input:
-
GET /api/memory/get/:idendpoint- Returns single memory with full details (sector, waypoints, decay info)
-
DELETE /api/memory/:id(soft delete -> set archived=true) -
GET /api/memory/all(paginated list, filter by userId/sector/archived) -
GET /api/sectors(list sectors with stats: count, avg strength) -
GET /api/health(version, index count, DB stats)
- Background job: runs every hour
- Query
decay_schedulewherenext_decay_at <= now HMDDecay.batchUpdateStrengths()for due memories- Archive memories below threshold (strength < 0.1)
- Update
next_decay_at
- Query
- Waypoint pruning: every 24h, remove waypoints with strength < 0.05
- MCP server wrapper around the REST API
- Tools:
memory_store,memory_query,memory_forget,memory_profile - Works with Claude Desktop, Cursor, etc.
- Tools:
- OpenClaw plugin (replace supermemory.ai with our local API)
- LangChain/LangGraph integration
- Python SDK
- JS/TS SDK
- Memory consolidation (merge similar memories periodically)
- Importance scoring at ingestion via LLM
- Contradiction detection + resolution
- User profile extraction from high-strength memories
- Multi-provider embeddings (OpenAI, Ollama, local)
- Document ingestion (PDF, DOCX, URL)
- Per-user decay calibration