Skip to content

How It Works

Memory lifecycle

memory_add(text)


 1. Hash dedup ──── duplicate? ──► skip


 2. Note Construction (LLM)
    ├── keywords (3–7 key terms)
    ├── tags (2–4 category tags)
    ├── context (one-sentence summary)
    └── category (Technical / Business / Personal / ...)


 3. Link Generation
    ├── retrieve top-6 candidates (embedding similarity > 0.3)
    └── LLM verifies each: link bidirectionally if relevant


 4. Memory Evolution
    ├── up to 3 linked notes get attributes updated
    └── may trigger additional link candidates


 5. Save to Qdrant

Retrieval pipeline

memory_search(query)


 1. Embed query (local ONNX, 384-dim)

      ├──► BM25 ranking (Jieba tokenized for CJK)
      └──► Dense vector cosine similarity


 2. RRF fusion (k=60)
    Final Score = BM25_rank⁻¹ + Vector_rank⁻¹


 3. Heat boost
    Score × (1 + 0.05 × ln(1 + retrieval_count) / (age_days + 1))


 4. 2-hop BFS expansion
    ├── Walk link graph up to 2 hops from top-K anchors
    └── Admit only nodes with cos-sim ≥ 0.25 vs query


 5. Return merged, deduplicated results

Temporal invalidation

When a memory is updated or contradicted, the old note is marked is_active: false and excluded from all future searches via Qdrant payload filtering. No data is ever hard-deleted — the full history is preserved.

Daily consolidation

At 02:30 AM (in-process scheduler), the plugin:

  1. Groups all active notes by category
  2. Within each group, finds pairs with cosine similarity ≥ 0.75
  3. Merges duplicates into a single unified note
  4. Cascades all link references from soft-deleted notes to the merged note

This prevents memory bloat from semantically redundant facts accumulated over days.

Released under the MIT License.