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.
- checksums.yaml +4 -4
- data/.claude/memory.sqlite3 +0 -0
- data/.claude/rules/claude_memory.generated.md +32 -2
- data/.claude/settings.json +65 -15
- data/.claude/settings.local.json +5 -2
- data/.claude/skills/improve/SKILL.md +113 -25
- data/.claude/skills/upgrade-dependencies/SKILL.md +154 -0
- data/.claude-plugin/commands/distill-transcripts.md +98 -0
- data/.claude-plugin/commands/memory-recall.md +67 -0
- data/.claude-plugin/marketplace.json +2 -2
- data/.claude-plugin/plugin.json +3 -3
- data/.claude-plugin/scripts/hook-runner.sh +14 -0
- data/.claude-plugin/scripts/serve-mcp.sh +14 -0
- data/.ruby-version +1 -1
- data/CHANGELOG.md +90 -1
- data/CLAUDE.md +56 -18
- data/README.md +35 -0
- data/db/migrations/013_add_mcp_tool_calls.rb +26 -0
- data/db/migrations/014_canonicalize_predicates.rb +30 -0
- data/docs/improvements.md +74 -74
- data/docs/influence/claude-mem.md +1 -0
- data/docs/influence/claude-supermemory.md +1 -0
- data/docs/influence/episodic-memory.md +1 -0
- data/docs/influence/grepai.md +1 -0
- data/docs/influence/kbs.md +1 -0
- data/docs/influence/lossless-claw.md +1 -0
- data/docs/influence/qmd.md +1 -0
- data/docs/quality_review.md +119 -224
- data/hooks/hooks.json +39 -7
- data/lib/claude_memory/commands/checks/distill_check.rb +61 -0
- data/lib/claude_memory/commands/checks/hooks_check.rb +2 -2
- data/lib/claude_memory/commands/checks/vec_check.rb +2 -1
- data/lib/claude_memory/commands/completion_command.rb +149 -0
- data/lib/claude_memory/commands/doctor_command.rb +2 -0
- data/lib/claude_memory/commands/embeddings_command.rb +198 -0
- data/lib/claude_memory/commands/help_command.rb +12 -1
- data/lib/claude_memory/commands/hook_command.rb +2 -1
- data/lib/claude_memory/commands/index_command.rb +85 -78
- data/lib/claude_memory/commands/initializers/database_ensurer.rb +16 -0
- data/lib/claude_memory/commands/initializers/global_initializer.rb +2 -1
- data/lib/claude_memory/commands/initializers/hooks_configurator.rb +55 -11
- data/lib/claude_memory/commands/initializers/project_initializer.rb +2 -1
- data/lib/claude_memory/commands/install_skill_command.rb +78 -0
- data/lib/claude_memory/commands/registry.rb +47 -32
- data/lib/claude_memory/commands/reject_command.rb +62 -0
- data/lib/claude_memory/commands/restore_command.rb +77 -0
- data/lib/claude_memory/commands/skills/distill-transcripts.md +102 -0
- data/lib/claude_memory/commands/skills/memory-recall.md +67 -0
- data/lib/claude_memory/commands/stats_command.rb +98 -2
- data/lib/claude_memory/configuration.rb +14 -1
- data/lib/claude_memory/core/fact_ranker.rb +2 -2
- data/lib/claude_memory/core/rr_fusion.rb +23 -6
- data/lib/claude_memory/core/snippet_extractor.rb +7 -3
- data/lib/claude_memory/core/text_builder.rb +11 -0
- data/lib/claude_memory/distill/json_schema.md +8 -4
- data/lib/claude_memory/distill/null_distiller.rb +2 -0
- data/lib/claude_memory/domain/entity.rb +13 -1
- data/lib/claude_memory/domain/fact.rb +26 -2
- data/lib/claude_memory/domain/provenance.rb +0 -1
- data/lib/claude_memory/embeddings/api_adapter.rb +97 -0
- data/lib/claude_memory/embeddings/dimension_check.rb +23 -0
- data/lib/claude_memory/embeddings/fastembed_adapter.rb +46 -12
- data/lib/claude_memory/embeddings/generator.rb +4 -0
- data/lib/claude_memory/embeddings/inspector.rb +91 -0
- data/lib/claude_memory/embeddings/model_registry.rb +210 -0
- data/lib/claude_memory/embeddings/resolver.rb +44 -0
- data/lib/claude_memory/hook/context_injector.rb +58 -2
- data/lib/claude_memory/hook/distillation_runner.rb +46 -0
- data/lib/claude_memory/hook/handler.rb +11 -2
- data/lib/claude_memory/index/vector_index.rb +15 -2
- data/lib/claude_memory/infrastructure/schema_validator.rb +3 -3
- data/lib/claude_memory/ingest/ingester.rb +17 -0
- data/lib/claude_memory/mcp/handlers/context_handlers.rb +38 -0
- data/lib/claude_memory/mcp/handlers/management_handlers.rb +169 -0
- data/lib/claude_memory/mcp/handlers/query_handlers.rb +115 -0
- data/lib/claude_memory/mcp/handlers/setup_handlers.rb +211 -0
- data/lib/claude_memory/mcp/handlers/shortcut_handlers.rb +37 -0
- data/lib/claude_memory/mcp/handlers/stats_handlers.rb +205 -0
- data/lib/claude_memory/mcp/instructions_builder.rb +19 -1
- data/lib/claude_memory/mcp/query_guide.rb +10 -0
- data/lib/claude_memory/mcp/response_formatter.rb +1 -0
- data/lib/claude_memory/mcp/server.rb +22 -1
- data/lib/claude_memory/mcp/telemetry.rb +86 -0
- data/lib/claude_memory/mcp/text_summary.rb +26 -0
- data/lib/claude_memory/mcp/tool_definitions.rb +116 -4
- data/lib/claude_memory/mcp/tool_helpers.rb +43 -0
- data/lib/claude_memory/mcp/tools.rb +50 -679
- data/lib/claude_memory/publish.rb +40 -5
- data/lib/claude_memory/recall/dual_engine.rb +105 -0
- data/lib/claude_memory/recall/legacy_engine.rb +138 -0
- data/lib/claude_memory/recall/query_core.rb +371 -0
- data/lib/claude_memory/recall.rb +121 -673
- data/lib/claude_memory/resolve/predicate_policy.rb +63 -3
- data/lib/claude_memory/resolve/resolver.rb +43 -0
- data/lib/claude_memory/shortcuts.rb +4 -4
- data/lib/claude_memory/store/retry_handler.rb +61 -0
- data/lib/claude_memory/store/schema_manager.rb +68 -0
- data/lib/claude_memory/store/sqlite_store.rb +334 -201
- data/lib/claude_memory/store/store_manager.rb +50 -1
- data/lib/claude_memory/sweep/maintenance.rb +115 -1
- data/lib/claude_memory/sweep/sweeper.rb +3 -0
- data/lib/claude_memory/templates/hooks.example.json +26 -7
- data/lib/claude_memory/version.rb +1 -1
- data/lib/claude_memory.rb +16 -0
- metadata +48 -8
- data/.claude/memory.sqlite3-shm +0 -0
- 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.
|
|
10
|
+
"version": "0.9.0",
|
|
11
11
|
"source": "./",
|
|
12
|
-
"description": "Long-term
|
|
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
|
]
|
data/.claude-plugin/plugin.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-memory",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Long-term
|
|
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", "
|
|
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
|
+
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
|
|
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
|
-
-
|
|
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
|
|
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 (
|
|
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 `
|
|
271
|
-
2.
|
|
272
|
-
3.
|
|
273
|
-
4.
|
|
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 `
|
|
278
|
-
2.
|
|
279
|
-
3.
|
|
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
|
|
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
|
-
|
|
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 (
|
|
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 (
|
|
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
|