th-memory-mcp 2.0.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1594 @@
1
+ # th-memory-mcp v2 — Architecture & Implementation Specification
2
+
3
+ **Status:** ✅ Released — `th-memory-mcp v2.0.0` is published (npm + Official MCP Registry + Glama).
4
+ **Baseline:** v1.2.2 → **Current:** v2.0.0
5
+ **Primary goal:** evolve th-memory-mcp from a structured local memory MCP into a durable, temporal, conflict-aware, hybrid-retrieval memory engine for AI agents.
6
+
7
+ > **Audience guide:** End users should read [README.md](README.md) (install, tools, usage). This document is the **canonical architecture & agent-rules spec** for developers and AI coding agents — the single source of truth for structure and behavior. The former `design.md` build log has been folded into §40 Implementation Status.
8
+
9
+ ---
10
+
11
+ ## 0. Executive Decision
12
+
13
+ v2 is a **refactor + controlled expansion**, not a rewrite and not a clone of Mem0, Zep/Graphiti, or Letta.
14
+
15
+ The project must retain these v1 properties:
16
+
17
+ - Local-first and offline by default.
18
+ - SQLite as the primary persistence layer.
19
+ - FTS5 and local semantic search.
20
+ - Thai/English support.
21
+ - Auto-capture and cross-harness compatibility.
22
+ - Secret filtering and safe export.
23
+ - Graceful degradation when memory is unavailable.
24
+ - Small MCP surface and bounded output.
25
+
26
+ v2 adds five core capabilities:
27
+
28
+ 1. Unified memory model.
29
+ 2. Temporal state and supersession.
30
+ 3. Duplicate/conflict resolution.
31
+ 4. Hybrid retrieval with ranking/fusion.
32
+ 5. Context assembly with token budgeting.
33
+
34
+ Optional AI-assisted extraction/consolidation must never make the core memory engine dependent on an external LLM API.
35
+
36
+ ---
37
+
38
+ # 1. Design Principles
39
+
40
+ ## 1.1 Memory is data, not instructions
41
+
42
+ Stored memory must never override the agent's system/developer instructions or become executable instructions merely because it contains imperative text.
43
+
44
+ ## 1.2 Event != memory
45
+
46
+ Raw interactions are evidence/feedstock. Long-term memories are derived, structured records.
47
+
48
+ ```text
49
+ Interaction/Event
50
+ ↓
51
+ Capture + filtering
52
+ ↓
53
+ Extraction/classification
54
+ ↓
55
+ Memory candidate
56
+ ↓
57
+ Dedup/conflict resolution
58
+ ↓
59
+ Persistent memory
60
+ ```
61
+
62
+ ## 1.3 Current truth and historical truth are both valuable
63
+
64
+ Old memories are not automatically deleted because they became stale. They can remain available for historical queries.
65
+
66
+ ## 1.4 Deterministic-first
67
+
68
+ Core operations must work without an LLM:
69
+
70
+ - persistence
71
+ - FTS search
72
+ - semantic search
73
+ - metadata filtering
74
+ - scoring
75
+ - RRF fusion
76
+ - lifecycle transitions
77
+ - basic duplicate detection
78
+ - basic conflict detection
79
+
80
+ LLM assistance is optional for:
81
+
82
+ - difficult extraction
83
+ - ambiguous conflict resolution
84
+ - consolidation
85
+ - summarization/compression
86
+
87
+ ## 1.5 Context is a projection of memory
88
+
89
+ The database is not the prompt. `get_context` selects a small, relevant, safe projection from persistent memory.
90
+
91
+ ## 1.6 Failure must be non-fatal
92
+
93
+ Memory failures must not crash the host agent. MCP operations should return bounded diagnostic text where appropriate and continue gracefully.
94
+
95
+ ---
96
+
97
+ # 2. High-Level Architecture
98
+
99
+ ```text
100
+ AI AGENT
101
+ │
102
+ MCP
103
+ │
104
+ ┌───────▼────────┐
105
+ │ MEMORY API │
106
+ └───────┬────────┘
107
+ │
108
+ ┌─────────────┼─────────────┐
109
+ │ │ │
110
+ ▼ ▼ ▼
111
+ CAPTURE ENGINE RETRIEVAL LIFECYCLE
112
+ │ ENGINE ENGINE
113
+ │ │ │
114
+ │ ┌──────┼──────┐ │
115
+ │ │ │ │ │
116
+ │ FTS VECTOR GRAPH │
117
+ │ │ │ │ │
118
+ │ └──────┼──────┘ │
119
+ │ │ │
120
+ └─────────────┼─────────────┘
121
+ ▼
122
+ MEMORY STORE
123
+ ┌─────────────────────┐
124
+ │ SQLite │
125
+ │ FTS5 │
126
+ │ local vectors │
127
+ │ entities/relations │
128
+ │ temporal metadata │
129
+ └──────────┬──────────┘
130
+ │
131
+ CONTEXT ENGINE
132
+ │
133
+ ▼
134
+ AI AGENT
135
+ ```
136
+
137
+ ---
138
+
139
+ # 3. Memory Taxonomy
140
+
141
+ Canonical memory types:
142
+
143
+ ```text
144
+ FACT
145
+ PREFERENCE
146
+ GOAL
147
+ DECISION
148
+ CONSTRAINT
149
+ LESSON
150
+ PROCEDURE
151
+ EPISODE
152
+ RELATION
153
+ PROFILE
154
+ ```
155
+
156
+ ### Semantics
157
+
158
+ | Type | Purpose |
159
+ |---|---|
160
+ | FACT | durable factual information |
161
+ | PREFERENCE | user/project preference |
162
+ | GOAL | desired future outcome |
163
+ | DECISION | chosen approach and rationale |
164
+ | CONSTRAINT | hard requirement or prohibition |
165
+ | LESSON | correction-derived knowledge |
166
+ | PROCEDURE | reusable method/workflow |
167
+ | EPISODE | meaningful historical event |
168
+ | RELATION | entity relationship information |
169
+ | PROFILE | high-value compact user/project summary |
170
+
171
+ Types must be extensible internally, but these ten are the stable v2 vocabulary.
172
+
173
+ ---
174
+
175
+ # 4. Memory Lifecycle
176
+
177
+ Every memory has a lifecycle state:
178
+
179
+ ```text
180
+ NEW → ACTIVE
181
+ ACTIVE → REINFORCED → ACTIVE
182
+ ACTIVE → STALE
183
+ ACTIVE → SUPERSEDED
184
+ STALE → ARCHIVED
185
+ SUPERSEDED → ARCHIVED
186
+ ACTIVE → DELETED
187
+ ARCHIVED → DELETED
188
+ ```
189
+
190
+ ### Rules
191
+
192
+ - `ACTIVE`: eligible for normal retrieval.
193
+ - `STALE`: low priority; eligible when historical context is useful.
194
+ - `SUPERSEDED`: replaced by another memory; normally excluded from current-context retrieval.
195
+ - `ARCHIVED`: retained but excluded from default retrieval.
196
+ - `DELETED`: logically deleted unless hard-delete is explicitly requested.
197
+
198
+ A superseded memory should retain a pointer to the replacement.
199
+
200
+ ---
201
+
202
+ # 5. Temporal Model
203
+
204
+ Each memory may have both record time and validity time:
205
+
206
+ ```text
207
+ created_at
208
+ updated_at
209
+ last_accessed_at
210
+ valid_from
211
+ valid_until
212
+ ```
213
+
214
+ `valid_until = NULL` means currently valid unless lifecycle state says otherwise.
215
+
216
+ Temporal questions must be supported conceptually:
217
+
218
+ - What is true now?
219
+ - What was true at time T?
220
+ - What changed?
221
+ - Which memory superseded this one?
222
+
223
+ Do not physically delete historical truth merely because it is no longer current.
224
+
225
+ ---
226
+
227
+ # 6. Database Schema
228
+
229
+ The following is the logical v2 schema. Migration SQL may implement equivalent SQLite details, but semantics must remain compatible.
230
+
231
+ ## 6.1 `memories`
232
+
233
+ ```sql
234
+ CREATE TABLE memories (
235
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
236
+ type TEXT NOT NULL,
237
+ content TEXT NOT NULL,
238
+ summary TEXT,
239
+ status TEXT NOT NULL DEFAULT 'active',
240
+ source TEXT NOT NULL DEFAULT 'explicit',
241
+ confidence REAL NOT NULL DEFAULT 0.5,
242
+ importance REAL NOT NULL DEFAULT 0.5,
243
+ salience REAL NOT NULL DEFAULT 0.5,
244
+ project_id TEXT,
245
+ session_id TEXT,
246
+ created_at TEXT NOT NULL,
247
+ updated_at TEXT NOT NULL,
248
+ last_accessed_at TEXT,
249
+ access_count INTEGER NOT NULL DEFAULT 0,
250
+ valid_from TEXT,
251
+ valid_until TEXT,
252
+ supersedes_id INTEGER,
253
+ metadata TEXT,
254
+ FOREIGN KEY (supersedes_id) REFERENCES memories(id)
255
+ );
256
+ ```
257
+
258
+ ### Required indexes
259
+
260
+ ```sql
261
+ CREATE INDEX idx_memories_type_status ON memories(type, status);
262
+ CREATE INDEX idx_memories_project_status ON memories(project_id, status);
263
+ CREATE INDEX idx_memories_updated ON memories(updated_at);
264
+ CREATE INDEX idx_memories_validity ON memories(valid_from, valid_until);
265
+ CREATE INDEX idx_memories_supersedes ON memories(supersedes_id);
266
+ ```
267
+
268
+ ## 6.2 `interactions`
269
+
270
+ Retain raw behavior/event storage:
271
+
272
+ ```sql
273
+ CREATE TABLE interactions (
274
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
275
+ ts TEXT NOT NULL,
276
+ session_id TEXT,
277
+ kind TEXT NOT NULL,
278
+ content TEXT NOT NULL,
279
+ meta TEXT
280
+ );
281
+ ```
282
+
283
+ Interactions are not automatically long-term memories.
284
+
285
+ ## 6.3 `entities`
286
+
287
+ ```sql
288
+ CREATE TABLE entities (
289
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
290
+ name TEXT NOT NULL,
291
+ canonical_name TEXT NOT NULL,
292
+ type TEXT,
293
+ metadata TEXT
294
+ );
295
+ CREATE UNIQUE INDEX idx_entities_canonical ON entities(canonical_name);
296
+ ```
297
+
298
+ ## 6.4 `relations`
299
+
300
+ ```sql
301
+ CREATE TABLE relations (
302
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
303
+ source_entity_id INTEGER NOT NULL,
304
+ relation TEXT NOT NULL,
305
+ target_entity_id INTEGER NOT NULL,
306
+ confidence REAL NOT NULL DEFAULT 0.5,
307
+ valid_from TEXT,
308
+ valid_until TEXT,
309
+ source_memory_id INTEGER,
310
+ metadata TEXT,
311
+ FOREIGN KEY (source_entity_id) REFERENCES entities(id),
312
+ FOREIGN KEY (target_entity_id) REFERENCES entities(id),
313
+ FOREIGN KEY (source_memory_id) REFERENCES memories(id)
314
+ );
315
+ ```
316
+
317
+ ## 6.5 `memory_links`
318
+
319
+ ```sql
320
+ CREATE TABLE memory_links (
321
+ source_memory_id INTEGER NOT NULL,
322
+ relation TEXT NOT NULL,
323
+ target_memory_id INTEGER NOT NULL,
324
+ confidence REAL NOT NULL DEFAULT 0.5,
325
+ created_at TEXT NOT NULL,
326
+ PRIMARY KEY (source_memory_id, relation, target_memory_id),
327
+ FOREIGN KEY (source_memory_id) REFERENCES memories(id),
328
+ FOREIGN KEY (target_memory_id) REFERENCES memories(id)
329
+ );
330
+ ```
331
+
332
+ Supported link relations:
333
+
334
+ ```text
335
+ supports
336
+ contradicts
337
+ supersedes
338
+ derived_from
339
+ related_to
340
+ caused_by
341
+ depends_on
342
+ ```
343
+
344
+ ## 6.6 `profile`
345
+
346
+ Retain compact profile sections for backward compatibility and fast injection:
347
+
348
+ ```sql
349
+ CREATE TABLE profile (
350
+ section TEXT PRIMARY KEY,
351
+ content TEXT NOT NULL,
352
+ updated_at TEXT NOT NULL
353
+ );
354
+ ```
355
+
356
+ In v2, profile is a projection/cache of important memories, not the canonical source of truth.
357
+
358
+ ---
359
+
360
+ # 7. Search Indexes
361
+
362
+ FTS5 remains mandatory.
363
+
364
+ Logical indexed fields:
365
+
366
+ ```text
367
+ memory id
368
+ memory type
369
+ content
370
+ summary
371
+ project_id
372
+ ```
373
+
374
+ The implementation may use a maintained FTS5 virtual table or separate indexes, but every mutation of searchable memory must keep indexes synchronized transactionally where possible.
375
+
376
+ Local semantic search remains supported. The implementation must preserve the dependency-light/offline property of v1.
377
+
378
+ ---
379
+
380
+ # 8. Memory Source Model
381
+
382
+ Canonical source values:
383
+
384
+ ```text
385
+ explicit
386
+ corrected
387
+ inferred
388
+ captured
389
+ consolidated
390
+ imported
391
+ system
392
+ ```
393
+
394
+ Recommended source weights for confidence calculation:
395
+
396
+ | Source | Weight |
397
+ |---|---:|
398
+ | explicit | 1.00 |
399
+ | corrected | 0.95 |
400
+ | captured | 0.30 |
401
+ | inferred | 0.50 |
402
+ | consolidated | 0.75 |
403
+ | imported | 0.70 |
404
+ | system | 0.80 |
405
+
406
+ These are defaults, not immutable constants.
407
+
408
+ ---
409
+
410
+ # 9. Confidence, Importance, Salience
411
+
412
+ All three values are normalized to `[0,1]`.
413
+
414
+ ## 9.1 Confidence
415
+
416
+ Confidence reflects how trustworthy the memory is.
417
+
418
+ Recommended conceptual model:
419
+
420
+ ```text
421
+ confidence = f(source_weight,
422
+ confirmation_count,
423
+ consistency,
424
+ conflict_penalty)
425
+ ```
426
+
427
+ Do not blindly increase confidence forever from duplicate saves. Repeated identical events should have diminishing returns.
428
+
429
+ ## 9.2 Importance
430
+
431
+ Importance is durable significance. It should not decay merely because the memory is old.
432
+
433
+ Examples:
434
+
435
+ - hard project constraint: high
436
+ - architectural decision: high
437
+ - temporary debugging detail: low
438
+
439
+ ## 9.3 Salience
440
+
441
+ Salience determines usefulness for a particular retrieval/context operation.
442
+
443
+ Recommended baseline:
444
+
445
+ ```text
446
+ salience =
447
+ 0.30 * semantic_relevance +
448
+ 0.20 * importance +
449
+ 0.15 * confidence +
450
+ 0.15 * recency +
451
+ 0.10 * access_frequency +
452
+ 0.10 * project_relevance
453
+ ```
454
+
455
+ Weights must be configurable and benchmarked.
456
+
457
+ ---
458
+
459
+ # 10. Recency and Decay
460
+
461
+ Use a bounded exponential recency factor:
462
+
463
+ ```text
464
+ recency = exp(-lambda * age_days)
465
+ ```
466
+
467
+ Decay policy must depend on memory type.
468
+
469
+ | Type | Default decay |
470
+ |---|---|
471
+ | CONSTRAINT | very low |
472
+ | DECISION | low |
473
+ | LESSON | low |
474
+ | PREFERENCE | low |
475
+ | FACT | low/medium |
476
+ | GOAL | medium |
477
+ | PROCEDURE | low/medium |
478
+ | EPISODE | medium |
479
+ | RELATION | low/medium |
480
+ | PROFILE | derived |
481
+
482
+ These are policy classes, not fixed numeric constants.
483
+
484
+ ---
485
+
486
+ # 11. Deduplication
487
+
488
+ Every `remember` candidate must pass duplicate detection before insertion.
489
+
490
+ Pipeline:
491
+
492
+ ```text
493
+ normalize
494
+ ↓
495
+ exact match
496
+ ↓
497
+ canonical/key match
498
+ ↓
499
+ FTS similarity
500
+ ↓
501
+ semantic similarity (if available)
502
+ ↓
503
+ DUPLICATE / UPDATE / DISTINCT
504
+ ```
505
+
506
+ Duplicate detection must avoid merging memories that are merely similar but semantically different.
507
+
508
+ ---
509
+
510
+ # 12. Conflict Resolution
511
+
512
+ This is a first-class v2 subsystem.
513
+
514
+ When a new candidate arrives:
515
+
516
+ ```text
517
+ candidate
518
+ ↓
519
+ find related active memories
520
+ ↓
521
+ classify relationship
522
+ ├── duplicate
523
+ ├── update
524
+ ├── contradiction
525
+ └── unrelated
526
+ ```
527
+
528
+ ### Update/supersession
529
+
530
+ For a direct change:
531
+
532
+ ```text
533
+ old memory: status = superseded
534
+ new memory: status = active
535
+ new memory.supersedes_id = old.id
536
+ ```
537
+
538
+ Create a `supersedes` memory link when useful.
539
+
540
+ ### Ambiguous conflict
541
+
542
+ If deterministic rules cannot safely decide, preserve both records and mark the relationship `contradicts`; do not silently destroy information.
543
+
544
+ ---
545
+
546
+ # 13. Hybrid Retrieval
547
+
548
+ `recall` and `get_context` must use more than one retrieval signal.
549
+
550
+ ```text
551
+ QUERY
552
+ │
553
+ ├── FTS5 keyword retrieval
554
+ │
555
+ ├── local semantic retrieval
556
+ │
557
+ ├── metadata/scope filtering
558
+ │
559
+ └── optional graph expansion
560
+ │
561
+ ▼
562
+ Candidate pool
563
+ │
564
+ ▼
565
+ RRF fusion
566
+ │
567
+ ▼
568
+ Scoring/reranking
569
+ │
570
+ ▼
571
+ Conflict/status filtering
572
+ │
573
+ ▼
574
+ Top K
575
+ ```
576
+
577
+ ## 13.1 Reciprocal Rank Fusion
578
+
579
+ Use RRF rather than directly mixing incompatible raw search scores:
580
+
581
+ ```text
582
+ RRF(m) = Σ 1 / (k + rank_i(m))
583
+ ```
584
+
585
+ Then apply memory-specific factors:
586
+
587
+ ```text
588
+ final_score =
589
+ RRF * confidence * importance_factor * recency_factor * scope_factor
590
+ ```
591
+
592
+ The exact formula must be benchmarked.
593
+
594
+ ---
595
+
596
+ # 14. Graph Retrieval
597
+
598
+ Graph is an augmentation, not the sole retrieval mechanism.
599
+
600
+ Default traversal should be shallow and bounded:
601
+
602
+ ```text
603
+ seed entities/memories
604
+ ↓
605
+ 1-hop related entities
606
+ ↓
607
+ related memories
608
+ ```
609
+
610
+ Do not perform unbounded graph traversal during normal `recall`.
611
+
612
+ Graph boost should improve relationship queries without allowing weak graph edges to dominate strong direct evidence.
613
+
614
+ ---
615
+
616
+ # 15. Context Engine
617
+
618
+ Introduce a first-class `get_context` operation.
619
+
620
+ Input concept:
621
+
622
+ ```json
623
+ {
624
+ "query": "current task",
625
+ "project": "optional-project-id",
626
+ "limit": 12,
627
+ "token_budget": 1500,
628
+ "include_history": false
629
+ }
630
+ ```
631
+
632
+ Pipeline:
633
+
634
+ ```text
635
+ query
636
+ ↓
637
+ retrieve candidate memories
638
+ ↓
639
+ filter stale/superseded records
640
+ ↓
641
+ deduplicate
642
+ ↓
643
+ resolve conflicts
644
+ ↓
645
+ rank
646
+ ↓
647
+ fit token budget
648
+ ↓
649
+ assemble structured context
650
+ ```
651
+
652
+ Output should be concise and machine-readable enough for agents to consume.
653
+
654
+ Recommended sections:
655
+
656
+ ```text
657
+ Current Profile
658
+ Relevant Preferences
659
+ Constraints
660
+ Decisions
661
+ Lessons
662
+ Relevant Facts
663
+ Historical Context (only when requested/useful)
664
+ ```
665
+
666
+ Default context should prioritize current project + active user constraints.
667
+
668
+ ---
669
+
670
+ # 16. Persistent vs Archival Memory
671
+
672
+ Two logical tiers:
673
+
674
+ ## Tier A — Persistent/Pinned
675
+
676
+ Small, high-value context that may be injected without retrieval:
677
+
678
+ - identity/profile essentials
679
+ - active goals
680
+ - critical constraints
681
+ - current project decisions
682
+
683
+ Target size: approximately 500–1500 tokens depending on host/context budget.
684
+
685
+ ## Tier B — Archival
686
+
687
+ Searchable persistent memory:
688
+
689
+ - facts
690
+ - episodes
691
+ - lessons
692
+ - procedures
693
+ - historical decisions
694
+ - relations
695
+
696
+ Tier A is a projection/cache; Tier B remains the source of truth.
697
+
698
+ ---
699
+
700
+ # 17. MCP Tool Surface
701
+
702
+ Do not expand to dozens of tools. v2.1.0 ships **16 tools** (the original spec targeted 14; the extra 2 are `consolidate` and `extract_memories`, which extend the v2 engine).
703
+
704
+ ## Shipped (16 tools)
705
+
706
+ ### Core / compatibility (carried from v1)
707
+ 1. `remember` — store a memory using the unified model (type + metadata)
708
+ 2. `recall` — hybrid FTS + semantic search (v1 behavior preserved)
709
+ 3. `forget` — soft delete by default
710
+ 4. `get_profile` — compact profile projection/cache
711
+ 5. `search_history` — search raw interactions
712
+ 6. `get_recent_interactions` — recent raw events
713
+ 7. `memory_stats` — lifecycle/retrieval/storage metrics
714
+ 8. `export_memory` — safe export confined to the allowed directory
715
+ 9. `save_lesson` — compatibility alias/wrapper over `remember(type=LESSON)`
716
+
717
+ ### v2 engine tools
718
+ 10. `get_context` — token-budgeted context assembly (preferred agent-facing retrieval)
719
+ 11. `consolidate` — cluster related memories + optional derived memory
720
+ 12. `link_memory` — typed relationship between two memories in the graph
721
+ 13. `merge_memory` — merge a duplicate into a canonical memory (source superseded, provenance in `metadata.merged_from`)
722
+ 14. `update_memory` — update mutable fields in place, or create a superseding memory when `content` changes
723
+ 15. `import_memory` — import memories from JSON (validates type, dedupes, dry-run by default)
724
+ 16. `extract_memories` — scan recent interactions for memory-intent and propose/create memories (deterministic, no LLM; dry-run by default)
725
+
726
+ All 16 are documented in README.md. The four tools originally marked "deferred" in this spec (`update_memory`, `merge_memory`, `link_memory`, `import_memory`) plus `extract_memories` were implemented in v2.1.0.
727
+
728
+ ---
729
+
730
+ # 18. Tool Contracts
731
+
732
+ ## `remember`
733
+
734
+ ```text
735
+ content: string
736
+ type?: MemoryType
737
+ importance?: 0..1
738
+ confidence?: 0..1
739
+ project_id?: string
740
+ session_id?: string
741
+ source?: SourceType
742
+ valid_from?: ISO timestamp
743
+ valid_until?: ISO timestamp
744
+ metadata?: object
745
+ ```
746
+
747
+ Returns:
748
+
749
+ ```text
750
+ created | reinforced | updated | superseded | duplicate | conflict
751
+ memory id
752
+ short summary
753
+ ```
754
+
755
+ ## `recall`
756
+
757
+ ```text
758
+ query: string
759
+ limit?: 1..50
760
+ project_id?: string
761
+ include_archived?: boolean
762
+ include_history?: boolean
763
+ ```
764
+
765
+ Uses hybrid retrieval.
766
+
767
+ ## `get_context`
768
+
769
+ ```text
770
+ query?: string
771
+ project_id?: string
772
+ token_budget?: integer
773
+ limit?: integer
774
+ include_history?: boolean
775
+ ```
776
+
777
+ This should be the preferred agent-facing retrieval operation for complex tasks.
778
+
779
+ ## `update_memory`
780
+
781
+ Updates mutable fields without silently changing identity/history.
782
+
783
+ Changes to factual content that represent a new truth should create a superseding memory where appropriate. (Implemented in v2.1.0 — see `src/tools/update_memory.ts`.)
784
+
785
+ ## `merge_memory`
786
+
787
+ Combines duplicate/near-duplicate memories while preserving provenance and source IDs. (Implemented in v2.1.0 — see `src/tools/merge_memory.ts`.)
788
+
789
+ ## `link_memory`
790
+
791
+ Creates a typed relationship between memories. (Implemented in v2.1.0 — see `src/tools/link_memory.ts`.)
792
+
793
+ ## `extract_memories`
794
+
795
+ Scans recent captured interactions for memory-intent phrases and proposes memory candidates. Deterministic (no LLM); dry-run by default, `apply=true` creates them (source=`captured`). Implemented in v2.1.0 — see `src/tools/extract_memories.ts`.
796
+
797
+ ## `forget`
798
+
799
+ Default behavior is soft delete. Hard delete must be explicit and documented.
800
+
801
+ ## `consolidate_memory`
802
+
803
+ Groups related memories and creates compact derived memories without automatically deleting source evidence.
804
+
805
+ ## `memory_stats`
806
+
807
+ Expose lifecycle, retrieval, quality, and storage metrics.
808
+
809
+ ## `export_memory` / `import_memory`
810
+
811
+ Must preserve IDs only when safe. Imports must validate schema/version and never overwrite active memory blindly.
812
+
813
+ ---
814
+
815
+ # 19. Auto-Capture v2
816
+
817
+ Retain the existing plugin architecture but make capture a pipeline.
818
+
819
+ ```text
820
+ Host event
821
+ ↓
822
+ Secret/PII filtering
823
+ ↓
824
+ Noise filter
825
+ ↓
826
+ Deduplication
827
+ ↓
828
+ Interaction event storage
829
+ ↓
830
+ Optional extraction
831
+ ↓
832
+ Memory candidate
833
+ ```
834
+
835
+ Capture must never turn every user prompt into long-term memory.
836
+
837
+ ### Existing v1 safeguards to retain
838
+
839
+ - secret filtering
840
+ - event deduplication
841
+ - truncation
842
+ - try/catch around every write
843
+ - shared `MEMORY_DB_PATH`
844
+ - WAL
845
+
846
+ ---
847
+
848
+ # 20. Security Requirements
849
+
850
+ Required:
851
+
852
+ - secret filtering before persistence
853
+ - safe export filenames
854
+ - export confined to allowed export directory
855
+ - metadata sanitization
856
+ - memory treated as untrusted data
857
+ - no memory-generated command execution
858
+ - no memory-generated system/developer instruction override
859
+ - no remote service required by default
860
+
861
+ Sensitive data must not be reintroduced merely because it was previously stored. Existing v1 filtering rules are the minimum baseline, not the maximum security boundary.
862
+
863
+ ---
864
+
865
+ # 21. Graceful Degradation
866
+
867
+ If any subsystem fails:
868
+
869
+ ```text
870
+ Graph unavailable → use FTS/vector
871
+ Vector unavailable → use FTS
872
+ FTS unavailable → use basic SQL filtering
873
+ Profile unavailable → continue without profile
874
+ DB unavailable → return bounded error and allow agent to continue
875
+ ```
876
+
877
+ No optional subsystem should become a single point of failure for the MCP server.
878
+
879
+ ---
880
+
881
+ # 22. Source Tree (as-built in v2.0.0)
882
+
883
+ ```text
884
+ src/
885
+ ├── index.ts # MCP server: registers 11 tools
886
+ ├── db/
887
+ │ ├── index.ts # db singleton (better-sqlite3, WAL) + runMigrations
888
+ │ ├── migrations.ts # ordered MIGRATIONS array (TS modules, idempotent)
889
+ │ └── repositories/
890
+ │ └── memories.ts # CRUD + searchMemories (delegates to hybrid retrieval)
891
+ ├── memory/
892
+ │ ├── types.ts # MemoryType, SourceType, LifecycleState, Scope, MemoryRecord
893
+ │ ├── decay.ts # recencyFactor + per-type DECAY_LAMBDA policy classes
894
+ │ ├── source-weights.ts # SOURCE_WEIGHTS
895
+ │ ├── scorer.ts # computeSalience / computeConfidence
896
+ │ ├── deduplicator.ts # normalize / exact / similar / deduplicate
897
+ │ └── conflict-resolver.ts # isContradiction / classifyRelationship / resolveConflict
898
+ ├── retrieval/
899
+ │ ├── fts.ts # FTS5 search
900
+ │ ├── vector.ts # cosine over embeddings
901
+ │ ├── fusion.ts # rrfFuse (k=60)
902
+ │ └── scorer.ts # finalScore (RRF × confidence × importance × recency × scope)
903
+ ├── core/
904
+ │ ├── lifecycle-engine.ts # transitions, reinforce, supersede, archive, softDelete
905
+ │ ├── temporal-engine.ts # validity intervals, point-in-time, supersession chains
906
+ │ ├── retrieval-engine.ts # retrieve(): FTS+vector → RRF → score → filter → topK
907
+ │ ├── graph-engine.ts # entities/relations, linkMemories, bounded traverse
908
+ │ ├── context-engine.ts # getContext(): retrieve → graph expand → temporal filter → budget
909
+ │ └── consolidation-engine.ts # clusterMemories, createDerivedMemory, getProvenance
910
+ ├── tools/
911
+ │ ├── context.ts # get_context tool
912
+ │ └── consolidate.ts # consolidate tool
913
+ ├── lib/
914
+ │ └── embed.ts # hashing-trick embed + DataView serialize/deserialize (fixed in v2)
915
+ └── plugin/
916
+ └── learning-capture.ts # Bun auto-capture plugin (OpenCode)
917
+ scripts/
918
+ └── claude-capture.mjs # Claude Code hook capture
919
+ test/
920
+ └── *.test.mjs # 20 suites (capture, distill, lifecycle, temporal, conflict,
921
+ # retrieval, graph, context, consolidation, benchmark, security,
922
+ # tools_v21, smoke, e2e_transport, retrieval_benchmark, recall_regression, scope, profile, entity_extraction, conflict_benchmark)
923
+ ```
924
+
925
+ Compatibility wrappers keep the old `remember`/`recall`/etc. tool names; v2 internals live under `core/`, `memory/`, `retrieval/`.
926
+
927
+ ---
928
+
929
+ # 23. Migration Strategy v1 → v2
930
+
931
+ Migration must be non-destructive.
932
+
933
+ ## Phase M0 — Backup
934
+
935
+ Before any schema migration:
936
+
937
+ 1. Verify DB exists.
938
+ 2. Create timestamped backup.
939
+ 3. Verify SQLite integrity.
940
+ 4. Record current schema version.
941
+
942
+ ## Phase M1 — Introduce migration metadata
943
+
944
+ Create:
945
+
946
+ ```sql
947
+ CREATE TABLE schema_meta (
948
+ key TEXT PRIMARY KEY,
949
+ value TEXT NOT NULL
950
+ );
951
+ ```
952
+
953
+ Store `schema_version`.
954
+
955
+ ## Phase M2 — Preserve old tables
956
+
957
+ Do not immediately delete:
958
+
959
+ ```text
960
+ preferences
961
+ lessons
962
+ interactions
963
+ profile
964
+ ```
965
+
966
+ ## Phase M3 — Convert
967
+
968
+ Map:
969
+
970
+ ```text
971
+ preferences → memories(type=PREFERENCE)
972
+ lessons → memories(type=LESSON)
973
+ profile → profile projection/cache
974
+ interactions → interactions unchanged
975
+ ```
976
+
977
+ Preserve original IDs in metadata when IDs cannot be retained directly.
978
+
979
+ ## Phase M4 — Rebuild indexes
980
+
981
+ Recreate FTS and semantic indexes from canonical v2 memory records.
982
+
983
+ ## Phase M5 — Validate
984
+
985
+ Checks:
986
+
987
+ - row counts
988
+ - content hashes/sample comparisons
989
+ - FTS availability
990
+ - memory type mapping
991
+ - profile availability
992
+ - export availability
993
+
994
+ Only after validation may v2 consider old tables deprecated.
995
+
996
+ ---
997
+
998
+ # 24. Migration Files (as-built)
999
+
1000
+ Migrations are **TypeScript modules** in `src/db/migrations.ts`, not `.sql` files. Each entry is an idempotent `up(db)` (`CREATE TABLE IF NOT EXISTS`) tracked in `schema_meta`. This avoids `.sql` file-copy issues under `tsc` while keeping deterministic order. The logical schema in §6 is the contract; the TS implementation realizes it.
1001
+
1002
+ Ordered migrations applied in v2.0.0:
1003
+
1004
+ 1. `schema_meta` table
1005
+ 2. `memories` + indexes
1006
+ 3. `entities` / `relations`
1007
+ 4. `memory_links`
1008
+ 5. v1 backfill (`preferences → PREFERENCE`, `lessons → LESSON`, sync FTS + embeddings; guarded by `v1_backfilled` flag, runs once)
1009
+
1010
+ The spec allowed implementation differences ("Exact SQL can differ if implementation constraints require it"); the TS approach is the chosen realization.
1011
+
1012
+ ---
1013
+
1014
+ # 25. Testing Strategy
1015
+
1016
+ Tests must be layered.
1017
+
1018
+ ## Unit tests
1019
+
1020
+ - classification
1021
+ - secret filtering
1022
+ - normalization
1023
+ - duplicate detection
1024
+ - conflict classification
1025
+ - confidence
1026
+ - decay
1027
+ - scoring
1028
+ - RRF
1029
+ - token budgeting
1030
+ - filename sanitization
1031
+
1032
+ ## Integration tests
1033
+
1034
+ - SQLite migration
1035
+ - FTS sync
1036
+ - semantic retrieval
1037
+ - graph relations
1038
+ - lifecycle transitions
1039
+ - import/export
1040
+
1041
+ ## MCP E2E
1042
+
1043
+ Run real JSON-RPC against the built server.
1044
+
1045
+ ## Plugin tests
1046
+
1047
+ - prompt capture
1048
+ - tool event capture
1049
+ - dedupe
1050
+ - secret filter
1051
+ - graceful DB failure
1052
+ - profile/context injection
1053
+
1054
+ ---
1055
+
1056
+ # 26. Retrieval Benchmark
1057
+
1058
+ Create:
1059
+
1060
+ ```text
1061
+ benchmark/
1062
+ ├── datasets/
1063
+ ├── retrieval/
1064
+ ├── conflict/
1065
+ ├── temporal/
1066
+ ├── lifecycle/
1067
+ └── performance/
1068
+ ```
1069
+
1070
+ Baseline dataset should contain:
1071
+
1072
+ - at least 500 memories
1073
+ - at least 100 distractors
1074
+ - at least 100 duplicates
1075
+ - at least 100 contradictions/updates
1076
+ - at least 100 temporal changes
1077
+
1078
+ Measure:
1079
+
1080
+ ```text
1081
+ Recall@1
1082
+ Recall@5
1083
+ Recall@10
1084
+ Precision@5
1085
+ MRR
1086
+ NDCG
1087
+ ```
1088
+
1089
+ Initial engineering targets:
1090
+
1091
+ ```text
1092
+ Recall@5 >= 0.90
1093
+ Precision@5 >= 0.85
1094
+ MRR >= 0.85
1095
+ ```
1096
+
1097
+ Targets are project acceptance goals, not claims about competitor performance.
1098
+
1099
+ ---
1100
+
1101
+ # 27. Conflict Benchmark
1102
+
1103
+ Target:
1104
+
1105
+ ```text
1106
+ >= 95% correct classification/resolution
1107
+ ```
1108
+
1109
+ Test cases must include:
1110
+
1111
+ - exact duplicate
1112
+ - paraphrase duplicate
1113
+ - preference update
1114
+ - direct contradiction
1115
+ - temporary exception
1116
+ - two valid but different scoped memories
1117
+ - ambiguous conflict
1118
+
1119
+ Ambiguous cases must prefer preservation over destructive guessing.
1120
+
1121
+ ---
1122
+
1123
+ # 28. Temporal Benchmark
1124
+
1125
+ Queries must test:
1126
+
1127
+ ```text
1128
+ current truth
1129
+ historical truth
1130
+ change detection
1131
+ supersession chain
1132
+ ```
1133
+
1134
+ No stale record may override an active current record in default current-context retrieval.
1135
+
1136
+ ---
1137
+
1138
+ # 29. Performance Targets
1139
+
1140
+ On a normal local development machine, initial targets are:
1141
+
1142
+ | Operation | Target |
1143
+ |---|---:|
1144
+ | remember | <20 ms typical |
1145
+ | recall | <50 ms typical |
1146
+ | get_context | <100 ms typical |
1147
+ | get_profile | <20 ms typical |
1148
+ | search_history | <30 ms typical |
1149
+
1150
+ These are engineering targets, not guaranteed SLAs.
1151
+
1152
+ Benchmark both cold-cache and warm-cache behavior where practical.
1153
+
1154
+ ---
1155
+
1156
+ # 30. Token Efficiency
1157
+
1158
+ Every retrieval operation must have a bounded output.
1159
+
1160
+ `get_context` must support an explicit token/character budget.
1161
+
1162
+ Do not return all matching memories merely because they match.
1163
+
1164
+ Target behavior:
1165
+
1166
+ ```text
1167
+ candidate pool: 50
1168
+ ↓
1169
+ rank: 20
1170
+ ↓
1171
+ filter: 12
1172
+ ↓
1173
+ budget: 5–15 useful memories
1174
+ ↓
1175
+ compact context
1176
+ ```
1177
+
1178
+ ---
1179
+
1180
+ # 31. Consolidation
1181
+
1182
+ Consolidation creates higher-level semantic memories from clusters of related evidence.
1183
+
1184
+ Example:
1185
+
1186
+ ```text
1187
+ User prefers TypeScript.
1188
+ User chooses TypeScript for projects.
1189
+ User corrected code examples from Python to TypeScript.
1190
+ ```
1191
+
1192
+ Can produce:
1193
+
1194
+ ```text
1195
+ User prefers TypeScript for software projects.
1196
+ ```
1197
+
1198
+ The derived memory must retain provenance:
1199
+
1200
+ ```text
1201
+ derived_from → source memories
1202
+ ```
1203
+
1204
+ Source evidence must not be deleted automatically.
1205
+
1206
+ ---
1207
+
1208
+ # 32. Decision Memory
1209
+
1210
+ `DECISION` should support optional rationale and alternatives in metadata.
1211
+
1212
+ Example:
1213
+
1214
+ ```json
1215
+ {
1216
+ "type": "DECISION",
1217
+ "content": "Use SQLite for local persistence",
1218
+ "metadata": {
1219
+ "reason": [
1220
+ "local-first",
1221
+ "simple deployment",
1222
+ "sufficient performance"
1223
+ ],
1224
+ "alternatives": ["PostgreSQL", "Neo4j"]
1225
+ }
1226
+ }
1227
+ ```
1228
+
1229
+ This prevents agents from repeatedly reopening already-settled architecture decisions.
1230
+
1231
+ ---
1232
+
1233
+ # 33. Scope Resolution
1234
+
1235
+ Supported scope hierarchy:
1236
+
1237
+ ```text
1238
+ GLOBAL
1239
+ ↓
1240
+ USER
1241
+ ↓
1242
+ PROJECT
1243
+ ↓
1244
+ SESSION
1245
+ ```
1246
+
1247
+ For current project queries, prefer:
1248
+
1249
+ ```text
1250
+ PROJECT > USER > GLOBAL > ARCHIVED
1251
+ ```
1252
+
1253
+ Session-specific temporary information should not silently become global memory.
1254
+
1255
+ ---
1256
+
1257
+ # 34. Compatibility Requirements
1258
+
1259
+ v2 must provide a migration/compatibility period where old workflows continue to work.
1260
+
1261
+ Minimum compatibility:
1262
+
1263
+ - existing `remember` usage
1264
+ - existing `recall` usage
1265
+ - existing `get_profile`
1266
+ - existing `save_lesson`
1267
+ - existing `search_history`
1268
+ - existing `forget`
1269
+ - existing `memory_stats`
1270
+ - existing `get_recent_interactions`
1271
+ - existing `export_memory`
1272
+ - existing OpenCode plugin DB path behavior
1273
+
1274
+ Where behavior changes, document it explicitly in `MIGRATION_v2.md`.
1275
+
1276
+ ---
1277
+
1278
+ # 35. Implementation Phases
1279
+
1280
+ ## Phase 0 — Freeze v1
1281
+
1282
+ - tag v1.2.2
1283
+ - backup database
1284
+ - record baseline benchmarks
1285
+ - do not modify production behavior
1286
+
1287
+ ## Phase 1 — Core abstraction
1288
+
1289
+ - repository layer
1290
+ - unified memory type
1291
+ - schema metadata
1292
+ - migration engine
1293
+ - v1 compatibility wrappers
1294
+
1295
+ ## Phase 2 — Lifecycle
1296
+
1297
+ - status
1298
+ - confidence
1299
+ - importance
1300
+ - salience
1301
+ - access tracking
1302
+ - decay
1303
+ - archive
1304
+ - supersession
1305
+
1306
+ ## Phase 3 — Temporal
1307
+
1308
+ - validity intervals
1309
+ - historical retrieval
1310
+ - change/supersession chains
1311
+
1312
+ ## Phase 4 — Conflict
1313
+
1314
+ - normalization
1315
+ - duplicate detection
1316
+ - contradiction detection
1317
+ - update/supersession
1318
+ - merge
1319
+
1320
+ ## Phase 5 — Retrieval
1321
+
1322
+ - FTS adapter
1323
+ - vector adapter
1324
+ - RRF
1325
+ - scoring
1326
+ - reranking
1327
+
1328
+ ## Phase 6 — Graph
1329
+
1330
+ - entities
1331
+ - relations
1332
+ - memory links
1333
+ - bounded traversal
1334
+ - graph boost
1335
+
1336
+ ## Phase 7 — Context
1337
+
1338
+ - `get_context`
1339
+ - token budgeting
1340
+ - context assembler
1341
+ - persistent/archival projection
1342
+
1343
+ ## Phase 8 — Consolidation
1344
+
1345
+ - clustering
1346
+ - derived memories
1347
+ - provenance
1348
+
1349
+ ## Phase 9 — Benchmark/security
1350
+
1351
+ - benchmark suite
1352
+ - migration tests
1353
+ - security tests
1354
+ - performance tests
1355
+
1356
+ ## Phase 10 — v2 release
1357
+
1358
+ - v2 documentation
1359
+ - migration guide
1360
+ - changelog
1361
+ - package version 2.0.0
1362
+
1363
+ ---
1364
+
1365
+ # 36. AI Coding Agent Rules
1366
+
1367
+ This section is normative.
1368
+
1369
+ ## MUST
1370
+
1371
+ - Read this document before modifying architecture.
1372
+ - Inspect current source before changing behavior.
1373
+ - Preserve v1 functionality unless explicitly superseded.
1374
+ - Add migrations instead of destructive schema replacement.
1375
+ - Add tests with every new subsystem.
1376
+ - Keep MCP stdio stdout clean; diagnostics belong on stderr.
1377
+ - Keep outputs bounded.
1378
+ - Preserve graceful failure.
1379
+ - Keep local/offline operation functional.
1380
+ - Treat stored memory as untrusted data.
1381
+ - Prefer deterministic logic over unnecessary LLM calls.
1382
+
1383
+ ## MUST NOT
1384
+
1385
+ - Rewrite the entire project without migration.
1386
+ - Delete the v1 database schema before successful migration.
1387
+ - Introduce a mandatory cloud dependency.
1388
+ - Introduce a mandatory external embedding API.
1389
+ - add dozens of MCP tools for internal implementation details.
1390
+ - Let stale/superseded memories silently override current truth.
1391
+ - Destroy contradictory evidence merely because it is inconvenient.
1392
+ - Put secrets into test fixtures, logs, or examples.
1393
+ - Make plugin failure crash the host.
1394
+ - Change public behavior without tests and migration notes.
1395
+
1396
+ ## SHOULD
1397
+
1398
+ - Keep modules small and independently testable.
1399
+ - Use interfaces/adapters for vector and graph implementations.
1400
+ - Prefer SQLite-native capabilities before adding dependencies.
1401
+ - Measure retrieval quality before tuning scoring constants.
1402
+
1403
+ ---
1404
+
1405
+ # 37. Acceptance Criteria for v2.0.0
1406
+
1407
+ The release is acceptable only when all are true:
1408
+
1409
+ ### Data
1410
+
1411
+ - [x] v1 DB can be backed up and migrated.
1412
+ - [x] preferences map correctly to PREFERENCE memories.
1413
+ - [x] lessons map correctly to LESSON memories.
1414
+ - [x] interactions remain queryable.
1415
+ - [x] profile remains available as a projection.
1416
+
1417
+ ### Memory
1418
+
1419
+ - [x] unified memory model works.
1420
+ - [x] lifecycle states work.
1421
+ - [x] temporal validity works.
1422
+ - [x] supersession works.
1423
+ - [x] duplicate detection works.
1424
+ - [x] conflict handling preserves ambiguous evidence.
1425
+
1426
+ ### Retrieval
1427
+
1428
+ - [x] FTS retrieval works.
1429
+ - [x] local semantic retrieval works.
1430
+ - [x] RRF fusion works.
1431
+ - [x] metadata/project scope works.
1432
+ - [x] stale/superseded filtering works.
1433
+ - [x] bounded output works.
1434
+
1435
+ ### Context
1436
+
1437
+ - [x] `get_context` works.
1438
+ - [x] token/character budget is enforced.
1439
+ - [x] current project context is prioritized.
1440
+ - [x] critical constraints are prioritized.
1441
+
1442
+ ### Graph
1443
+
1444
+ - [x] entity/relation persistence works.
1445
+ - [x] memory links work.
1446
+ - [x] graph traversal is bounded.
1447
+ - [x] graph failure does not break retrieval.
1448
+
1449
+ ### Security
1450
+
1451
+ - [x] secrets are filtered before storage.
1452
+ - [x] exports are confined to the allowed directory.
1453
+ - [x] memory cannot become executable instructions.
1454
+ - [x] import validates schema/version.
1455
+
1456
+ ### Reliability
1457
+
1458
+ - [x] DB errors do not crash the MCP server.
1459
+ - [x] plugin errors do not crash the host.
1460
+ - [x] stdout remains protocol-safe.
1461
+
1462
+ ### Quality
1463
+
1464
+ - [x] retrieval benchmark passes project targets.
1465
+ - [x] conflict benchmark meets >=95% target.
1466
+ - [x] migration tests pass.
1467
+ - [x] performance targets are measured and documented.
1468
+
1469
+ ---
1470
+
1471
+ # 38. Recommended v2 Positioning
1472
+
1473
+ Do not market v2 as "another Mem0".
1474
+
1475
+ Position it as:
1476
+
1477
+ > **A local-first, privacy-focused, temporal memory MCP for AI coding agents, with hybrid retrieval, conflict-aware memory, and token-efficient context assembly.**
1478
+
1479
+ The differentiators are:
1480
+
1481
+ 1. Local-first.
1482
+ 2. SQLite simplicity.
1483
+ 3. No mandatory API/cloud.
1484
+ 4. Thai/English friendliness.
1485
+ 5. Cross-harness portability.
1486
+ 6. Temporal + conflict-aware memory.
1487
+ 7. Small MCP interface.
1488
+ 8. Agent-oriented context assembly.
1489
+
1490
+ ---
1491
+
1492
+ # 39. Final Architecture Contract
1493
+
1494
+ The canonical v2 flow is:
1495
+
1496
+ ```text
1497
+ ┌──────────────────┐
1498
+ │ AI AGENT │
1499
+ └────────┬─────────┘
1500
+ │ MCP
1501
+ ┌────────▼─────────┐
1502
+ │ MEMORY API │
1503
+ └────────┬─────────┘
1504
+ │
1505
+ ┌──────────────────┼──────────────────┐
1506
+ │ │ │
1507
+ ▼ ▼ ▼
1508
+ CAPTURE RETRIEVAL LIFECYCLE
1509
+ │ │ │
1510
+ │ ┌─────────┼─────────┐ │
1511
+ │ │ │ │ │
1512
+ │ FTS VECTOR GRAPH │
1513
+ │ │ │ │ │
1514
+ │ └─────────┼─────────┘ │
1515
+ │ │ │
1516
+ └──────────────────┼──────────────────┘
1517
+ ▼
1518
+ ┌────────────────┐
1519
+ │ MEMORY STORE │
1520
+ │ SQLite + FTS5 │
1521
+ │ vectors + graph│
1522
+ │ temporal state │
1523
+ └───────┬────────┘
1524
+ │
1525
+ ┌───────▼────────┐
1526
+ │ CONTEXT ENGINE │
1527
+ │ rank/filter │
1528
+ │ dedupe/compress│
1529
+ │ token budget │
1530
+ └───────┬────────┘
1531
+ │
1532
+ ▼
1533
+ AI AGENT
1534
+ ```
1535
+
1536
+ **This document is the implementation source of truth for th-memory-mcp v2 unless a later version explicitly supersedes it.**
1537
+
1538
+ ---
1539
+
1540
+ # 40. Implementation Status (as-built, v2.1.0)
1541
+
1542
+ This section folds in the former `design.md` build log. All v2 engine phases are complete and tested. v2.1.0 adds the five previously-deferred tools.
1543
+
1544
+ ## What shipped (v2.0.0 + v2.1.0)
1545
+ - **16 MCP tools** (see §17). `save_lesson` retained as a compatibility wrapper. The four tools originally marked deferred (`update_memory`, `merge_memory`, `link_memory`, `import_memory`) plus `extract_memories` landed in v2.1.0.
1546
+ - **Non-destructive migration** from v1.2.2: v1 tables preserved; `memories`/`entities`/`relations`/`memory_links`/`schema_meta` added; one-time backfill of preferences + lessons.
1547
+ - **Hybrid retrieval**: FTS5 + local semantic (hashing-trick vectors) fused via RRF, then scored by confidence × importance × recency × scope.
1548
+ - **Temporal model**: validity intervals, point-in-time retrieval, supersession chains, change detection.
1549
+ - **Conflict/dedup**: normalize → exact → similar → classify (duplicate/update/contradiction/unrelated); ambiguous conflicts preserved, never silently destroyed.
1550
+ - **Graph**: entities/relations + bounded memory-link traversal (maxDepth 1–5); `link_memory` exposes it publicly.
1551
+ - **Context engine**: `get_context` with token budgeting, temporal filtering, optional graph expansion.
1552
+ - **Consolidation**: clustering + derived memories with `derived_from` provenance.
1553
+ - **Auto-extraction**: `extract_memories` scans recent interactions for memory-intent (deterministic, no LLM) and proposes/creates memories.
1554
+ - **Security**: secret filtering, parameterized SQL, FTS-injection quoting, memory treated as untrusted data, bounded output.
1555
+
1556
+ ## Phase checklist
1557
+ - [x] Phase 1 — Core abstraction (types, migrations, repository, index wiring)
1558
+ - [x] Phase 2 — Lifecycle engine (decay, source-weights, scorer, transitions)
1559
+ - [x] Phase 3 — Temporal model
1560
+ - [x] Phase 4 — Conflict & dedup (+ fixed v1 `embed.ts` DataView bug)
1561
+ - [x] Phase 5 — Hybrid retrieval (FTS/vector/fusion/scorer/engine)
1562
+ - [x] Phase 6 — Graph engine
1563
+ - [x] Phase 7 — Context engine (`get_context`)
1564
+ - [x] Phase 8 — Consolidation (`consolidate`)
1565
+ - [x] Phase 9 — Benchmark + security suites (20 test suites total)
1566
+ - [x] Phase 10 — Docs + v2.0.0 release (npm, GitHub Release, Official MCP Registry, Glama)
1567
+ - [x] v2.1.0 — `link_memory` / `merge_memory` / `update_memory` / `import_memory` / `extract_memories` (16 tools, 20 suites)
1568
+
1569
+ ## Test status
1570
+ All 20 test suites pass (capture, distill, lifecycle 17, temporal 7, conflict 14, retrieval 7, graph 7, context 7, consolidation 5, benchmark 2, security 5, tools_v21 21, smoke 16-tool, e2e_transport, retrieval_benchmark, recall_regression, scope, profile, entity_extraction, conflict_benchmark).
1571
+
1572
+ ## Resolved gaps vs original spec (all addressed — no regressions)
1573
+ - ✅ DONE — Retrieval quality benchmark (§26): measured in-repo (`test/retrieval_benchmark.test.mjs`), meets targets (Recall@5=1.00, Precision@5=0.92, MRR=1.00 on a 700-memory baseline).
1574
+ - ✅ DONE — Conflict-resolution quality benchmark (§27, ≥95% correct classification): measured in-repo (`test/conflict_benchmark.test.mjs`), 100% accuracy on a 14-case labeled set covering all 7 required categories (exact/paraphrase duplicate, preference update, direct contradiction, temporary exception, two valid scoped memories, ambiguous conflict). Ambiguous opposite-preference pairs preserved as `contradiction` (linked), never silently superseded.
1575
+ - ✅ DONE — Perf targets (§29): measured in CI via the perf benchmark suite (`test/benchmark.test.mjs`); all per-op latencies meet targets.
1576
+ - ✅ DONE — USER scope (migration 007: `users` table + `memories.user_id`). Clients pass `userId` (external identity) to `import_memory`, `extract_memories`, and `get_context`; `createMemory` derives `USER` scope and auto-creates the user row. `scopeFactorFor` boosts USER-scoped memories (1.0) for the matching user and penalizes foreign ones (0.3); SESSION/PROJECT/GLOBAL isolation unchanged. Preferences and lessons remain global (no user column).
1577
+ - Trust model: `userId` is client-declared (no authentication). This is acceptable for the intended single-user local deployment where the SQLite DB file is private to its owner. Multi-user isolation, if ever required, should be solved at the DB-file level (one DB per user/session), not by adding auth to the engine.
1578
+ - ✅ DONE — Auto entity extraction in consolidation (`src/core/entity-extractor.ts`, wired into `consolidate`).
1579
+
1580
+ ## Future-feature backlog (resolved)
1581
+ All previously-deferred future features are implemented. AI-assisted extraction was dropped by owner decision and is not developed.
1582
+ - [x] E2E MCP transport test — `test/e2e_transport.test.mjs`
1583
+ - [x] Retrieval quality benchmark (§26) — `test/retrieval_benchmark.test.mjs`
1584
+ - [x] Perf benchmark (§29) in CI — `test/benchmark.test.mjs` + `.github/workflows/ci.yml`
1585
+ - [x] CI pipeline — `.github/workflows/ci.yml` (ubuntu-latest, node 20, `npm ci`, `npm test`)
1586
+ - [x] Scope hierarchy USER/SESSION/PROJECT/GLOBAL — migrations 006 + 007
1587
+ - [x] Profile auto-projection — `src/tools/profile.ts`
1588
+ - [x] Auto entity extraction in consolidation — `src/core/entity-extractor.ts`
1589
+ - [x] Conflict-resolution quality benchmark (§27) — `test/conflict_benchmark.test.mjs`
1590
+
1591
+ ## Release
1592
+ - v2.0.0: released — npm `th-memory-mcp@2.0.0` (latest), GitHub Release `v2.0.0`, Official MCP Registry `io.github.worakorn-prince/th-memory-mcp@2.0.0`, Glama listed.
1593
+ - v2.1.0: implemented and tested locally; publish skipped (superseded by v2.2.0).
1594
+ - v2.2.0: tag + GitHub Release created by the build agent. **npm / Official MCP Registry / Glama publish pending** — requires the owner to re-authenticate (`npm login` / `mcp-publisher` GitHub OAuth) because the publish token expired.