claude_memory 0.1.0 → 0.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.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/.claude/.mind.mv2.aLCUZd +0 -0
  3. data/.claude/memory.sqlite3 +0 -0
  4. data/.claude/rules/claude_memory.generated.md +7 -1
  5. data/.claude/settings.json +0 -4
  6. data/.claude/settings.local.json +4 -1
  7. data/.claude-plugin/plugin.json +1 -1
  8. data/.claude.json +11 -0
  9. data/.ruby-version +1 -0
  10. data/CHANGELOG.md +62 -11
  11. data/CLAUDE.md +87 -24
  12. data/README.md +76 -159
  13. data/docs/EXAMPLES.md +436 -0
  14. data/docs/RELEASE_NOTES_v0.2.0.md +179 -0
  15. data/docs/RUBY_COMMUNITY_POST_v0.2.0.md +582 -0
  16. data/docs/SOCIAL_MEDIA_v0.2.0.md +420 -0
  17. data/docs/architecture.md +360 -0
  18. data/docs/expert_review.md +1718 -0
  19. data/docs/feature_adoption_plan.md +1241 -0
  20. data/docs/feature_adoption_plan_revised.md +2374 -0
  21. data/docs/improvements.md +1325 -0
  22. data/docs/quality_review.md +1544 -0
  23. data/docs/review_summary.md +480 -0
  24. data/lefthook.yml +10 -0
  25. data/lib/claude_memory/cli.rb +16 -844
  26. data/lib/claude_memory/commands/base_command.rb +95 -0
  27. data/lib/claude_memory/commands/changes_command.rb +39 -0
  28. data/lib/claude_memory/commands/conflicts_command.rb +37 -0
  29. data/lib/claude_memory/commands/db_init_command.rb +40 -0
  30. data/lib/claude_memory/commands/doctor_command.rb +147 -0
  31. data/lib/claude_memory/commands/explain_command.rb +65 -0
  32. data/lib/claude_memory/commands/help_command.rb +37 -0
  33. data/lib/claude_memory/commands/hook_command.rb +106 -0
  34. data/lib/claude_memory/commands/ingest_command.rb +47 -0
  35. data/lib/claude_memory/commands/init_command.rb +218 -0
  36. data/lib/claude_memory/commands/promote_command.rb +30 -0
  37. data/lib/claude_memory/commands/publish_command.rb +36 -0
  38. data/lib/claude_memory/commands/recall_command.rb +61 -0
  39. data/lib/claude_memory/commands/registry.rb +55 -0
  40. data/lib/claude_memory/commands/search_command.rb +43 -0
  41. data/lib/claude_memory/commands/serve_mcp_command.rb +16 -0
  42. data/lib/claude_memory/commands/sweep_command.rb +36 -0
  43. data/lib/claude_memory/commands/version_command.rb +13 -0
  44. data/lib/claude_memory/configuration.rb +38 -0
  45. data/lib/claude_memory/core/fact_id.rb +41 -0
  46. data/lib/claude_memory/core/null_explanation.rb +47 -0
  47. data/lib/claude_memory/core/null_fact.rb +30 -0
  48. data/lib/claude_memory/core/result.rb +143 -0
  49. data/lib/claude_memory/core/session_id.rb +37 -0
  50. data/lib/claude_memory/core/token_estimator.rb +33 -0
  51. data/lib/claude_memory/core/transcript_path.rb +37 -0
  52. data/lib/claude_memory/domain/conflict.rb +51 -0
  53. data/lib/claude_memory/domain/entity.rb +51 -0
  54. data/lib/claude_memory/domain/fact.rb +70 -0
  55. data/lib/claude_memory/domain/provenance.rb +48 -0
  56. data/lib/claude_memory/hook/exit_codes.rb +18 -0
  57. data/lib/claude_memory/hook/handler.rb +7 -2
  58. data/lib/claude_memory/index/index_query.rb +89 -0
  59. data/lib/claude_memory/index/index_query_logic.rb +41 -0
  60. data/lib/claude_memory/index/query_options.rb +67 -0
  61. data/lib/claude_memory/infrastructure/file_system.rb +29 -0
  62. data/lib/claude_memory/infrastructure/in_memory_file_system.rb +32 -0
  63. data/lib/claude_memory/ingest/content_sanitizer.rb +42 -0
  64. data/lib/claude_memory/ingest/ingester.rb +3 -0
  65. data/lib/claude_memory/ingest/privacy_tag.rb +48 -0
  66. data/lib/claude_memory/mcp/tools.rb +174 -1
  67. data/lib/claude_memory/publish.rb +29 -20
  68. data/lib/claude_memory/recall.rb +164 -16
  69. data/lib/claude_memory/resolve/resolver.rb +41 -37
  70. data/lib/claude_memory/shortcuts.rb +56 -0
  71. data/lib/claude_memory/store/store_manager.rb +35 -32
  72. data/lib/claude_memory/templates/hooks.example.json +0 -4
  73. data/lib/claude_memory/version.rb +1 -1
  74. data/lib/claude_memory.rb +59 -21
  75. metadata +55 -1
@@ -0,0 +1,1325 @@
1
+ # Improvements to Consider (Based on claude-mem Analysis)
2
+
3
+ *Generated: 2026-01-21*
4
+ *Source: Comparative analysis of [thedotmack/claude-mem](https://github.com/thedotmack/claude-mem)*
5
+
6
+ This document identifies design patterns, features, and architectural decisions from claude-mem that could improve claude_memory. Each section includes rationale, implementation considerations, and priority.
7
+
8
+ ---
9
+
10
+ ## Executive Summary
11
+
12
+ Claude-mem (TypeScript/Node.js, v9.0.5) is a production-grade memory compression system with 6+ months of real-world usage. Key strengths:
13
+
14
+ - **Progressive Disclosure**: Token-efficient 3-layer retrieval workflow
15
+ - **ROI Metrics**: Tracks token costs and discovery efficiency
16
+ - **Slim Architecture**: Clean separation via service layer pattern
17
+ - **Dual Integration**: Plugin + MCP server for flexibility
18
+ - **Privacy-First**: User-controlled content exclusion via tags
19
+ - **Fail-Fast Philosophy**: Explicit error handling and exit codes
20
+
21
+ **Our Advantages**:
22
+ - Ruby ecosystem (simpler dependencies)
23
+ - Dual-database architecture (global + project scope)
24
+ - Fact-based knowledge graph (vs observation blobs)
25
+ - Truth maintenance system (conflict resolution)
26
+ - Predicate policies (single vs multi-value)
27
+
28
+ ---
29
+
30
+ ## 1. Progressive Disclosure Pattern
31
+
32
+ ### What claude-mem Does
33
+
34
+ **3-Layer Workflow** enforced at the tool level:
35
+
36
+ ```
37
+ Layer 1: search → Get compact index with IDs (~50-100 tokens/result)
38
+ Layer 2: timeline → Get chronological context around IDs
39
+ Layer 3: get_observations → Fetch full details (~500-1,000 tokens/result)
40
+ ```
41
+
42
+ **Token savings**: ~10x reduction by filtering before fetching.
43
+
44
+ **MCP Tools**:
45
+ - `search` - Returns index format (titles, IDs, token counts)
46
+ - `timeline` - Returns context around specific observation
47
+ - `get_observations` - Returns full details only for filtered IDs
48
+ - `__IMPORTANT` - Workflow documentation (always visible)
49
+
50
+ **File**: `docs/public/progressive-disclosure.mdx` (673 lines of philosophy)
51
+
52
+ ### What We Should Do
53
+
54
+ **Priority**: HIGH
55
+
56
+ **Implementation**:
57
+
58
+ 1. **Add token count field to facts table**:
59
+ ```ruby
60
+ alter table :facts do
61
+ add_column :token_count, Integer
62
+ end
63
+ ```
64
+
65
+ 2. **Create index format in Recall**:
66
+ ```ruby
67
+ # lib/claude_memory/recall.rb
68
+ def recall_index(query, scope: :project, limit: 20)
69
+ facts = search_facts(query, scope:, limit:)
70
+ facts.map do |fact|
71
+ {
72
+ id: fact[:id],
73
+ subject: fact[:subject],
74
+ predicate: fact[:predicate],
75
+ object_preview: fact[:object_value][0..50],
76
+ scope: fact[:scope],
77
+ token_count: fact[:token_count] || estimate_tokens(fact)
78
+ }
79
+ end
80
+ end
81
+ ```
82
+
83
+ 3. **Add MCP tool for fetching details**:
84
+ ```ruby
85
+ # lib/claude_memory/mcp/tools.rb
86
+ TOOLS["memory.recall_index"] = {
87
+ description: "Layer 1: Search for facts. Returns compact index with IDs.",
88
+ input_schema: {
89
+ type: "object",
90
+ properties: {
91
+ query: { type: "string" },
92
+ scope: { type: "string", enum: ["global", "project", "both"] },
93
+ limit: { type: "integer", default: 20 }
94
+ }
95
+ }
96
+ }
97
+
98
+ TOOLS["memory.recall_details"] = {
99
+ description: "Layer 2: Fetch full fact details by IDs.",
100
+ input_schema: {
101
+ type: "object",
102
+ properties: {
103
+ fact_ids: { type: "array", items: { type: "integer" } }
104
+ },
105
+ required: ["fact_ids"]
106
+ }
107
+ }
108
+ ```
109
+
110
+ 4. **Update publish format** to show costs:
111
+ ```markdown
112
+ ## Recent Facts
113
+
114
+ | ID | Subject | Predicate | Preview | Tokens |
115
+ |----|---------|-----------|---------|--------|
116
+ | #123 | project | uses_database | PostgreSQL | ~45 |
117
+ | #124 | project | has_constraint | API rate lim... | ~120 |
118
+ ```
119
+
120
+ **Benefits**:
121
+ - Reduces context waste in published snapshots
122
+ - Gives Claude control over retrieval depth
123
+ - Makes token costs visible for informed decisions
124
+
125
+ **Trade-offs**:
126
+ - More complex MCP interface
127
+ - Requires token estimation logic
128
+ - May confuse users who expect full details
129
+
130
+ ---
131
+
132
+ ## 2. ROI Metrics and Token Economics
133
+
134
+ ### What claude-mem Does
135
+
136
+ **Discovery Token Tracking**:
137
+ - `discovery_tokens` field on observations table
138
+ - Tracks tokens spent discovering each piece of knowledge
139
+ - Cumulative metrics in session summaries
140
+ - Footer displays ROI: "Access 10k tokens for 2,500t"
141
+
142
+ **File**: `src/services/sqlite/Database.ts`
143
+
144
+ ```typescript
145
+ observations: {
146
+ id: INTEGER PRIMARY KEY,
147
+ title: TEXT,
148
+ narrative: TEXT,
149
+ discovery_tokens: INTEGER, // ← Cost tracking
150
+ created_at_epoch: INTEGER
151
+ }
152
+
153
+ session_summaries: {
154
+ cumulative_discovery_tokens: INTEGER, // ← Running total
155
+ observation_count: INTEGER
156
+ }
157
+ ```
158
+
159
+ **Context Footer Example**:
160
+ ```markdown
161
+ 💡 **Token Economics:**
162
+ - Context shown: 2,500 tokens
163
+ - Research captured: 10,000 tokens
164
+ - ROI: 4x compression
165
+ ```
166
+
167
+ ### What We Should Do
168
+
169
+ **Priority**: MEDIUM
170
+
171
+ **Implementation**:
172
+
173
+ 1. **Add metrics table**:
174
+ ```ruby
175
+ create_table :ingestion_metrics do
176
+ primary_key :id
177
+ foreign_key :content_item_id, :content_items
178
+ Integer :input_tokens
179
+ Integer :output_tokens
180
+ Integer :facts_extracted
181
+ DateTime :created_at
182
+ end
183
+ ```
184
+
185
+ 2. **Track during distillation**:
186
+ ```ruby
187
+ # lib/claude_memory/distill/distiller.rb
188
+ def distill(content)
189
+ response = api_call(content)
190
+ facts = extract_facts(response)
191
+
192
+ store_metrics(
193
+ input_tokens: response.usage.input_tokens,
194
+ output_tokens: response.usage.output_tokens,
195
+ facts_extracted: facts.size
196
+ )
197
+
198
+ facts
199
+ end
200
+ ```
201
+
202
+ 3. **Display in CLI**:
203
+ ```ruby
204
+ # claude-memory stats
205
+ def stats_cmd
206
+ metrics = store.aggregate_metrics
207
+ puts "Token Economics:"
208
+ puts " Input: #{metrics[:input_tokens]} tokens"
209
+ puts " Output: #{metrics[:output_tokens]} tokens"
210
+ puts " Facts: #{metrics[:facts_extracted]}"
211
+ puts " Efficiency: #{metrics[:facts_extracted] / metrics[:input_tokens].to_f} facts/token"
212
+ end
213
+ ```
214
+
215
+ 4. **Add to published snapshot**:
216
+ ```markdown
217
+ <!-- At bottom of .claude/rules/claude_memory.generated.md -->
218
+
219
+ ---
220
+
221
+ *Memory stats: 145 facts from 12,500 ingested tokens (86 facts/1k tokens)*
222
+ ```
223
+
224
+ **Benefits**:
225
+ - Visibility into memory system efficiency
226
+ - Justifies API costs (shows compression ratio)
227
+ - Helps tune distillation prompts for better extraction
228
+
229
+ **Trade-offs**:
230
+ - Requires API usage tracking
231
+ - Adds database complexity
232
+ - May not be meaningful for all distiller implementations
233
+
234
+ ---
235
+
236
+ ## 3. Privacy Tag System
237
+
238
+ ### What claude-mem Does
239
+
240
+ **Dual-Tag Architecture** for content exclusion:
241
+
242
+ 1. **`<claude-mem-context>`** (system tag):
243
+ - Prevents recursive storage when context is auto-injected
244
+ - Strips at hook layer before worker sees it
245
+
246
+ 2. **`<private>`** (user tag):
247
+ - Manual privacy control
248
+ - Users wrap sensitive content to exclude from storage
249
+ - Example: `API key: <private>sk-abc123</private>`
250
+
251
+ **File**: `src/utils/tag-stripping.ts`
252
+
253
+ ```typescript
254
+ export function stripPrivateTags(text: string): string {
255
+ const MAX_TAG_COUNT = 100; // ReDoS protection
256
+
257
+ return text
258
+ .replace(/<claude-mem-context>[\s\S]*?<\/claude-mem-context>/g, '')
259
+ .replace(/<private>[\s\S]*?<\/private>/g, '');
260
+ }
261
+ ```
262
+
263
+ **Edge Processing Philosophy**: Stripping happens at hook layer (before data reaches database).
264
+
265
+ ### What We Should Do
266
+
267
+ **Priority**: HIGH
268
+
269
+ **Implementation**:
270
+
271
+ 1. **Add tag stripping to ingester**:
272
+ ```ruby
273
+ # lib/claude_memory/ingest/transcript_reader.rb
274
+ class TranscriptReader
275
+ SYSTEM_TAGS = ['claude-memory-context'].freeze
276
+ USER_TAGS = ['private', 'no-memory'].freeze
277
+ MAX_TAG_COUNT = 100
278
+
279
+ def strip_tags(text)
280
+ validate_tag_count(text)
281
+
282
+ ALL_TAGS = SYSTEM_TAGS + USER_TAGS
283
+ ALL_TAGS.each do |tag|
284
+ text = text.gsub(/<#{tag}>.*?<\/#{tag}>/m, '')
285
+ end
286
+
287
+ text
288
+ end
289
+
290
+ def validate_tag_count(text)
291
+ count = text.scan(/<(?:#{ALL_TAGS.join('|')})>/).size
292
+ raise "Too many tags (#{count}), possible ReDoS" if count > MAX_TAG_COUNT
293
+ end
294
+ end
295
+ ```
296
+
297
+ 2. **Document in README**:
298
+ ```markdown
299
+ ## Privacy Control
300
+
301
+ Wrap sensitive content in `<private>` tags to exclude from storage:
302
+
303
+ ```
304
+ API endpoint: https://api.example.com
305
+ API key: <private>sk-abc123def456</private>
306
+ ```
307
+
308
+ System tags (auto-stripped):
309
+ - `<claude-memory-context>` - Prevents recursive storage of published memory
310
+ ```
311
+
312
+ 3. **Add to hook handler**:
313
+ ```ruby
314
+ # lib/claude_memory/hook/handler.rb
315
+ def ingest_hook
316
+ input = read_stdin
317
+ transcript = input[:transcript_delta]
318
+
319
+ # Strip tags before processing
320
+ transcript = strip_privacy_tags(transcript)
321
+
322
+ ingester.ingest(transcript)
323
+ end
324
+ ```
325
+
326
+ 4. **Test edge cases**:
327
+ ```ruby
328
+ # spec/claude_memory/ingest/transcript_reader_spec.rb
329
+ it "strips nested private tags" do
330
+ text = "Public <private>Secret <private>Nested</private></private> Public"
331
+ expect(strip_tags(text)).to eq("Public Public")
332
+ end
333
+
334
+ it "prevents ReDoS with many tags" do
335
+ text = "<private>" * 101
336
+ expect { strip_tags(text) }.to raise_error(/Too many tags/)
337
+ end
338
+ ```
339
+
340
+ **Benefits**:
341
+ - User control over sensitive data
342
+ - Prevents credential leakage
343
+ - Protects recursive context injection
344
+ - Security-conscious design
345
+
346
+ **Trade-offs**:
347
+ - Users must remember to tag sensitive content
348
+ - May create false sense of security
349
+ - Regex-based (could miss edge cases)
350
+
351
+ ---
352
+
353
+ ## 4. Slim Orchestrator Pattern
354
+
355
+ ### What claude-mem Does
356
+
357
+ **Worker Service Evolution**: Refactored from 2,000 lines → 300 lines orchestrator.
358
+
359
+ **File Structure**:
360
+ ```
361
+ src/services/worker-service.ts (300 lines - orchestrator)
362
+ ↓ delegates to
363
+ src/server/Server.ts (Express setup)
364
+ src/services/sqlite/Database.ts (data layer)
365
+ src/services/worker/ (business logic)
366
+ ├── SDKAgent.ts (agent management)
367
+ ├── SessionManager.ts (session lifecycle)
368
+ └── search/SearchOrchestrator.ts (search strategies)
369
+ src/infrastructure/ (process management)
370
+ ```
371
+
372
+ **Benefit**: Testability, readability, separation of concerns.
373
+
374
+ ### What We Should Do
375
+
376
+ **Priority**: MEDIUM
377
+
378
+ **Current State**:
379
+ - `lib/claude_memory/cli.rb`: 800+ lines (all commands)
380
+ - Logic mixed with CLI parsing
381
+ - Hard to test individual commands
382
+
383
+ **Implementation**:
384
+
385
+ 1. **Extract command classes**:
386
+ ```ruby
387
+ # lib/claude_memory/commands/
388
+ ├── base_command.rb
389
+ ├── ingest_command.rb
390
+ ├── recall_command.rb
391
+ ├── publish_command.rb
392
+ ├── promote_command.rb
393
+ └── sweep_command.rb
394
+ ```
395
+
396
+ 2. **Slim CLI to routing**:
397
+ ```ruby
398
+ # lib/claude_memory/cli.rb (150 lines)
399
+ module ClaudeMemory
400
+ class CLI
401
+ def run(args)
402
+ command_name = args[0]
403
+ command = command_for(command_name)
404
+ command.run(args[1..])
405
+ end
406
+
407
+ private
408
+
409
+ def command_for(name)
410
+ case name
411
+ when "ingest" then Commands::IngestCommand.new
412
+ when "recall" then Commands::RecallCommand.new
413
+ # ...
414
+ end
415
+ end
416
+ end
417
+ end
418
+ ```
419
+
420
+ 3. **Command base class**:
421
+ ```ruby
422
+ # lib/claude_memory/commands/base_command.rb
423
+ module ClaudeMemory
424
+ module Commands
425
+ class BaseCommand
426
+ def initialize
427
+ @store_manager = Store::StoreManager.new
428
+ end
429
+
430
+ def run(args)
431
+ options = parse_options(args)
432
+ validate_options(options)
433
+ execute(options)
434
+ end
435
+
436
+ private
437
+
438
+ def parse_options(args)
439
+ raise NotImplementedError
440
+ end
441
+
442
+ def execute(options)
443
+ raise NotImplementedError
444
+ end
445
+ end
446
+ end
447
+ end
448
+ ```
449
+
450
+ 4. **Example command**:
451
+ ```ruby
452
+ # lib/claude_memory/commands/recall_command.rb
453
+ module ClaudeMemory
454
+ module Commands
455
+ class RecallCommand < BaseCommand
456
+ def parse_options(args)
457
+ OptionParser.new do |opts|
458
+ opts.on("--query QUERY") { |q| options[:query] = q }
459
+ opts.on("--scope SCOPE") { |s| options[:scope] = s }
460
+ end.parse!(args)
461
+ end
462
+
463
+ def execute(options)
464
+ results = Recall.search(
465
+ options[:query],
466
+ scope: options[:scope]
467
+ )
468
+ puts format_results(results)
469
+ end
470
+ end
471
+ end
472
+ end
473
+ ```
474
+
475
+ **Benefits**:
476
+ - Each command is independently testable
477
+ - CLI.rb becomes simple router
478
+ - Easier to add new commands
479
+ - Clear separation of parsing vs execution
480
+
481
+ **Trade-offs**:
482
+ - More files to navigate
483
+ - Slightly more boilerplate
484
+ - May be overkill for small CLI
485
+
486
+ ---
487
+
488
+ ## 5. Health Monitoring and Process Management
489
+
490
+ ### What claude-mem Does
491
+
492
+ **Worker Service Management**:
493
+
494
+ ```typescript
495
+ // Health check endpoint
496
+ app.get('/health', (req, res) => {
497
+ res.json({
498
+ status: 'ok',
499
+ uptime: process.uptime(),
500
+ port: WORKER_PORT,
501
+ memory: process.memoryUsage(),
502
+ version: packageJson.version
503
+ });
504
+ });
505
+
506
+ // Smart startup
507
+ async function ensureWorkerHealthy(timeout = 10000) {
508
+ const healthy = await checkHealth();
509
+ if (!healthy) {
510
+ await startWorker();
511
+ await waitForHealth(timeout);
512
+ }
513
+ }
514
+ ```
515
+
516
+ **Process Management**:
517
+ - PID file tracking (`~/.claude-mem/worker.pid`)
518
+ - Port conflict detection
519
+ - Version mismatch warnings
520
+ - Graceful shutdown handlers
521
+ - Platform-aware timeouts (Windows vs Unix)
522
+
523
+ **File**: `src/infrastructure/ProcessManager.ts`
524
+
525
+ ### What We Should Do
526
+
527
+ **Priority**: LOW (we use MCP server, not background worker)
528
+
529
+ **Implementation** (if we add background worker):
530
+
531
+ 1. **Health endpoint in MCP server**:
532
+ ```ruby
533
+ # lib/claude_memory/mcp/server.rb
534
+ def handle_ping
535
+ {
536
+ status: "ok",
537
+ version: ClaudeMemory::VERSION,
538
+ databases: {
539
+ global: File.exist?(global_db_path),
540
+ project: File.exist?(project_db_path)
541
+ },
542
+ uptime: Process.clock_gettime(Process::CLOCK_MONOTONIC) - @start_time
543
+ }
544
+ end
545
+ ```
546
+
547
+ 2. **PID file management**:
548
+ ```ruby
549
+ # lib/claude_memory/daemon.rb
550
+ class Daemon
551
+ PID_FILE = File.expand_path("~/.claude/memory_server.pid")
552
+
553
+ def start
554
+ check_existing_process
555
+ fork_and_daemonize
556
+ write_pid_file
557
+ setup_signal_handlers
558
+ run_server
559
+ end
560
+
561
+ def stop
562
+ pid = read_pid_file
563
+ Process.kill("TERM", pid)
564
+ wait_for_shutdown
565
+ remove_pid_file
566
+ end
567
+ end
568
+ ```
569
+
570
+ **Benefits**:
571
+ - Reliable server lifecycle
572
+ - Easy debugging (health checks)
573
+ - Prevents duplicate processes
574
+
575
+ **Trade-offs**:
576
+ - Complexity we may not need
577
+ - Ruby daemons are tricky on Windows
578
+ - MCP stdio transport doesn't need health checks
579
+
580
+ **Verdict**: Skip unless we switch to HTTP-based MCP transport.
581
+
582
+ ---
583
+
584
+ ## 6. Semantic Shortcuts and Search Strategies
585
+
586
+ ### What claude-mem Does
587
+
588
+ **Semantic Shortcuts** (pre-configured queries):
589
+
590
+ ```typescript
591
+ // File: src/services/worker/http/routes/SearchRoutes.ts
592
+ app.get('/api/decisions', (req, res) => {
593
+ const results = await search({ type: 'decision' });
594
+ res.json(results);
595
+ });
596
+
597
+ app.get('/api/changes', (req, res) => {
598
+ const results = await search({ type: ['feature', 'change'] });
599
+ res.json(results);
600
+ });
601
+
602
+ app.get('/api/how-it-works', (req, res) => {
603
+ const results = await search({ type: 'how-it-works' });
604
+ res.json(results);
605
+ });
606
+ ```
607
+
608
+ **Search Strategy Pattern**:
609
+
610
+ ```typescript
611
+ // File: src/services/worker/search/SearchOrchestrator.ts
612
+ class SearchOrchestrator {
613
+ strategies: [
614
+ ChromaSearchStrategy, // Vector search (if available)
615
+ SQLiteSearchStrategy, // FTS5 fallback
616
+ HybridSearchStrategy // Combine both
617
+ ]
618
+
619
+ async search(query, options) {
620
+ const strategy = selectStrategy(options);
621
+ return strategy.execute(query);
622
+ }
623
+ }
624
+ ```
625
+
626
+ **Fallback Logic**:
627
+ 1. Try Chroma vector search (semantic)
628
+ 2. Fall back to SQLite FTS5 (keyword)
629
+ 3. Merge and re-rank results if both available
630
+
631
+ ### What We Should Do
632
+
633
+ **Priority**: MEDIUM
634
+
635
+ **Implementation**:
636
+
637
+ 1. **Add shortcut methods to Recall**:
638
+ ```ruby
639
+ # lib/claude_memory/recall.rb
640
+ module ClaudeMemory
641
+ class Recall
642
+ class << self
643
+ def recent_decisions(limit: 10)
644
+ search("decision constraint rule", limit:)
645
+ end
646
+
647
+ def architecture_choices(limit: 10)
648
+ search("uses framework implements architecture", limit:)
649
+ end
650
+
651
+ def conventions(limit: 20)
652
+ search("convention style format pattern", scope: :global, limit:)
653
+ end
654
+
655
+ def project_config(limit: 10)
656
+ search("uses requires depends_on", scope: :project, limit:)
657
+ end
658
+ end
659
+ end
660
+ end
661
+ ```
662
+
663
+ 2. **Add MCP tools for shortcuts**:
664
+ ```ruby
665
+ # lib/claude_memory/mcp/tools.rb
666
+ TOOLS["memory.decisions"] = {
667
+ description: "Quick access to architectural decisions and constraints",
668
+ input_schema: { type: "object", properties: { limit: { type: "integer" } } }
669
+ }
670
+
671
+ TOOLS["memory.conventions"] = {
672
+ description: "Quick access to coding conventions and preferences",
673
+ input_schema: { type: "object", properties: { limit: { type: "integer" } } }
674
+ }
675
+ ```
676
+
677
+ 3. **Search strategy pattern** (future: if we add vector search):
678
+ ```ruby
679
+ # lib/claude_memory/index/search_strategy.rb
680
+ module ClaudeMemory
681
+ module Index
682
+ class SearchStrategy
683
+ def self.select(options)
684
+ if options[:semantic] && vector_db_available?
685
+ VectorSearchStrategy.new
686
+ else
687
+ LexicalSearchStrategy.new
688
+ end
689
+ end
690
+ end
691
+
692
+ class LexicalSearchStrategy < SearchStrategy
693
+ def search(query)
694
+ LexicalFTS.search(query)
695
+ end
696
+ end
697
+
698
+ class VectorSearchStrategy < SearchStrategy
699
+ def search(query)
700
+ # Future: vector embeddings
701
+ end
702
+ end
703
+ end
704
+ end
705
+ ```
706
+
707
+ **Benefits**:
708
+ - Common queries are one command
709
+ - Reduces cognitive load
710
+ - Pre-optimized for specific use cases
711
+ - Strategy pattern enables future enhancements
712
+
713
+ **Trade-offs**:
714
+ - Need to pick right shortcuts (user research)
715
+ - May not cover all use cases
716
+ - Shortcuts can become stale
717
+
718
+ ---
719
+
720
+ ## 7. Web-Based Viewer UI
721
+
722
+ ### What claude-mem Does
723
+
724
+ **Real-Time Memory Viewer** at `http://localhost:37777`:
725
+
726
+ - React-based web UI
727
+ - Server-Sent Events (SSE) for real-time updates
728
+ - Infinite scroll pagination
729
+ - Project filtering
730
+ - Settings persistence (sidebar state, theme)
731
+ - Auto-reconnection with exponential backoff
732
+ - Single-file HTML bundle (esbuild)
733
+
734
+ **File**: `src/ui/viewer/` (React components)
735
+
736
+ **Features**:
737
+ - See observations as they're captured
738
+ - Search historical observations
739
+ - Filter by project
740
+ - Export/share observations
741
+ - Theme toggle (light/dark)
742
+
743
+ **Build**:
744
+ ```typescript
745
+ esbuild.build({
746
+ entryPoints: ['src/ui/viewer/index.tsx'],
747
+ bundle: true,
748
+ outfile: 'plugin/ui/viewer.html',
749
+ loader: { '.tsx': 'tsx', '.woff2': 'dataurl' },
750
+ });
751
+ ```
752
+
753
+ ### What We Should Do
754
+
755
+ **Priority**: LOW (nice-to-have)
756
+
757
+ **Implementation** (if we want it):
758
+
759
+ 1. **Add Sinatra web server**:
760
+ ```ruby
761
+ # lib/claude_memory/web/server.rb
762
+ require 'sinatra/base'
763
+ require 'json'
764
+
765
+ module ClaudeMemory
766
+ module Web
767
+ class Server < Sinatra::Base
768
+ get '/' do
769
+ erb :index
770
+ end
771
+
772
+ get '/api/facts' do
773
+ facts = Recall.search(params[:query], limit: 100)
774
+ json facts
775
+ end
776
+
777
+ get '/api/stream' do
778
+ stream :keep_open do |out|
779
+ # SSE for real-time updates
780
+ EventMachine.add_periodic_timer(1) do
781
+ out << "data: #{recent_facts.to_json}\n\n"
782
+ end
783
+ end
784
+ end
785
+ end
786
+ end
787
+ end
788
+ ```
789
+
790
+ 2. **Add to MCP server** (optional HTTP endpoint):
791
+ ```ruby
792
+ # claude-memory serve --web
793
+ def serve_with_web
794
+ Thread.new { Web::Server.run!(port: 37778) }
795
+ serve_mcp # Main MCP server
796
+ end
797
+ ```
798
+
799
+ 3. **Simple HTML viewer**:
800
+ ```html
801
+ <!-- lib/claude_memory/web/views/index.erb -->
802
+ <!DOCTYPE html>
803
+ <html>
804
+ <head>
805
+ <title>ClaudeMemory Viewer</title>
806
+ <style>/* Minimal CSS */</style>
807
+ </head>
808
+ <body>
809
+ <div id="facts-list"></div>
810
+ <script>
811
+ // Fetch and display facts
812
+ fetch('/api/facts')
813
+ .then(r => r.json())
814
+ .then(facts => render(facts));
815
+ </script>
816
+ </body>
817
+ </html>
818
+ ```
819
+
820
+ **Benefits**:
821
+ - Visibility into memory system
822
+ - Debugging tool
823
+ - User trust (transparency)
824
+
825
+ **Trade-offs**:
826
+ - Significant development effort
827
+ - Need to bundle web assets
828
+ - Another dependency (web server)
829
+ - Maintenance burden
830
+
831
+ **Verdict**: Skip for MVP. Consider if users request it.
832
+
833
+ ---
834
+
835
+ ## 8. Dual-Integration Strategy
836
+
837
+ ### What claude-mem Does
838
+
839
+ **Plugin + MCP Server Hybrid**:
840
+
841
+ 1. **Claude Code Plugin** (primary):
842
+ - Hooks for lifecycle events
843
+ - Worker service for AI processing
844
+ - Installed via marketplace
845
+
846
+ 2. **MCP Server** (secondary):
847
+ - Thin wrapper delegating to worker HTTP API
848
+ - Enables Claude Desktop integration
849
+ - Same backend, different frontend
850
+
851
+ **File**: `src/servers/mcp-server.ts` (thin wrapper)
852
+
853
+ ```typescript
854
+ // MCP server delegates to worker HTTP API
855
+ const mcpServer = new McpServer({
856
+ name: "claude-mem",
857
+ version: packageJson.version
858
+ });
859
+
860
+ mcpServer.setRequestHandler(ListToolsRequestSchema, async () => {
861
+ // Fetch tools from worker
862
+ const tools = await fetch('http://localhost:37777/api/mcp/tools');
863
+ return tools.json();
864
+ });
865
+
866
+ mcpServer.setRequestHandler(CallToolRequestSchema, async (request) => {
867
+ // Forward to worker
868
+ const result = await fetch('http://localhost:37777/api/mcp/call', {
869
+ method: 'POST',
870
+ body: JSON.stringify(request.params)
871
+ });
872
+ return result.json();
873
+ });
874
+ ```
875
+
876
+ **Benefit**: One backend, multiple frontends.
877
+
878
+ ### What We Should Do
879
+
880
+ **Priority**: LOW
881
+
882
+ **Current State**: We only have MCP server (no plugin hooks yet).
883
+
884
+ **Implementation** (if we add Claude Code hooks):
885
+
886
+ 1. **Keep MCP server as primary**:
887
+ ```ruby
888
+ # lib/claude_memory/mcp/server.rb
889
+ # Current implementation - keep as-is
890
+ ```
891
+
892
+ 2. **Add hook handlers**:
893
+ ```ruby
894
+ # lib/claude_memory/hook/handler.rb
895
+ # Delegate to same store manager
896
+ def ingest_hook
897
+ store_manager = Store::StoreManager.new
898
+ ingester = Ingest::Ingester.new(store_manager)
899
+ ingester.ingest(read_stdin[:transcript_delta])
900
+ end
901
+ ```
902
+
903
+ 3. **Shared backend**:
904
+ ```
905
+ MCP Server (stdio) ──┐
906
+ ├──> Store::StoreManager ──> SQLite
907
+ Hook Handler (stdin) ─┘
908
+ ```
909
+
910
+ **Benefits**:
911
+ - Works with both Claude Code and Claude Desktop
912
+ - No duplicate logic
913
+ - Clean separation of transport vs business logic
914
+
915
+ **Trade-offs**:
916
+ - More integration points to maintain
917
+ - Hook contract is Claude Code-specific
918
+
919
+ **Verdict**: Consider if we add Claude Code hooks (not urgent).
920
+
921
+ ---
922
+
923
+ ## 9. Exit Code Strategy for Hooks
924
+
925
+ ### What claude-mem Does
926
+
927
+ **Hook Exit Code Contract**:
928
+
929
+ ```typescript
930
+ // Success or graceful shutdown
931
+ process.exit(0); // Windows Terminal closes tab
932
+
933
+ // Non-blocking error (show to user, continue)
934
+ console.error("Warning: ...");
935
+ process.exit(1);
936
+
937
+ // Blocking error (feed to Claude for processing)
938
+ console.error("ERROR: ...");
939
+ process.exit(2);
940
+ ```
941
+
942
+ **Philosophy**: Worker/hook errors exit with 0 to prevent Windows Terminal tab accumulation.
943
+
944
+ **File**: `docs/context/claude-code/exit-codes.md`
945
+
946
+ ### What We Should Do
947
+
948
+ **Priority**: MEDIUM (if we add hooks)
949
+
950
+ **Implementation**:
951
+
952
+ 1. **Define exit code constants**:
953
+ ```ruby
954
+ # lib/claude_memory/hook/exit_codes.rb
955
+ module ClaudeMemory
956
+ module Hook
957
+ module ExitCodes
958
+ SUCCESS = 0
959
+ WARNING = 1 # Non-blocking error
960
+ ERROR = 2 # Blocking error
961
+ end
962
+ end
963
+ end
964
+ ```
965
+
966
+ 2. **Use in hook handler**:
967
+ ```ruby
968
+ # lib/claude_memory/hook/handler.rb
969
+ def run
970
+ handle_hook(ARGV[0])
971
+ exit ExitCodes::SUCCESS
972
+ rescue NonBlockingError => e
973
+ warn e.message
974
+ exit ExitCodes::WARNING
975
+ rescue => e
976
+ $stderr.puts "ERROR: #{e.message}"
977
+ exit ExitCodes::ERROR
978
+ end
979
+ ```
980
+
981
+ 3. **Document in CLAUDE.md**:
982
+ ```markdown
983
+ ## Hook Exit Codes
984
+
985
+ - **0**: Success or graceful shutdown
986
+ - **1**: Non-blocking error (shown to user, session continues)
987
+ - **2**: Blocking error (fed to Claude for processing)
988
+ ```
989
+
990
+ **Benefits**:
991
+ - Clear contract with Claude Code
992
+ - Predictable behavior
993
+ - Better error handling
994
+
995
+ **Trade-offs**:
996
+ - Hook-specific pattern
997
+ - Not applicable to MCP server
998
+
999
+ ---
1000
+
1001
+ ## 10. Configuration-Driven Context Injection
1002
+
1003
+ ### What claude-mem Does
1004
+
1005
+ **Context Config File**: `~/.claude-mem/settings.json`
1006
+
1007
+ ```json
1008
+ {
1009
+ "context": {
1010
+ "mode": "reader", // reader | chat | inference
1011
+ "observations": {
1012
+ "enabled": true,
1013
+ "limit": 10,
1014
+ "types": ["decision", "gotcha", "trade-off"]
1015
+ },
1016
+ "summaries": {
1017
+ "enabled": true,
1018
+ "fields": ["request", "learned", "completed"]
1019
+ },
1020
+ "timeline": {
1021
+ "depth": 5
1022
+ }
1023
+ }
1024
+ }
1025
+ ```
1026
+
1027
+ **File**: `src/services/context/ContextConfigLoader.ts`
1028
+
1029
+ **Benefit**: Users can fine-tune what gets injected.
1030
+
1031
+ ### What We Should Do
1032
+
1033
+ **Priority**: LOW
1034
+
1035
+ **Implementation**:
1036
+
1037
+ 1. **Add config file**:
1038
+ ```ruby
1039
+ # ~/.claude/memory_config.yml
1040
+ publish:
1041
+ mode: shared # shared | local | home
1042
+ facts:
1043
+ limit: 50
1044
+ scopes: [global, project]
1045
+ predicates: [uses_*, depends_on, has_constraint]
1046
+ entities:
1047
+ limit: 20
1048
+ conflicts:
1049
+ show: true
1050
+ ```
1051
+
1052
+ 2. **Load in publisher**:
1053
+ ```ruby
1054
+ # lib/claude_memory/publish.rb
1055
+ class Publisher
1056
+ def initialize
1057
+ @config = load_config
1058
+ end
1059
+
1060
+ def load_config
1061
+ path = File.expand_path("~/.claude/memory_config.yml")
1062
+ YAML.load_file(path) if File.exist?(path)
1063
+ rescue
1064
+ default_config
1065
+ end
1066
+ end
1067
+ ```
1068
+
1069
+ 3. **Apply during publish**:
1070
+ ```ruby
1071
+ def build_snapshot
1072
+ config = @config[:publish]
1073
+
1074
+ facts = store.facts(
1075
+ limit: config[:facts][:limit],
1076
+ scopes: config[:facts][:scopes]
1077
+ )
1078
+
1079
+ format_snapshot(facts, config)
1080
+ end
1081
+ ```
1082
+
1083
+ **Benefits**:
1084
+ - User control over published content
1085
+ - Environment-specific configs
1086
+ - Reduces noise in generated files
1087
+
1088
+ **Trade-offs**:
1089
+ - Another config file to document
1090
+ - May confuse users
1091
+ - Publish should be opinionated by default
1092
+
1093
+ **Verdict**: Skip for MVP. Default config is sufficient.
1094
+
1095
+ ---
1096
+
1097
+ ## Features We're Already Doing Better
1098
+
1099
+ ### 1. Dual-Database Architecture (Global + Project)
1100
+
1101
+ **Our Advantage**: `Store::StoreManager` with global + project scopes.
1102
+
1103
+ Claude-mem has a single database with project filtering. Our approach is cleaner:
1104
+
1105
+ ```ruby
1106
+ # We separate global vs project knowledge
1107
+ @global_store = Store::SqliteStore.new(global_db_path)
1108
+ @project_store = Store::SqliteStore.new(project_db_path)
1109
+
1110
+ # Claude-mem filters post-query
1111
+ SELECT * FROM observations WHERE project = ?
1112
+ ```
1113
+
1114
+ **Keep this.** It's a better design.
1115
+
1116
+ ### 2. Fact-Based Knowledge Graph
1117
+
1118
+ **Our Advantage**: Subject-predicate-object triples with provenance.
1119
+
1120
+ Claude-mem stores blob observations. We store structured facts:
1121
+
1122
+ ```ruby
1123
+ # Ours (structured)
1124
+ { subject: "project", predicate: "uses_database", object: "PostgreSQL" }
1125
+
1126
+ # Theirs (blob)
1127
+ { title: "Uses PostgreSQL", narrative: "The project uses..." }
1128
+ ```
1129
+
1130
+ **Keep this.** Enables richer queries and inference.
1131
+
1132
+ ### 3. Truth Maintenance System
1133
+
1134
+ **Our Advantage**: `Resolve::Resolver` with supersession and conflicts.
1135
+
1136
+ Claude-mem doesn't resolve contradictions. We do:
1137
+
1138
+ ```ruby
1139
+ # We detect when facts supersede each other
1140
+ old: { subject: "api", predicate: "uses_auth", object: "JWT" }
1141
+ new: { subject: "api", predicate: "uses_auth", object: "OAuth2" }
1142
+ # → Creates supersession link
1143
+
1144
+ # We detect conflicts
1145
+ fact1: { subject: "api", predicate: "rate_limit", object: "100/min" }
1146
+ fact2: { subject: "api", predicate: "rate_limit", object: "1000/min" }
1147
+ # → Creates conflict record
1148
+ ```
1149
+
1150
+ **Keep this.** It's a core differentiator.
1151
+
1152
+ ### 4. Predicate Policies
1153
+
1154
+ **Our Advantage**: `Resolve::PredicatePolicy` for single vs multi-value.
1155
+
1156
+ Claude-mem doesn't distinguish. We do:
1157
+
1158
+ ```ruby
1159
+ # Single-value (supersedes)
1160
+ "uses_database" → only one database at a time
1161
+
1162
+ # Multi-value (accumulates)
1163
+ "depends_on" → many dependencies
1164
+ ```
1165
+
1166
+ **Keep this.** Prevents false conflicts.
1167
+
1168
+ ### 5. Ruby Ecosystem (Simpler)
1169
+
1170
+ **Our Advantage**: Fewer dependencies, easier install.
1171
+
1172
+ ```ruby
1173
+ # Ours
1174
+ gem install claude_memory # Done
1175
+
1176
+ # Theirs
1177
+ npm install # Needs Node.js
1178
+ npm install chromadb # Needs Python + pip
1179
+ npm install better-sqlite3 # Needs node-gyp + build tools
1180
+ ```
1181
+
1182
+ **Keep this.** Ruby's stdlib is excellent.
1183
+
1184
+ ---
1185
+
1186
+ ## Features to Avoid
1187
+
1188
+ ### 1. Chroma Vector Database
1189
+
1190
+ **Their Approach**: Hybrid SQLite FTS5 + Chroma vector search.
1191
+
1192
+ **Our Take**: **Skip it.** Adds significant complexity:
1193
+
1194
+ - Python dependency
1195
+ - ChromaDB server
1196
+ - Embedding generation
1197
+ - Sync overhead
1198
+
1199
+ **Alternative**: Stick with SQLite FTS5. Add embeddings only if users request semantic search.
1200
+
1201
+ ### 2. Claude Agent SDK for Distillation
1202
+
1203
+ **Their Approach**: Use `@anthropic-ai/claude-agent-sdk` for observation compression.
1204
+
1205
+ **Our Take**: **Skip it.** We already have `Distill::Distiller` interface. SDK adds:
1206
+
1207
+ - Node.js dependency
1208
+ - Subprocess management
1209
+ - Complex event loop
1210
+
1211
+ **Alternative**: Direct API calls via `anthropic-rb` gem (if we implement distiller).
1212
+
1213
+ ### 3. Worker Service Background Process
1214
+
1215
+ **Their Approach**: Long-running worker with HTTP API + MCP wrapper.
1216
+
1217
+ **Our Take**: **Skip it.** We use MCP server directly:
1218
+
1219
+ - No background process to manage
1220
+ - No port conflicts
1221
+ - No PID files
1222
+ - Simpler deployment
1223
+
1224
+ **Alternative**: Keep stdio-based MCP server. Add HTTP transport only if needed.
1225
+
1226
+ ### 4. Web Viewer UI
1227
+
1228
+ **Their Approach**: React-based web UI at `http://localhost:37777`.
1229
+
1230
+ **Our Take**: **Skip for MVP.** Significant effort for uncertain value:
1231
+
1232
+ - React + esbuild
1233
+ - SSE implementation
1234
+ - State management
1235
+ - CSS/theming
1236
+
1237
+ **Alternative**: CLI output is sufficient. Add web UI if users request it.
1238
+
1239
+ ---
1240
+
1241
+ ## Implementation Priorities
1242
+
1243
+ ### High Priority (Next Sprint)
1244
+
1245
+ 1. **Progressive Disclosure Pattern** - Add index format to Recall, update MCP tools
1246
+ 2. **Privacy Tag System** - Implement `<private>` tag stripping
1247
+ 3. **Exit Code Strategy** - Define exit codes for future hooks
1248
+
1249
+ ### Medium Priority (Next Quarter)
1250
+
1251
+ 4. **ROI Metrics** - Track token economics
1252
+ 5. **Slim Orchestrator Pattern** - Extract commands from CLI
1253
+ 6. **Semantic Shortcuts** - Add convenience methods to Recall
1254
+ 7. **Search Strategies** - Prepare for future vector search
1255
+
1256
+ ### Low Priority (Future)
1257
+
1258
+ 8. **Health Monitoring** - Only if we add background worker
1259
+ 9. **Dual Integration** - Only if we add Claude Code hooks
1260
+ 10. **Config-Driven Context** - Only if users request customization
1261
+ 11. **Web Viewer UI** - Only if users request visualization
1262
+
1263
+ ---
1264
+
1265
+ ## Migration Path
1266
+
1267
+ ### Phase 1: Quick Wins (1-2 weeks)
1268
+
1269
+ - [ ] Implement `<private>` tag stripping in ingester
1270
+ - [ ] Add token count estimation to facts
1271
+ - [ ] Create index format in Recall
1272
+ - [ ] Add `memory.recall_index` MCP tool
1273
+ - [ ] Document progressive disclosure pattern
1274
+
1275
+ ### Phase 2: Structural (1 month)
1276
+
1277
+ - [ ] Extract command classes from CLI
1278
+ - [ ] Add metrics table for token tracking
1279
+ - [ ] Implement semantic shortcuts
1280
+ - [ ] Add search strategy pattern (prep for vector search)
1281
+
1282
+ ### Phase 3: Advanced (3+ months)
1283
+
1284
+ - [ ] Add vector embeddings (if requested)
1285
+ - [ ] Build web viewer (if requested)
1286
+ - [ ] Add Claude Code hooks (if requested)
1287
+ - [ ] Implement background worker (if needed)
1288
+
1289
+ ---
1290
+
1291
+ ## Key Takeaways
1292
+
1293
+ **What claude-mem does exceptionally well**:
1294
+ 1. Progressive disclosure (token efficiency)
1295
+ 2. ROI metrics (visibility)
1296
+ 3. Privacy controls (user trust)
1297
+ 4. Clean architecture (maintainability)
1298
+ 5. Production polish (error handling, logging, health checks)
1299
+
1300
+ **What we do better**:
1301
+ 1. Dual-database architecture (global + project)
1302
+ 2. Fact-based knowledge graph (structured)
1303
+ 3. Truth maintenance (conflict resolution)
1304
+ 4. Predicate policies (semantic understanding)
1305
+ 5. Simpler dependencies (Ruby ecosystem)
1306
+
1307
+ **Our path forward**:
1308
+ - Adopt their token efficiency patterns
1309
+ - Keep our knowledge graph architecture
1310
+ - Add privacy controls
1311
+ - Improve observability (metrics)
1312
+ - Maintain simplicity (avoid over-engineering)
1313
+
1314
+ ---
1315
+
1316
+ ## References
1317
+
1318
+ - [claude-mem GitHub](https://github.com/thedotmack/claude-mem)
1319
+ - [Architecture Evolution](../claude-mem/docs/public/architecture-evolution.mdx)
1320
+ - [Progressive Disclosure Philosophy](../claude-mem/docs/public/progressive-disclosure.mdx)
1321
+ - [ClaudeMemory Updated Plan](updated_plan.md)
1322
+
1323
+ ---
1324
+
1325
+ *This analysis represents a critical review of production-grade patterns that have proven effective in real-world usage. Our goal is to learn from claude-mem's strengths while preserving the unique advantages of our fact-based approach.*