claude_memory 0.7.0 → 0.8.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/memory.sqlite3-shm +0 -0
- data/.claude/memory.sqlite3-wal +0 -0
- data/.claude/settings.json +78 -6
- data/.claude/settings.local.json +5 -2
- data/.claude/skills/improve/SKILL.md +113 -25
- data/.claude-plugin/commands/distill-transcripts.md +98 -0
- data/.claude-plugin/commands/memory-recall.md +67 -0
- data/.claude-plugin/marketplace.json +1 -1
- data/.claude-plugin/plugin.json +1 -2
- data/CHANGELOG.md +74 -1
- data/CLAUDE.md +32 -6
- data/README.md +1 -1
- data/docs/improvements.md +51 -91
- data/docs/influence/lossless-claw.md +409 -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 +179 -0
- data/lib/claude_memory/commands/doctor_command.rb +2 -0
- data/lib/claude_memory/commands/help_command.rb +4 -0
- data/lib/claude_memory/commands/hook_command.rb +2 -1
- data/lib/claude_memory/commands/index_command.rb +100 -65
- 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 +3 -1
- data/lib/claude_memory/commands/skills/distill-transcripts.md +98 -0
- data/lib/claude_memory/commands/skills/memory-recall.md +67 -0
- 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/domain/provenance.rb +0 -1
- data/lib/claude_memory/embeddings/api_adapter.rb +96 -0
- data/lib/claude_memory/embeddings/dimension_check.rb +23 -0
- data/lib/claude_memory/embeddings/fastembed_adapter.rb +4 -0
- data/lib/claude_memory/embeddings/generator.rb +4 -0
- data/lib/claude_memory/embeddings/resolver.rb +18 -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/mcp/error_classifier.rb +171 -0
- data/lib/claude_memory/mcp/handlers/context_handlers.rb +38 -0
- data/lib/claude_memory/mcp/handlers/management_handlers.rb +145 -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 +202 -0
- data/lib/claude_memory/mcp/instructions_builder.rb +64 -5
- data/lib/claude_memory/mcp/query_guide.rb +51 -22
- data/lib/claude_memory/mcp/response_formatter.rb +4 -1
- data/lib/claude_memory/mcp/server.rb +1 -0
- data/lib/claude_memory/mcp/text_summary.rb +28 -1
- data/lib/claude_memory/mcp/tool_definitions.rb +33 -3
- data/lib/claude_memory/mcp/tool_helpers.rb +43 -0
- data/lib/claude_memory/mcp/tools.rb +47 -681
- 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 +29 -616
- 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 +85 -201
- data/lib/claude_memory/sweep/maintenance.rb +126 -0
- data/lib/claude_memory/sweep/sweeper.rb +81 -75
- data/lib/claude_memory/templates/hooks.example.json +26 -7
- data/lib/claude_memory/version.rb +1 -1
- data/lib/claude_memory.rb +12 -0
- data/v0.6.0.ANNOUNCE +32 -0
- metadata +27 -1
|
@@ -28,6 +28,8 @@ module ClaudeMemory
|
|
|
28
28
|
when "memory.recall_semantic" then summarize_semantic(result)
|
|
29
29
|
when "memory.search_concepts" then summarize_concepts(result)
|
|
30
30
|
when "memory.fact_graph" then summarize_fact_graph(result)
|
|
31
|
+
when "memory.undistilled" then summarize_undistilled(result)
|
|
32
|
+
when "memory.mark_distilled" then summarize_mark_distilled(result)
|
|
31
33
|
when "memory.check_setup" then summarize_check_setup(result)
|
|
32
34
|
else JSON.generate(result)
|
|
33
35
|
end
|
|
@@ -104,7 +106,8 @@ module ClaudeMemory
|
|
|
104
106
|
end
|
|
105
107
|
|
|
106
108
|
def self.summarize_sweep(result)
|
|
107
|
-
|
|
109
|
+
escalation = result[:escalation_level] ? " [#{result[:escalation_level]}]" : ""
|
|
110
|
+
"Sweep (#{result[:scope]})#{escalation}: #{result[:proposed_expired]} proposed expired, " \
|
|
108
111
|
"#{result[:disputed_expired]} disputed expired, " \
|
|
109
112
|
"#{result[:orphaned_deleted]} orphaned deleted, " \
|
|
110
113
|
"#{result[:content_pruned]} content pruned " \
|
|
@@ -121,6 +124,10 @@ module ClaudeMemory
|
|
|
121
124
|
"- #{name}: #{info[:facts_active]} active facts, #{info[:open_conflicts]} conflicts (schema v#{info[:schema_version]})"
|
|
122
125
|
end
|
|
123
126
|
end
|
|
127
|
+
|
|
128
|
+
pending = result[:pending_distillation] || 0
|
|
129
|
+
lines << "Pending distillation: #{pending}" if pending > 0
|
|
130
|
+
|
|
124
131
|
lines.join("\n")
|
|
125
132
|
end
|
|
126
133
|
|
|
@@ -232,6 +239,26 @@ module ClaudeMemory
|
|
|
232
239
|
lines.join("\n")
|
|
233
240
|
end
|
|
234
241
|
|
|
242
|
+
def self.summarize_undistilled(result)
|
|
243
|
+
items = result[:items] || []
|
|
244
|
+
return "No undistilled content items." if items.empty?
|
|
245
|
+
|
|
246
|
+
lines = ["#{result[:count]} undistilled content item(s):"]
|
|
247
|
+
items.each do |i|
|
|
248
|
+
ago = i[:occurred_ago] || "unknown"
|
|
249
|
+
lines << "- Item ##{i[:content_item_id]} (#{ago}): #{(i[:raw_text] || "")[0, 80]}..."
|
|
250
|
+
end
|
|
251
|
+
lines.join("\n")
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
def self.summarize_mark_distilled(result)
|
|
255
|
+
if result[:success]
|
|
256
|
+
"Marked content item ##{result[:content_item_id]} as distilled (#{result[:facts_extracted]} facts extracted)"
|
|
257
|
+
else
|
|
258
|
+
result[:error]
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
|
|
235
262
|
def self.summarize_check_setup(result)
|
|
236
263
|
lines = ["Setup status: #{result[:status]}"]
|
|
237
264
|
lines << "Version: #{result[:version][:current]} (latest: #{result[:version][:latest]})"
|
|
@@ -25,6 +25,7 @@ module ClaudeMemory
|
|
|
25
25
|
type: "object",
|
|
26
26
|
properties: {
|
|
27
27
|
query: {type: "string", description: "Search query for existing knowledge (e.g., 'authentication flow', 'error handling', 'database setup')"},
|
|
28
|
+
intent: {type: "string", description: "Optional intent to disambiguate the query (e.g., 'migration' or 'performance' when query is 'database'). Steers search without replacing the query."},
|
|
28
29
|
limit: {type: "integer", description: "Max results", default: 10},
|
|
29
30
|
scope: {type: "string", enum: ["all", "global", "project"], description: "Filter by scope: 'all' (default), 'global', or 'project'", default: "all"},
|
|
30
31
|
compact: {type: "boolean", description: "Omit provenance receipts for ~60% smaller responses (~800 → ~300 tokens/result)", default: false}
|
|
@@ -40,6 +41,7 @@ module ClaudeMemory
|
|
|
40
41
|
type: "object",
|
|
41
42
|
properties: {
|
|
42
43
|
query: {type: "string", description: "Search query for existing knowledge (e.g., 'client errors', 'database choice')"},
|
|
44
|
+
intent: {type: "string", description: "Optional intent to disambiguate the query (e.g., 'schema' or 'optimization' when query is 'database'). Steers search without replacing the query."},
|
|
43
45
|
limit: {type: "integer", description: "Maximum results to return", default: 20},
|
|
44
46
|
scope: {type: "string", enum: ["all", "global", "project"], description: "Scope: 'all' (both), 'global' (user-wide), 'project' (current only)", default: "all"}
|
|
45
47
|
},
|
|
@@ -99,12 +101,13 @@ module ClaudeMemory
|
|
|
99
101
|
},
|
|
100
102
|
{
|
|
101
103
|
name: "memory.sweep_now",
|
|
102
|
-
description: "Run maintenance sweep on a database",
|
|
104
|
+
description: "Run maintenance sweep on a database. Use escalate: true for guaranteed progress (normal → aggressive → fallback).",
|
|
103
105
|
inputSchema: {
|
|
104
106
|
type: "object",
|
|
105
107
|
properties: {
|
|
106
108
|
budget_seconds: {type: "integer", default: 5},
|
|
107
|
-
scope: {type: "string", enum: ["global", "project"], default: "project"}
|
|
109
|
+
scope: {type: "string", enum: ["global", "project"], default: "project"},
|
|
110
|
+
escalate: {type: "boolean", default: false, description: "Enable three-level escalation (normal → aggressive → fallback) to guarantee progress"}
|
|
108
111
|
}
|
|
109
112
|
},
|
|
110
113
|
annotations: WRITE
|
|
@@ -264,10 +267,12 @@ module ClaudeMemory
|
|
|
264
267
|
type: "object",
|
|
265
268
|
properties: {
|
|
266
269
|
query: {type: "string", description: "Search query"},
|
|
270
|
+
intent: {type: "string", description: "Optional intent to disambiguate the query (e.g., 'security' when query is 'authentication'). Disables BM25 shortcut to ensure vector search runs."},
|
|
267
271
|
mode: {type: "string", enum: ["vector", "text", "both"], default: "both", description: "Search mode: vector (embeddings), text (FTS), or both (hybrid)"},
|
|
268
272
|
limit: {type: "integer", default: 10, description: "Maximum results to return"},
|
|
269
273
|
scope: {type: "string", enum: ["all", "global", "project"], default: "all", description: "Filter by scope"},
|
|
270
|
-
compact: {type: "boolean", description: "Omit provenance receipts for ~60% smaller responses (~800 → ~300 tokens/result)", default: false}
|
|
274
|
+
compact: {type: "boolean", description: "Omit provenance receipts for ~60% smaller responses (~800 → ~300 tokens/result)", default: false},
|
|
275
|
+
explain: {type: "boolean", description: "Include per-result score traces showing FTS rank, vector similarity, and RRF contribution", default: false}
|
|
271
276
|
},
|
|
272
277
|
required: ["query"]
|
|
273
278
|
},
|
|
@@ -308,6 +313,31 @@ module ClaudeMemory
|
|
|
308
313
|
},
|
|
309
314
|
annotations: READ_ONLY
|
|
310
315
|
},
|
|
316
|
+
{
|
|
317
|
+
name: "memory.undistilled",
|
|
318
|
+
description: "List content items not yet deeply distilled. Returns raw transcript text for knowledge extraction.",
|
|
319
|
+
inputSchema: {
|
|
320
|
+
type: "object",
|
|
321
|
+
properties: {
|
|
322
|
+
limit: {type: "integer", default: 3, description: "Max items to return"},
|
|
323
|
+
min_length: {type: "integer", default: 200, description: "Min text length (skip tiny deltas)"}
|
|
324
|
+
}
|
|
325
|
+
},
|
|
326
|
+
annotations: READ_ONLY
|
|
327
|
+
},
|
|
328
|
+
{
|
|
329
|
+
name: "memory.mark_distilled",
|
|
330
|
+
description: "Mark a content item as distilled after extracting facts from it.",
|
|
331
|
+
inputSchema: {
|
|
332
|
+
type: "object",
|
|
333
|
+
properties: {
|
|
334
|
+
content_item_id: {type: "integer", description: "ID of the distilled content item"},
|
|
335
|
+
facts_extracted: {type: "integer", default: 0, description: "Number of facts extracted"}
|
|
336
|
+
},
|
|
337
|
+
required: ["content_item_id"]
|
|
338
|
+
},
|
|
339
|
+
annotations: WRITE_IDEMPOTENT
|
|
340
|
+
},
|
|
311
341
|
{
|
|
312
342
|
name: "memory.check_setup",
|
|
313
343
|
description: "Check ClaudeMemory initialization status. Returns version info, issues found, and recommendations.",
|
|
@@ -75,6 +75,49 @@ module ClaudeMemory
|
|
|
75
75
|
def extract_limit(args, default: 10)
|
|
76
76
|
args["limit"] || default
|
|
77
77
|
end
|
|
78
|
+
|
|
79
|
+
# Extract optional intent parameter for query disambiguation
|
|
80
|
+
# @param args [Hash] Tool arguments
|
|
81
|
+
# @return [String, nil] Intent string or nil if not provided/blank
|
|
82
|
+
def extract_intent(args)
|
|
83
|
+
intent = args["intent"]
|
|
84
|
+
(intent.nil? || intent.to_s.strip.empty?) ? nil : intent.to_s.strip
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Collect undistilled content items from both stores (or legacy store)
|
|
88
|
+
# @param limit [Integer] Maximum items to return
|
|
89
|
+
# @param min_length [Integer] Minimum byte_len to include
|
|
90
|
+
# @return [Array<Hash>] Undistilled items sorted by recency
|
|
91
|
+
def collect_undistilled_items(limit:, min_length: 200)
|
|
92
|
+
if @manager
|
|
93
|
+
stores = []
|
|
94
|
+
stores << @manager.project_store if @manager.project_exists?
|
|
95
|
+
stores << @manager.global_store if @manager.global_exists?
|
|
96
|
+
items = stores.flat_map { |s| s.undistilled_content_items(limit: limit, min_length: min_length) }
|
|
97
|
+
items.sort_by { |i| i[:occurred_at] || "" }.reverse.first(limit)
|
|
98
|
+
elsif @legacy_store
|
|
99
|
+
@legacy_store.undistilled_content_items(limit: limit, min_length: min_length)
|
|
100
|
+
else
|
|
101
|
+
[]
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Find the store containing a given content item
|
|
106
|
+
# @param content_item_id [Integer] Content item ID to locate
|
|
107
|
+
# @return [Store::SQLiteStore, nil] The store containing the item, or nil
|
|
108
|
+
def find_store_for_content_item(content_item_id)
|
|
109
|
+
if @manager
|
|
110
|
+
if @manager.project_store&.content_items&.where(id: content_item_id)&.any?
|
|
111
|
+
@manager.project_store
|
|
112
|
+
elsif @manager.global_store&.content_items&.where(id: content_item_id)&.any?
|
|
113
|
+
@manager.global_store
|
|
114
|
+
end
|
|
115
|
+
elsif @legacy_store
|
|
116
|
+
if @legacy_store.content_items.where(id: content_item_id).any?
|
|
117
|
+
@legacy_store
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
78
121
|
end
|
|
79
122
|
end
|
|
80
123
|
end
|