claude_memory 0.8.0 → 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 +30 -52
- data/.claude/settings.local.json +3 -1
- data/.claude/skills/upgrade-dependencies/SKILL.md +154 -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 +41 -0
- data/CLAUDE.md +31 -17
- 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 +58 -20
- 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/lib/claude_memory/commands/completion_command.rb +1 -31
- data/lib/claude_memory/commands/embeddings_command.rb +198 -0
- data/lib/claude_memory/commands/help_command.rb +8 -1
- data/lib/claude_memory/commands/registry.rb +47 -34
- 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 +5 -1
- data/lib/claude_memory/commands/stats_command.rb +98 -2
- data/lib/claude_memory/configuration.rb +14 -1
- 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/embeddings/api_adapter.rb +5 -4
- data/lib/claude_memory/embeddings/fastembed_adapter.rb +43 -13
- 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 +32 -6
- data/lib/claude_memory/ingest/ingester.rb +17 -0
- data/lib/claude_memory/mcp/handlers/management_handlers.rb +24 -0
- data/lib/claude_memory/mcp/handlers/stats_handlers.rb +5 -2
- data/lib/claude_memory/mcp/instructions_builder.rb +17 -0
- data/lib/claude_memory/mcp/server.rb +22 -1
- data/lib/claude_memory/mcp/telemetry.rb +86 -0
- data/lib/claude_memory/mcp/tool_definitions.rb +86 -3
- data/lib/claude_memory/mcp/tools.rb +10 -0
- data/lib/claude_memory/publish.rb +40 -5
- data/lib/claude_memory/recall.rb +81 -0
- data/lib/claude_memory/resolve/predicate_policy.rb +63 -3
- data/lib/claude_memory/resolve/resolver.rb +43 -0
- data/lib/claude_memory/store/schema_manager.rb +1 -1
- data/lib/claude_memory/store/sqlite_store.rb +250 -1
- 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/version.rb +1 -1
- data/lib/claude_memory.rb +5 -0
- metadata +26 -8
- data/.claude/memory.sqlite3-shm +0 -0
- data/.claude/memory.sqlite3-wal +0 -0
|
@@ -8,10 +8,16 @@ module ClaudeMemory
|
|
|
8
8
|
#
|
|
9
9
|
# Source: QMD v2.0.1 Maintenance class pattern
|
|
10
10
|
class Maintenance
|
|
11
|
+
# Short / noise tokens dropped before Jaccard comparison.
|
|
12
|
+
# Intentionally minimal — we want conservative token extraction that
|
|
13
|
+
# still treats "Rails 8.0" and "Rails 8.1" as overlapping.
|
|
14
|
+
RESTORE_STOPWORDS = %w[for the and with via of in on to by is are].to_set.freeze
|
|
15
|
+
RESTORE_JACCARD_THRESHOLD = 0.5
|
|
11
16
|
DEFAULT_CONFIG = {
|
|
12
17
|
proposed_fact_ttl_days: 14,
|
|
13
18
|
disputed_fact_ttl_days: 30,
|
|
14
|
-
content_retention_days: 30
|
|
19
|
+
content_retention_days: 30,
|
|
20
|
+
mcp_tool_call_retention_days: 90
|
|
15
21
|
}.freeze
|
|
16
22
|
|
|
17
23
|
attr_reader :store
|
|
@@ -96,6 +102,85 @@ module ClaudeMemory
|
|
|
96
102
|
0
|
|
97
103
|
end
|
|
98
104
|
|
|
105
|
+
# Restore superseded facts in a (subject, predicate) slot that were
|
|
106
|
+
# only superseded because of an obsolete single-value classification.
|
|
107
|
+
# Uses Jaccard-based token overlap to distinguish bug-superseded facts
|
|
108
|
+
# (token-disjoint siblings) from legitimate corrections (overlapping
|
|
109
|
+
# siblings).
|
|
110
|
+
#
|
|
111
|
+
# Refuses to run on predicates still classified as single-value — they
|
|
112
|
+
# should stay superseded by design.
|
|
113
|
+
#
|
|
114
|
+
# Never touches status: "rejected" facts (explicit user decisions).
|
|
115
|
+
#
|
|
116
|
+
# @return [Hash] {inspected, restored, skipped_ambiguous, skipped_rejected, decisions}
|
|
117
|
+
def restore_multi_value_supersessions(predicate:, dry_run: false)
|
|
118
|
+
if ClaudeMemory::Resolve::PredicatePolicy.single?(predicate)
|
|
119
|
+
raise ArgumentError, "Predicate '#{predicate}' is still classified single-value; refusing to restore"
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
result = {inspected: 0, restored: 0, skipped_ambiguous: 0, skipped_rejected: 0, decisions: []}
|
|
123
|
+
|
|
124
|
+
rows_by_subject = @store.facts
|
|
125
|
+
.where(predicate: predicate)
|
|
126
|
+
.exclude(status: "rejected")
|
|
127
|
+
.select(:id, :subject_entity_id, :object_literal, :status)
|
|
128
|
+
.all
|
|
129
|
+
.group_by { |r| r[:subject_entity_id] }
|
|
130
|
+
|
|
131
|
+
rejected_by_subject = @store.facts
|
|
132
|
+
.where(predicate: predicate, status: "rejected")
|
|
133
|
+
.select(:id, :subject_entity_id, :object_literal)
|
|
134
|
+
.all
|
|
135
|
+
.group_by { |r| r[:subject_entity_id] }
|
|
136
|
+
|
|
137
|
+
@store.db.transaction do
|
|
138
|
+
rows_by_subject.each do |subject_id, rows|
|
|
139
|
+
rejected_rows = rejected_by_subject[subject_id] || []
|
|
140
|
+
siblings = rows + rejected_rows
|
|
141
|
+
|
|
142
|
+
rows.each do |candidate|
|
|
143
|
+
next unless candidate[:status] == "superseded"
|
|
144
|
+
result[:inspected] += 1
|
|
145
|
+
|
|
146
|
+
candidate_tokens = restore_tokenize(candidate[:object_literal])
|
|
147
|
+
ambiguous_against = find_overlapping_siblings(candidate, siblings, candidate_tokens)
|
|
148
|
+
|
|
149
|
+
if ambiguous_against.empty?
|
|
150
|
+
result[:restored] += 1
|
|
151
|
+
result[:decisions] << {
|
|
152
|
+
subject_entity_id: subject_id,
|
|
153
|
+
fact_id: candidate[:id],
|
|
154
|
+
object: candidate[:object_literal],
|
|
155
|
+
action: :restore
|
|
156
|
+
}
|
|
157
|
+
restore_fact!(candidate[:id]) unless dry_run
|
|
158
|
+
else
|
|
159
|
+
result[:skipped_ambiguous] += 1
|
|
160
|
+
result[:decisions] << {
|
|
161
|
+
subject_entity_id: subject_id,
|
|
162
|
+
fact_id: candidate[:id],
|
|
163
|
+
object: candidate[:object_literal],
|
|
164
|
+
action: :skip_ambiguous,
|
|
165
|
+
overlaps_with: ambiguous_against.map { |s| s[:object_literal] }
|
|
166
|
+
}
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
result
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# Delete MCP tool-call telemetry rows older than retention window.
|
|
176
|
+
# Returns: Integer count of deleted rows (0 if table missing).
|
|
177
|
+
def prune_old_mcp_tool_calls
|
|
178
|
+
return 0 unless @store.db.table_exists?(:mcp_tool_calls)
|
|
179
|
+
|
|
180
|
+
cutoff = cutoff_time(@config[:mcp_tool_call_retention_days])
|
|
181
|
+
@store.mcp_tool_calls.where { called_at < cutoff }.delete
|
|
182
|
+
end
|
|
183
|
+
|
|
99
184
|
# Checkpoint the SQLite WAL file for compaction.
|
|
100
185
|
# Returns: true
|
|
101
186
|
def checkpoint_wal
|
|
@@ -112,6 +197,35 @@ module ClaudeMemory
|
|
|
112
197
|
|
|
113
198
|
private
|
|
114
199
|
|
|
200
|
+
def restore_tokenize(text)
|
|
201
|
+
return Set.new if text.nil?
|
|
202
|
+
text.downcase
|
|
203
|
+
.scan(/[a-z0-9]+/)
|
|
204
|
+
.reject { |t| t.length <= 2 || RESTORE_STOPWORDS.include?(t) }
|
|
205
|
+
.to_set
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def restore_jaccard(a, b)
|
|
209
|
+
return 0.0 if a.empty? && b.empty?
|
|
210
|
+
intersection = (a & b).size
|
|
211
|
+
union = (a | b).size
|
|
212
|
+
return 0.0 if union.zero?
|
|
213
|
+
intersection.to_f / union
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def find_overlapping_siblings(candidate, siblings, candidate_tokens)
|
|
217
|
+
siblings.select do |other|
|
|
218
|
+
next false if other[:id] == candidate[:id]
|
|
219
|
+
other_tokens = restore_tokenize(other[:object_literal])
|
|
220
|
+
restore_jaccard(candidate_tokens, other_tokens) >= RESTORE_JACCARD_THRESHOLD
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
def restore_fact!(fact_id)
|
|
225
|
+
@store.facts.where(id: fact_id).update(status: "active", valid_to: nil)
|
|
226
|
+
@store.fact_links.where(to_fact_id: fact_id, link_type: "supersedes").delete
|
|
227
|
+
end
|
|
228
|
+
|
|
115
229
|
def cutoff_time(days)
|
|
116
230
|
(Time.now - days * 86400).utc.iso8601
|
|
117
231
|
end
|
|
@@ -7,6 +7,7 @@ module ClaudeMemory
|
|
|
7
7
|
proposed_fact_ttl_days: 14,
|
|
8
8
|
disputed_fact_ttl_days: 30,
|
|
9
9
|
content_retention_days: 30,
|
|
10
|
+
mcp_tool_call_retention_days: 90,
|
|
10
11
|
default_budget_seconds: 5
|
|
11
12
|
}.freeze
|
|
12
13
|
|
|
@@ -29,6 +30,7 @@ module ClaudeMemory
|
|
|
29
30
|
disputed_facts_expired: 0,
|
|
30
31
|
orphaned_provenance_deleted: 0,
|
|
31
32
|
old_content_pruned: 0,
|
|
33
|
+
mcp_tool_calls_pruned: 0,
|
|
32
34
|
escalation_level: :normal
|
|
33
35
|
}
|
|
34
36
|
|
|
@@ -38,6 +40,7 @@ module ClaudeMemory
|
|
|
38
40
|
run_if_within_budget { @stats[:disputed_facts_expired] = maintenance.expire_disputed_facts }
|
|
39
41
|
run_if_within_budget { @stats[:orphaned_provenance_deleted] = maintenance.prune_orphaned_provenance }
|
|
40
42
|
run_if_within_budget { @stats[:old_content_pruned] = maintenance.prune_old_content }
|
|
43
|
+
run_if_within_budget { @stats[:mcp_tool_calls_pruned] = maintenance.prune_old_mcp_tool_calls }
|
|
41
44
|
run_if_within_budget { @stats[:vec_backfilled] = maintenance.backfill_vec_index }
|
|
42
45
|
run_if_within_budget { @stats[:vec_cleaned] = maintenance.cleanup_vec_expired }
|
|
43
46
|
run_if_within_budget { @stats[:wal_checkpointed] = maintenance.checkpoint_wal }
|
data/lib/claude_memory.rb
CHANGED
|
@@ -70,6 +70,9 @@ require_relative "claude_memory/commands/export_command"
|
|
|
70
70
|
require_relative "claude_memory/commands/git_lfs_command"
|
|
71
71
|
require_relative "claude_memory/commands/install_skill_command"
|
|
72
72
|
require_relative "claude_memory/commands/completion_command"
|
|
73
|
+
require_relative "claude_memory/commands/embeddings_command"
|
|
74
|
+
require_relative "claude_memory/commands/reject_command"
|
|
75
|
+
require_relative "claude_memory/commands/restore_command"
|
|
73
76
|
require_relative "claude_memory/commands/registry"
|
|
74
77
|
require_relative "claude_memory/cli"
|
|
75
78
|
require_relative "claude_memory/configuration"
|
|
@@ -80,6 +83,8 @@ require_relative "claude_memory/domain/fact"
|
|
|
80
83
|
require_relative "claude_memory/domain/entity"
|
|
81
84
|
require_relative "claude_memory/domain/provenance"
|
|
82
85
|
require_relative "claude_memory/domain/conflict"
|
|
86
|
+
require_relative "claude_memory/embeddings/model_registry"
|
|
87
|
+
require_relative "claude_memory/embeddings/inspector"
|
|
83
88
|
require_relative "claude_memory/embeddings/generator"
|
|
84
89
|
require_relative "claude_memory/embeddings/fastembed_adapter"
|
|
85
90
|
require_relative "claude_memory/embeddings/api_adapter"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: claude_memory
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.9.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Valentino Stoll
|
|
@@ -15,14 +15,14 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - "~>"
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: '5.
|
|
18
|
+
version: '5.102'
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - "~>"
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: '5.
|
|
25
|
+
version: '5.102'
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: extralite
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -44,6 +44,9 @@ dependencies:
|
|
|
44
44
|
- - "~>"
|
|
45
45
|
- !ruby/object:Gem::Version
|
|
46
46
|
version: '0.1'
|
|
47
|
+
- - ">="
|
|
48
|
+
- !ruby/object:Gem::Version
|
|
49
|
+
version: 0.1.9
|
|
47
50
|
type: :runtime
|
|
48
51
|
prerelease: false
|
|
49
52
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -51,8 +54,13 @@ dependencies:
|
|
|
51
54
|
- - "~>"
|
|
52
55
|
- !ruby/object:Gem::Version
|
|
53
56
|
version: '0.1'
|
|
54
|
-
|
|
55
|
-
|
|
57
|
+
- - ">="
|
|
58
|
+
- !ruby/object:Gem::Version
|
|
59
|
+
version: 0.1.9
|
|
60
|
+
description: Gives Claude Code persistent memory across sessions. Claude recalls your
|
|
61
|
+
codebase architecture without file traversal, enforces project conventions during
|
|
62
|
+
code generation, tracks decisions with rationale, and remembers your preferences
|
|
63
|
+
across all projects. Zero-config via Hooks + MCP.
|
|
56
64
|
email:
|
|
57
65
|
- v@codenamev.com
|
|
58
66
|
executables:
|
|
@@ -64,11 +72,11 @@ files:
|
|
|
64
72
|
- ".claude-plugin/commands/memory-recall.md"
|
|
65
73
|
- ".claude-plugin/marketplace.json"
|
|
66
74
|
- ".claude-plugin/plugin.json"
|
|
75
|
+
- ".claude-plugin/scripts/hook-runner.sh"
|
|
76
|
+
- ".claude-plugin/scripts/serve-mcp.sh"
|
|
67
77
|
- ".claude.json"
|
|
68
78
|
- ".claude/CLAUDE.md"
|
|
69
79
|
- ".claude/memory.sqlite3"
|
|
70
|
-
- ".claude/memory.sqlite3-shm"
|
|
71
|
-
- ".claude/memory.sqlite3-wal"
|
|
72
80
|
- ".claude/output-styles/memory-aware.md"
|
|
73
81
|
- ".claude/rules/claude_memory.generated.md"
|
|
74
82
|
- ".claude/settings.json"
|
|
@@ -88,6 +96,7 @@ files:
|
|
|
88
96
|
- ".claude/skills/study-repo/SKILL.md"
|
|
89
97
|
- ".claude/skills/study-repo/analysis-template.md"
|
|
90
98
|
- ".claude/skills/study-repo/focus-examples.md"
|
|
99
|
+
- ".claude/skills/upgrade-dependencies/SKILL.md"
|
|
91
100
|
- ".gitattributes"
|
|
92
101
|
- ".lefthook/map_specs.rb"
|
|
93
102
|
- ".mcp.json"
|
|
@@ -114,6 +123,8 @@ files:
|
|
|
114
123
|
- db/migrations/010_add_llm_cache.rb
|
|
115
124
|
- db/migrations/011_add_tool_call_summaries.rb
|
|
116
125
|
- db/migrations/012_add_vec_indexing_support.rb
|
|
126
|
+
- db/migrations/013_add_mcp_tool_calls.rb
|
|
127
|
+
- db/migrations/014_canonicalize_predicates.rb
|
|
117
128
|
- docs/EXAMPLES.md
|
|
118
129
|
- docs/GETTING_STARTED.md
|
|
119
130
|
- docs/RELEASE_NOTES_v0.2.0.md
|
|
@@ -163,6 +174,7 @@ files:
|
|
|
163
174
|
- lib/claude_memory/commands/conflicts_command.rb
|
|
164
175
|
- lib/claude_memory/commands/db_init_command.rb
|
|
165
176
|
- lib/claude_memory/commands/doctor_command.rb
|
|
177
|
+
- lib/claude_memory/commands/embeddings_command.rb
|
|
166
178
|
- lib/claude_memory/commands/explain_command.rb
|
|
167
179
|
- lib/claude_memory/commands/export_command.rb
|
|
168
180
|
- lib/claude_memory/commands/git_lfs_command.rb
|
|
@@ -183,6 +195,8 @@ files:
|
|
|
183
195
|
- lib/claude_memory/commands/recall_command.rb
|
|
184
196
|
- lib/claude_memory/commands/recover_command.rb
|
|
185
197
|
- lib/claude_memory/commands/registry.rb
|
|
198
|
+
- lib/claude_memory/commands/reject_command.rb
|
|
199
|
+
- lib/claude_memory/commands/restore_command.rb
|
|
186
200
|
- lib/claude_memory/commands/search_command.rb
|
|
187
201
|
- lib/claude_memory/commands/serve_mcp_command.rb
|
|
188
202
|
- lib/claude_memory/commands/skills/distill-transcripts.md
|
|
@@ -225,6 +239,8 @@ files:
|
|
|
225
239
|
- lib/claude_memory/embeddings/dimension_check.rb
|
|
226
240
|
- lib/claude_memory/embeddings/fastembed_adapter.rb
|
|
227
241
|
- lib/claude_memory/embeddings/generator.rb
|
|
242
|
+
- lib/claude_memory/embeddings/inspector.rb
|
|
243
|
+
- lib/claude_memory/embeddings/model_registry.rb
|
|
228
244
|
- lib/claude_memory/embeddings/resolver.rb
|
|
229
245
|
- lib/claude_memory/embeddings/similarity.rb
|
|
230
246
|
- lib/claude_memory/hook/context_injector.rb
|
|
@@ -262,6 +278,7 @@ files:
|
|
|
262
278
|
- lib/claude_memory/mcp/response_formatter.rb
|
|
263
279
|
- lib/claude_memory/mcp/server.rb
|
|
264
280
|
- lib/claude_memory/mcp/setup_status_analyzer.rb
|
|
281
|
+
- lib/claude_memory/mcp/telemetry.rb
|
|
265
282
|
- lib/claude_memory/mcp/text_summary.rb
|
|
266
283
|
- lib/claude_memory/mcp/tool_definitions.rb
|
|
267
284
|
- lib/claude_memory/mcp/tool_helpers.rb
|
|
@@ -318,5 +335,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
318
335
|
requirements: []
|
|
319
336
|
rubygems_version: 4.0.6
|
|
320
337
|
specification_version: 4
|
|
321
|
-
summary: Long-term
|
|
338
|
+
summary: Long-term memory for Claude Code — architecture recall, convention enforcement,
|
|
339
|
+
decision tracking
|
|
322
340
|
test_files: []
|
data/.claude/memory.sqlite3-shm
DELETED
|
Binary file
|
data/.claude/memory.sqlite3-wal
DELETED
|
Binary file
|