claude_memory 0.7.1 → 0.9.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 (107) hide show
  1. checksums.yaml +4 -4
  2. data/.claude/memory.sqlite3 +0 -0
  3. data/.claude/rules/claude_memory.generated.md +32 -2
  4. data/.claude/settings.json +65 -15
  5. data/.claude/settings.local.json +5 -2
  6. data/.claude/skills/improve/SKILL.md +113 -25
  7. data/.claude/skills/upgrade-dependencies/SKILL.md +154 -0
  8. data/.claude-plugin/commands/distill-transcripts.md +98 -0
  9. data/.claude-plugin/commands/memory-recall.md +67 -0
  10. data/.claude-plugin/marketplace.json +2 -2
  11. data/.claude-plugin/plugin.json +3 -3
  12. data/.claude-plugin/scripts/hook-runner.sh +14 -0
  13. data/.claude-plugin/scripts/serve-mcp.sh +14 -0
  14. data/.ruby-version +1 -1
  15. data/CHANGELOG.md +90 -1
  16. data/CLAUDE.md +56 -18
  17. data/README.md +35 -0
  18. data/db/migrations/013_add_mcp_tool_calls.rb +26 -0
  19. data/db/migrations/014_canonicalize_predicates.rb +30 -0
  20. data/docs/improvements.md +74 -74
  21. data/docs/influence/claude-mem.md +1 -0
  22. data/docs/influence/claude-supermemory.md +1 -0
  23. data/docs/influence/episodic-memory.md +1 -0
  24. data/docs/influence/grepai.md +1 -0
  25. data/docs/influence/kbs.md +1 -0
  26. data/docs/influence/lossless-claw.md +1 -0
  27. data/docs/influence/qmd.md +1 -0
  28. data/docs/quality_review.md +119 -224
  29. data/hooks/hooks.json +39 -7
  30. data/lib/claude_memory/commands/checks/distill_check.rb +61 -0
  31. data/lib/claude_memory/commands/checks/hooks_check.rb +2 -2
  32. data/lib/claude_memory/commands/checks/vec_check.rb +2 -1
  33. data/lib/claude_memory/commands/completion_command.rb +149 -0
  34. data/lib/claude_memory/commands/doctor_command.rb +2 -0
  35. data/lib/claude_memory/commands/embeddings_command.rb +198 -0
  36. data/lib/claude_memory/commands/help_command.rb +12 -1
  37. data/lib/claude_memory/commands/hook_command.rb +2 -1
  38. data/lib/claude_memory/commands/index_command.rb +85 -78
  39. data/lib/claude_memory/commands/initializers/database_ensurer.rb +16 -0
  40. data/lib/claude_memory/commands/initializers/global_initializer.rb +2 -1
  41. data/lib/claude_memory/commands/initializers/hooks_configurator.rb +55 -11
  42. data/lib/claude_memory/commands/initializers/project_initializer.rb +2 -1
  43. data/lib/claude_memory/commands/install_skill_command.rb +78 -0
  44. data/lib/claude_memory/commands/registry.rb +47 -32
  45. data/lib/claude_memory/commands/reject_command.rb +62 -0
  46. data/lib/claude_memory/commands/restore_command.rb +77 -0
  47. data/lib/claude_memory/commands/skills/distill-transcripts.md +102 -0
  48. data/lib/claude_memory/commands/skills/memory-recall.md +67 -0
  49. data/lib/claude_memory/commands/stats_command.rb +98 -2
  50. data/lib/claude_memory/configuration.rb +14 -1
  51. data/lib/claude_memory/core/fact_ranker.rb +2 -2
  52. data/lib/claude_memory/core/rr_fusion.rb +23 -6
  53. data/lib/claude_memory/core/snippet_extractor.rb +7 -3
  54. data/lib/claude_memory/core/text_builder.rb +11 -0
  55. data/lib/claude_memory/distill/json_schema.md +8 -4
  56. data/lib/claude_memory/distill/null_distiller.rb +2 -0
  57. data/lib/claude_memory/domain/entity.rb +13 -1
  58. data/lib/claude_memory/domain/fact.rb +26 -2
  59. data/lib/claude_memory/domain/provenance.rb +0 -1
  60. data/lib/claude_memory/embeddings/api_adapter.rb +97 -0
  61. data/lib/claude_memory/embeddings/dimension_check.rb +23 -0
  62. data/lib/claude_memory/embeddings/fastembed_adapter.rb +46 -12
  63. data/lib/claude_memory/embeddings/generator.rb +4 -0
  64. data/lib/claude_memory/embeddings/inspector.rb +91 -0
  65. data/lib/claude_memory/embeddings/model_registry.rb +210 -0
  66. data/lib/claude_memory/embeddings/resolver.rb +44 -0
  67. data/lib/claude_memory/hook/context_injector.rb +58 -2
  68. data/lib/claude_memory/hook/distillation_runner.rb +46 -0
  69. data/lib/claude_memory/hook/handler.rb +11 -2
  70. data/lib/claude_memory/index/vector_index.rb +15 -2
  71. data/lib/claude_memory/infrastructure/schema_validator.rb +3 -3
  72. data/lib/claude_memory/ingest/ingester.rb +17 -0
  73. data/lib/claude_memory/mcp/handlers/context_handlers.rb +38 -0
  74. data/lib/claude_memory/mcp/handlers/management_handlers.rb +169 -0
  75. data/lib/claude_memory/mcp/handlers/query_handlers.rb +115 -0
  76. data/lib/claude_memory/mcp/handlers/setup_handlers.rb +211 -0
  77. data/lib/claude_memory/mcp/handlers/shortcut_handlers.rb +37 -0
  78. data/lib/claude_memory/mcp/handlers/stats_handlers.rb +205 -0
  79. data/lib/claude_memory/mcp/instructions_builder.rb +19 -1
  80. data/lib/claude_memory/mcp/query_guide.rb +10 -0
  81. data/lib/claude_memory/mcp/response_formatter.rb +1 -0
  82. data/lib/claude_memory/mcp/server.rb +22 -1
  83. data/lib/claude_memory/mcp/telemetry.rb +86 -0
  84. data/lib/claude_memory/mcp/text_summary.rb +26 -0
  85. data/lib/claude_memory/mcp/tool_definitions.rb +116 -4
  86. data/lib/claude_memory/mcp/tool_helpers.rb +43 -0
  87. data/lib/claude_memory/mcp/tools.rb +50 -679
  88. data/lib/claude_memory/publish.rb +40 -5
  89. data/lib/claude_memory/recall/dual_engine.rb +105 -0
  90. data/lib/claude_memory/recall/legacy_engine.rb +138 -0
  91. data/lib/claude_memory/recall/query_core.rb +371 -0
  92. data/lib/claude_memory/recall.rb +121 -673
  93. data/lib/claude_memory/resolve/predicate_policy.rb +63 -3
  94. data/lib/claude_memory/resolve/resolver.rb +43 -0
  95. data/lib/claude_memory/shortcuts.rb +4 -4
  96. data/lib/claude_memory/store/retry_handler.rb +61 -0
  97. data/lib/claude_memory/store/schema_manager.rb +68 -0
  98. data/lib/claude_memory/store/sqlite_store.rb +334 -201
  99. data/lib/claude_memory/store/store_manager.rb +50 -1
  100. data/lib/claude_memory/sweep/maintenance.rb +115 -1
  101. data/lib/claude_memory/sweep/sweeper.rb +3 -0
  102. data/lib/claude_memory/templates/hooks.example.json +26 -7
  103. data/lib/claude_memory/version.rb +1 -1
  104. data/lib/claude_memory.rb +16 -0
  105. metadata +48 -8
  106. data/.claude/memory.sqlite3-shm +0 -0
  107. data/.claude/memory.sqlite3-wal +0 -0
@@ -0,0 +1,67 @@
1
+ # Memory Recall Agent
2
+
3
+ Search long-term memory for facts, decisions, conventions, and architectural knowledge. Chains multiple memory tools to build comprehensive answers while saving main-agent context.
4
+
5
+ ## Usage
6
+
7
+ Provide a natural language query describing what you want to recall:
8
+
9
+ ```
10
+ /memory-recall database migration strategy
11
+ /memory-recall authentication decisions
12
+ /memory-recall testing conventions
13
+ ```
14
+
15
+ ## Workflow
16
+
17
+ 1. **Fast lookup** — Start with `memory.recall` for keyword matches
18
+ 2. **Semantic search** — If recall returns few results, try `memory.recall_semantic` for conceptual matches
19
+ 3. **Shortcuts** — For known categories, use `memory.decisions`, `memory.conventions`, or `memory.architecture`
20
+ 4. **Deep dive** — For specific facts, use `memory.explain` to get provenance and `memory.fact_graph` to see relationships
21
+ 5. **Synthesize** — Combine findings into a concise, structured answer
22
+
23
+ ## Instructions
24
+
25
+ You are a memory recall specialist. Given a query, search ClaudeMemory using the available MCP tools and return a synthesized answer.
26
+
27
+ ### Step 1: Initial Search
28
+
29
+ Run `memory.recall` with the user's query. If the query mentions decisions, conventions, or architecture, also run the appropriate shortcut tool in parallel.
30
+
31
+ ### Step 2: Expand if Needed
32
+
33
+ If Step 1 returns fewer than 3 results:
34
+ - Try `memory.recall_semantic` with a rephrased version of the query
35
+ - Try `memory.search_concepts` with 2-3 key concepts extracted from the query
36
+
37
+ ### Step 3: Enrich Key Facts
38
+
39
+ For the top 2-3 most relevant facts:
40
+ - Run `memory.explain` to get provenance (where the fact came from)
41
+ - If relationships matter, run `memory.fact_graph` to see connected facts
42
+
43
+ ### Step 4: Synthesize
44
+
45
+ Return a structured response:
46
+
47
+ ```
48
+ ## Memory Recall Results
49
+
50
+ ### Key Facts
51
+ - [Fact 1 with provenance]
52
+ - [Fact 2 with provenance]
53
+
54
+ ### Context
55
+ [How these facts relate to the query]
56
+
57
+ ### Confidence
58
+ [High/Medium/Low based on number and freshness of supporting facts]
59
+ ```
60
+
61
+ ### Guidelines
62
+
63
+ - Prefer `memory.recall` (fast, token-efficient) before escalating to semantic search
64
+ - Use `compact: true` on all tool calls to minimize token usage
65
+ - Do NOT fabricate facts — only report what memory tools return
66
+ - If no relevant facts found, say so clearly rather than guessing
67
+ - Include fact IDs so the main agent can reference them
@@ -7,9 +7,9 @@
7
7
  "plugins": [
8
8
  {
9
9
  "name": "claude-memory",
10
- "version": "0.7.1",
10
+ "version": "0.9.0",
11
11
  "source": "./",
12
- "description": "Long-term self-managed memory for Claude Code with fact extraction, truth maintenance, and provenance tracking",
12
+ "description": "Long-term memory for Claude Code. Recalls architecture, conventions, and decisions across sessions — so Claude explains your codebase without file traversal, follows your patterns, and never re-asks what it already learned.",
13
13
  "repository": "https://github.com/codenamev/claude_memory"
14
14
  }
15
15
  ]
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "claude-memory",
3
- "version": "0.7.1",
4
- "description": "Long-term self-managed memory for Claude Code with fact extraction, truth maintenance, and provenance tracking",
3
+ "version": "0.9.0",
4
+ "description": "Long-term memory for Claude Code. Recalls architecture, conventions, and decisions across sessions — so Claude explains your codebase without file traversal, follows your patterns, and never re-asks what it already learned.",
5
5
  "author": {
6
6
  "name": "Valentino Stoll",
7
7
  "email": "v@codenamev.com"
@@ -9,7 +9,7 @@
9
9
  "homepage": "https://github.com/codenamev/claude_memory",
10
10
  "repository": "https://github.com/codenamev/claude_memory",
11
11
  "license": "MIT",
12
- "keywords": ["memory", "facts", "knowledge", "persistence", "long-term-memory"],
12
+ "keywords": ["memory", "architecture", "conventions", "decisions", "recall", "preferences", "long-term-memory"],
13
13
  "mcpServers": {
14
14
  "memory": {
15
15
  "command": "${CLAUDE_PLUGIN_ROOT}/scripts/serve-mcp.sh",
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env bash
2
+ # Generic hook delegate for claude-memory.
3
+ # Used by the Claude Code plugin to run hook subcommands.
4
+ # Usage: hook-runner.sh <subcommand> [args...]
5
+ # Exit 0 on missing binary to avoid blocking Claude Code.
6
+
7
+ set -uo pipefail
8
+
9
+ if command -v claude-memory > /dev/null 2>&1; then
10
+ exec claude-memory hook "$@"
11
+ else
12
+ echo "claude-memory gem not found. Install with: gem install claude_memory" >&2
13
+ exit 0
14
+ fi
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env bash
2
+ # Wrapper script for claude-memory MCP server.
3
+ # Used by the Claude Code plugin to launch the MCP server.
4
+ # Falls back to a JSON-RPC error if the gem is not installed.
5
+
6
+ set -euo pipefail
7
+
8
+ if command -v claude-memory > /dev/null 2>&1; then
9
+ exec claude-memory serve-mcp
10
+ else
11
+ # Return a JSON-RPC error so Claude Code surfaces it to the user
12
+ echo '{"jsonrpc":"2.0","id":1,"error":{"code":-32603,"message":"claude-memory gem not found. Install with: gem install claude_memory"}}'
13
+ exit 1
14
+ fi
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 4.0.1
1
+ 4.0.2
data/CHANGELOG.md CHANGED
@@ -4,6 +4,95 @@ All notable changes to this project will be documented in this file.
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.9.0] - 2026-04-16
8
+
9
+ ### Added
10
+
11
+ - `claude-memory reject <id_or_docid>` command + `memory.reject_fact` MCP tool — explicitly mark distiller hallucinations as wrong, closing associated conflicts
12
+ - `claude-memory restore --predicate NAME` command — recover facts that were superseded by obsolete single-value predicate classifications (uses Jaccard-based token overlap to distinguish bug-caused supersession from real corrections)
13
+ - MCP tool-call telemetry: `mcp_tool_calls` table records every tool invocation with timing, result counts, and error classification. `claude-memory stats --tools [--since DAYS]` for usage reporting. 90-day retention via Sweep
14
+ - `CLAUDE_CONFIG_DIR` env var support for non-standard Claude Code config locations
15
+ - Predicate synonym canonicalization at insert time (`has_convention` → `convention`, `primary_language` → `uses_language`). Prevents drift from fragmenting the knowledge graph
16
+ - Novel predicate warnings at insert time — logged when the Resolver encounters a predicate not in PredicatePolicy
17
+ - NullDistiller now emits `uses_language` facts for detected language entities
18
+ - Proactive memory recall guidance in MCP instructions — Claude now checks conventions before code generation, architecture before explanations, decisions before refactoring
19
+ - YARD documentation across 13 core source files (+473 lines)
20
+
21
+ ### Changed
22
+
23
+ - **`uses_framework` reclassified as multi-value** — real projects use multiple frameworks (Rails + Turbo + Tailwind). The prior single-value classification silently superseded valid facts in production databases. Run `claude-memory restore --predicate uses_framework` to recover affected facts
24
+ - `PredicatePolicy` is now the single source of truth for predicate vocabulary, snapshot section mapping, synonym canonicalization, and LLM guidance. `tool_definitions.rb`, `publish.rb`, and `distill-transcripts.md` all derive from the policy
25
+ - Predicate vocabulary curated from 13 → 8 based on multi-project usage data. Removed predicates (`preference`, `workflow`, `dependency`, `testing_strategy`, `tool_usage`, `ci_platform`, `primary_language`) had zero facts across all surveyed databases. They still work via DEFAULT_POLICY but are no longer advertised to the LLM
26
+ - `Registry::COMMANDS` stores `{class:, description:}` entries with direct class references instead of string class names
27
+ - Plugin and gem descriptions rewritten from mechanism-focused to outcome-focused
28
+
29
+ ### Fixed
30
+
31
+ - **`StatsCommand` broken in production** — used `Sequel.sqlite` which requires the unlisted `sqlite3` gem. Now uses the extralite adapter consistently
32
+ - Missing `embeddings` command in shell completion output
33
+
34
+ ### Upgrade Notes
35
+
36
+ **Schema**: v12 → v14 (two automatic migrations). Migration 013 adds `mcp_tool_calls` table. Migration 014 canonicalizes stale predicate names (`has_convention` → `convention`, `primary_language` → `uses_language`) in existing facts.
37
+
38
+ **Action required for `uses_framework` recovery**: If your project uses multiple frameworks (Rails + Turbo + Tailwind, etc.), past sessions may have superseded valid facts. After upgrading, run:
39
+
40
+ ```bash
41
+ claude-memory restore --predicate uses_framework --dry-run # preview
42
+ claude-memory restore --predicate uses_framework # restore
43
+ claude-memory restore --predicate uses_framework --scope global # if needed for global DB
44
+ ```
45
+
46
+ **Pruned predicates still work**: `preference`, `workflow`, `dependency`, `testing_strategy`, `tool_usage`, `ci_platform` fall through to the default multi-value policy. Existing facts with these predicates are unaffected. They'll appear as "novel" in `memory.stats` but function normally.
47
+
48
+ ## [0.8.0] - 2026-03-30
49
+
50
+ ### Added
51
+
52
+ **Three-Layer Distillation Pipeline**
53
+ - Automatic distillation via NullDistiller in ingest pipeline (Layer 1: regex-based, P95 < 5ms)
54
+ - Context hook injection for LLM-based extraction at SessionStart (Layer 2: Claude Code as distiller, zero extra cost)
55
+ - `/distill-transcripts` skill for manual deep extraction (Layer 3: on-demand, depth-aware prompts)
56
+ - `memory.undistilled` and `memory.mark_distilled` MCP tools for distillation tracking
57
+ - `Hook::DistillationRunner` extracted from Handler for context hook injection
58
+ - `TaskCompleted` and `TeammateIdle` hook events for ingest triggers
59
+ - Distillation metrics backfill on database initialization
60
+ - Doctor check for undistilled content
61
+ - Pending distillation count in `memory.status` output
62
+
63
+ **Recall Enhancements**
64
+ - Intent parameter for recall query disambiguation (#3)
65
+ - Retrieval score traces for semantic search (#5)
66
+ - Configurable embedding providers with dimension checking
67
+
68
+ **Hook Enhancements**
69
+ - `statusMessage` on all hooks for descriptive spinner text during hook execution
70
+ - `StopFailure` hook to capture transcript data even on session errors (rate limits, server errors)
71
+ - `Notification` hook with `idle_prompt` matcher for opportunistic sweep during idle
72
+
73
+ **New Commands & Skills**
74
+ - `install-skill` command and `memory-recall` agent (#8, #12)
75
+ - Shell completion command for bash and zsh (#18)
76
+
77
+ **Distillation Benchmark Results**
78
+ - NullDistiller: Concept Recall 0.952, Fact Precision/Recall 1.000 (31 test cases)
79
+ - Claude Code LLM: Concept Recall 0.902 (all 41 cases), 0.900 on semantic cases (vs 0.333 for regex)
80
+ - Average 1.6 facts stored per case across LLM extraction
81
+ - E2E distillation recall benchmark and extraction quality benchmarks
82
+ - Concept-based matching for distiller-agnostic benchmark comparison
83
+
84
+ ### Fixed
85
+
86
+ - `--allowedTools` added to `ClaudeCliRunner` for MCP tool permissions
87
+ - Test isolation for context hook when global database has facts
88
+
89
+ ### Internal
90
+ - Extracted `RetryHandler` and `SchemaManager` modules from `SQLiteStore`
91
+ - Extracted `Recall` into engine strategy pattern with `DualEngine`, `LegacyEngine`, and shared `QueryCore`
92
+ - Extracted `Tools` god object into 6 handler modules
93
+ - Added 36 specs for 5 previously untested files
94
+ - All 3 god objects eliminated, 0 files over 500 lines
95
+
7
96
  ## [0.7.1] - 2026-03-17
8
97
 
9
98
  ### Added
@@ -45,7 +134,7 @@ All notable changes to this project will be documented in this file.
45
134
  - Opt-out: set `CLAUDE_MEMORY_ISOLATE_WORKTREES=1` for per-worktree isolation
46
135
 
47
136
  **MCP Enhancements**
48
- - Tool annotations: `readOnlyHint`, `idempotentHint`, `destructiveHint` on all 21 tools
137
+ - Tool annotations: `readOnlyHint`, `idempotentHint`, `destructiveHint` on all 23 tools
49
138
  - Stdout protection: MCP server redirects `$stdout` to `$stderr` to prevent protocol corruption from accidental `puts`/`print` calls
50
139
  - Self-excluding agent conversations via `SELF_CONTEXT_MARKER` to prevent meta-pollution
51
140
 
data/CLAUDE.md CHANGED
@@ -15,6 +15,12 @@ ClaudeMemory is a Ruby gem that provides long-term, self-managed memory for Clau
15
15
 
16
16
  **Check memory before exploring code.** Use `memory.recall`, `memory.decisions`, `memory.architecture`, or `memory.conventions` to find existing knowledge before reading files.
17
17
 
18
+ ### Git Usage & Best Practices
19
+
20
+ - Before each commit, apply the quality-review skill
21
+ - Iteratively commit related changes with their tests
22
+
23
+
18
24
  ## Development Commands
19
25
 
20
26
  ### Setup
@@ -99,6 +105,18 @@ bin/run-evals --comparative # Run benchmarks with available tools
99
105
  bin/run-evals --comparative --setup-competitors # Install + run in one step
100
106
  ```
101
107
 
108
+ ### Distillation Extraction Accuracy
109
+
110
+ NullDistiller (regex, Layer 1):
111
+ - Concept Recall: 0.952 (regex-detectable entities/facts)
112
+ - Fact Precision: 1.000, Fact Recall: 1.000 (on 31 test cases)
113
+ - Pipeline latency: P95 < 5ms (medium text)
114
+
115
+ Claude Code (LLM, Layers 2+3):
116
+ - Concept Recall: 0.902 (all 41 cases)
117
+ - Concept Recall on semantic cases: 0.900 (vs NullDistiller's 0.333)
118
+ - Avg facts stored per case: 1.6
119
+
102
120
  ## Architecture
103
121
 
104
122
  ### Dual-Database System
@@ -123,6 +141,16 @@ Transcripts → Ingest → Index (FTS5)
123
141
  Publish → .claude/rules/claude_memory.generated.md
124
142
  ```
125
143
 
144
+ ### Three-Layer Distillation
145
+
146
+ The distillation pipeline operates at three levels of depth:
147
+
148
+ - **Layer 1: NullDistiller** (automatic, regex, free) — Runs in the ingest pipeline on every hook event. Extracts entities, facts, and scope hints using pattern matching. P95 latency < 5ms.
149
+ - **Layer 2: Context Hook Injection** (automatic, LLM, zero extra cost) — At SessionStart, undistilled content is injected into the session via `hookSpecificOutput.additionalContext` with extraction instructions. Claude Code itself acts as the distiller, extracting structured facts at no additional API cost.
150
+ - **Layer 3: `/distill-transcripts` Skill** (manual, on-demand) — Deep extraction triggered by the user. Processes undistilled content with depth-aware prompts (initial extraction, consolidation, contradiction resolution).
151
+
152
+ New MCP tools `memory.undistilled` and `memory.mark_distilled` support the pipeline by tracking which content items have been deeply distilled.
153
+
126
154
  ### Module Structure
127
155
 
128
156
  #### Application Layer
@@ -135,7 +163,7 @@ Transcripts → Ingest → Index (FTS5)
135
163
  - Each command is a separate class (HelpCommand, DoctorCommand, etc.)
136
164
  - All commands inherit from BaseCommand
137
165
  - Dependency injection for I/O (stdout, stderr, stdin)
138
- - 22 commands total, each focused on single responsibility
166
+ - 28 commands total, each focused on single responsibility
139
167
 
140
168
  - **`Configuration`**: Centralized ENV access (`configuration.rb`)
141
169
  - Single source of truth for paths and environment variables
@@ -144,7 +172,7 @@ Transcripts → Ingest → Index (FTS5)
144
172
  #### Core Domain Layer
145
173
 
146
174
  - **`Domain`**: Rich domain models with business logic (`domain/`)
147
- - `Fact`: Facts with validation, status checking (active?, superseded?)
175
+ - `Fact`: Facts with validation, status checking (active?, superseded?, rejected?)
148
176
  - `Entity`: Entities with type checking (database?, framework?)
149
177
  - `Provenance`: Evidence with strength checking (stated?, inferred?)
150
178
  - `Conflict`: Conflicts with status tracking (open?, resolved?)
@@ -160,7 +188,7 @@ Transcripts → Ingest → Index (FTS5)
160
188
  - **`Store`**: SQLite database access via Sequel (`store/`)
161
189
  - `SQLiteStore`: Database operations
162
190
  - `StoreManager`: Dual-database connection manager
163
- - Schema includes: content_items, entities, facts, provenance, fact_links, conflicts
191
+ - Schema includes: content_items, entities, facts, provenance, fact_links, conflicts, mcp_tool_calls
164
192
  - Transaction safety for multi-step operations
165
193
 
166
194
  - **`Infrastructure`**: I/O abstractions (`infrastructure/`)
@@ -183,7 +211,7 @@ Transcripts → Ingest → Index (FTS5)
183
211
 
184
212
  - **`Resolve`**: Truth maintenance and conflict resolution (`resolve/`)
185
213
  - Determines equivalence, supersession, or conflicts
186
- - PredicatePolicy controls single-value vs multi-value predicates
214
+ - PredicatePolicy: single source of truth for predicate vocabulary, cardinality, section mapping, and synonym canonicalization
187
215
  - Transaction safety for atomic operations
188
216
 
189
217
  - **`Recall`**: Query interface for facts (`recall.rb`)
@@ -198,12 +226,14 @@ Transcripts → Ingest → Index (FTS5)
198
226
  - Modes: shared (repo), local (uncommitted), home (user directory)
199
227
 
200
228
  - **`MCP`**: Model Context Protocol server and tools (`mcp/`)
201
- - Exposes memory tools to Claude Code (21 tools total)
229
+ - Exposes memory tools to Claude Code (24 tools total)
230
+ - `Telemetry`: Records tool invocations to `mcp_tool_calls` table for usage stats
202
231
  - Dual content/structuredContent responses with compact mode
203
232
 
204
233
  - **`Hook`**: Hook entrypoint handlers (`hook/`)
205
234
  - Reads stdin JSON from Claude Code hooks
206
235
  - Routes to ingest/sweep/publish commands
236
+ - `DistillationRunner`: Manages context hook injection with undistilled content for LLM extraction
207
237
 
208
238
  ### Database Schema
209
239
 
@@ -215,6 +245,7 @@ Key tables (defined in `sqlite_store.rb`):
215
245
  - `provenance`: Links facts to source content_items
216
246
  - `fact_links`: Supersession and conflict relationships
217
247
  - `conflicts`: Open contradictions
248
+ - `mcp_tool_calls`: MCP server tool invocation telemetry (schema v13)
218
249
 
219
250
  Facts include:
220
251
  - `scope`: "global" or "project" (determines applicability)
@@ -267,28 +298,34 @@ end
267
298
 
268
299
  ### Adding a New MCP Tool
269
300
 
270
- 1. Add tool definition to `MCP::Tools::TOOLS` hash
271
- 2. Implement handler in `MCP::Server#handle_tool_call`
272
- 3. Ensure tool queries appropriate database(s) via StoreManager
273
- 4. Add tests in `spec/claude_memory/mcp/`
301
+ 1. Add tool definition to `ToolDefinitions.all` array in `lib/claude_memory/mcp/tool_definitions.rb`
302
+ 2. Add `when` clause in `Tools#call` dispatch in `lib/claude_memory/mcp/tools.rb`
303
+ 3. Implement handler method in the appropriate handler module in `mcp/handlers/`
304
+ 4. Ensure tool queries appropriate database(s) via StoreManager
305
+ 5. Add tests in `spec/claude_memory/mcp/`
274
306
 
275
307
  ### Modifying Database Schema
276
308
 
277
- 1. Increment `SCHEMA_VERSION` in `sqlite_store.rb`
278
- 2. Add migration method (e.g., `migrate_to_v3!`)
279
- 3. Call migration in `run_migrations!`
309
+ 1. Increment `SCHEMA_VERSION` in `store/schema_manager.rb`
310
+ 2. Create a new Sequel migration file in `db/migrations/` (e.g., `013_add_mcp_tool_calls.rb`)
311
+ 3. Sequel::Migrator runs migrations automatically in `ensure_schema!`
280
312
  4. Test migration on existing database files
281
313
  5. Update documentation if schema changes affect external interfaces
282
314
 
283
- ### Adding a New Predicate Policy
315
+ ### Adding a New Predicate
316
+
317
+ Edit `PredicatePolicy::POLICIES` in `lib/claude_memory/resolve/predicate_policy.rb` — this is the single source of truth. Choose cardinality:
318
+
319
+ - **single** (exclusive: true): Facts supersede or conflict (e.g., `uses_database` — one per project)
320
+ - **multi** (exclusive: false): Facts accumulate (e.g., `convention`, `uses_framework`)
284
321
 
285
- Single-value predicates (like "uses_database") supersede old values. Multi-value predicates (like "depends_on") accumulate. Modify `PredicatePolicy.single?` to adjust behavior.
322
+ Also update `SECTION_MAP` if the predicate should appear in a specific snapshot section (`:decisions`, `:conventions`, `:constraints`). The `ToolDefinitions` predicate list updates automatically via `PredicatePolicy.known_predicates`. Add entries to `SYNONYMS` if the distiller might emit variant names.
286
323
 
287
324
  ## Important Files
288
325
 
289
326
  - `lib/claude_memory.rb`: Main module, requires, database path helpers
290
327
  - `lib/claude_memory/cli.rb`: Thin command router (41 lines)
291
- - `lib/claude_memory/commands/`: Individual command classes (22 commands)
328
+ - `lib/claude_memory/commands/`: Individual command classes (28 commands)
292
329
  - `lib/claude_memory/configuration.rb`: Centralized configuration and ENV access
293
330
  - `lib/claude_memory/domain/`: Domain models (Fact, Entity, Provenance, Conflict)
294
331
  - `lib/claude_memory/core/`: Value objects and null objects
@@ -303,12 +340,13 @@ Single-value predicates (like "uses_database") supersede old values. Multi-value
303
340
 
304
341
  The gem includes an MCP server (`claude-memory serve-mcp`) that exposes memory operations as tools. Configuration should be in `.mcp.json` at project root.
305
342
 
306
- Available MCP tools (21 total):
343
+ Available MCP tools (24 total):
307
344
  - **Query & Recall**: `memory.recall`, `memory.recall_index`, `memory.recall_details`, `memory.recall_semantic`, `memory.search_concepts`
308
345
  - **Provenance**: `memory.explain`, `memory.fact_graph`
309
346
  - **Shortcuts**: `memory.decisions`, `memory.conventions`, `memory.architecture`
310
347
  - **Context**: `memory.facts_by_tool`, `memory.facts_by_context`
311
- - **Management**: `memory.promote`, `memory.store_extraction`
348
+ - **Management**: `memory.promote`, `memory.reject_fact`, `memory.store_extraction`
349
+ - **Distillation**: `memory.undistilled`, `memory.mark_distilled`
312
350
  - **Monitoring**: `memory.status`, `memory.stats`, `memory.changes`, `memory.conflicts`
313
351
  - **Maintenance**: `memory.sweep_now`
314
352
  - **Discovery**: `memory.check_setup`, `memory.list_projects`
@@ -317,7 +355,7 @@ Available MCP tools (21 total):
317
355
 
318
356
  ClaudeMemory integrates with Claude Code via hooks in `.claude/settings.json`:
319
357
 
320
- - **Ingest hook**: Triggers on Stop/SessionStart/PreCompact/SessionEnd events
358
+ - **Ingest hook**: Triggers on Stop/SessionStart/PreCompact/SessionEnd/TaskCompleted/TeammateIdle events
321
359
  - Calls `claude-memory hook ingest` with stdin JSON
322
360
  - Reads transcript delta and updates both global and project databases
323
361
 
data/README.md CHANGED
@@ -83,6 +83,41 @@ Claude: "Based on my memory, you're using Rails with PostgreSQL..."
83
83
  👉 **[See Getting Started Guide →](docs/GETTING_STARTED.md)**
84
84
  👉 **[View Example Conversations →](docs/EXAMPLES.md)**
85
85
 
86
+ ## Why It Matters — Real A/B Test Results
87
+
88
+ We tested identical prompts with and without ClaudeMemory to measure the actual impact. Here's what we found:
89
+
90
+ ### Architecture Recall Without File Traversal
91
+
92
+ > **Prompt:** "Explain the conflict detection and resolution system. Answer from knowledge only — do not read any files."
93
+
94
+ | | Without Memory | With Memory |
95
+ |---|---|---|
96
+ | **Response** | 16 lines: "I don't know this codebase — let me read the files" | 76 lines: correct 4-role PredicatePolicy explanation, resolution pipeline, specific examples |
97
+ | **Outcome** | Honest refusal — zero architectural understanding | Deep understanding without touching the filesystem |
98
+
99
+ ### Correct File Paths vs Hallucinated Guesses
100
+
101
+ > **Prompt:** "I want to add a new predicate. Walk me through every file I need to update."
102
+
103
+ | | Without Memory | With Memory |
104
+ |---|---|---|
105
+ | **Response** | 6 steps targeting 3 **non-existent files** (`predicate.rb`, `predicate_synonyms.rb`, `json_schema.rb`) | 8 steps, all targeting **real files** with correct paths |
106
+ | **Outcome** | Plausible but wrong — would waste developer time | Actionable, correct, references actual commits |
107
+
108
+ ### Cross-Project Preferences
109
+
110
+ > **Prompt:** "What are my standard development environment preferences across all my projects?"
111
+
112
+ | | Without Memory | With Memory |
113
+ |---|---|---|
114
+ | **Response** | "I don't have stored knowledge of your preferences" | Lists 7 real preferences: iTerm2, tmux, VS Code, PostgreSQL, Redis, Docker |
115
+ | **Outcome** | Blank slate every session | Personalized from day one |
116
+
117
+ ### When Memory Doesn't Help
118
+
119
+ File-searchable questions ("what version is this?") and one-shot code generation without explicit recall don't benefit — `grep` is equally effective. Memory shines when the answer **isn't in any single file**: architecture spanning dozens of classes, conventions from past sessions, decisions with rationale, and user preferences.
120
+
86
121
  ## How It Works
87
122
 
88
123
  1. **You chat with Claude** - Tell it about your project
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Migration v13: Add mcp_tool_calls telemetry table
4
+ # Records every MCP server tool invocation for usage stats and ROI tracking.
5
+ # Distinct from `tool_calls` (v3), which stores Claude Code tool observations
6
+ # extracted from transcripts.
7
+ Sequel.migration do
8
+ up do
9
+ create_table?(:mcp_tool_calls) do
10
+ primary_key :id
11
+ String :tool_name, null: false
12
+ String :called_at, null: false
13
+ Integer :duration_ms, null: false
14
+ Integer :result_count
15
+ String :scope
16
+ String :error_class
17
+ end
18
+
19
+ run "CREATE INDEX IF NOT EXISTS idx_mcp_tool_calls_name_time ON mcp_tool_calls(tool_name, called_at)"
20
+ run "CREATE INDEX IF NOT EXISTS idx_mcp_tool_calls_called_at ON mcp_tool_calls(called_at)"
21
+ end
22
+
23
+ down do
24
+ drop_table?(:mcp_tool_calls)
25
+ end
26
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Migration v14: Canonicalize stale predicate names in existing facts.
4
+ #
5
+ # The predicate vocabulary was curated in 0.9.0 — synonym canonicalization
6
+ # now runs at insert time (Resolver), but existing facts with stale
7
+ # predicate names need a one-time rewrite so they appear in the correct
8
+ # snapshot sections and query results.
9
+ #
10
+ # This migration applies PredicatePolicy::SYNONYMS to all active facts.
11
+ # Reversible: the down migration is a no-op because we can't know the
12
+ # original predicate name after rewriting.
13
+ Sequel.migration do
14
+ up do
15
+ # Inline the synonym map so the migration is self-contained and
16
+ # doesn't break if PredicatePolicy::SYNONYMS changes later.
17
+ synonyms = {
18
+ "has_convention" => "convention",
19
+ "primary_language" => "uses_language"
20
+ }
21
+
22
+ synonyms.each do |from, to|
23
+ self[:facts].where(predicate: from).update(predicate: to)
24
+ end
25
+ end
26
+
27
+ down do
28
+ # No-op: can't reverse a predicate rename without storing the original.
29
+ end
30
+ end