claude_memory 0.8.0 → 0.9.1
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 +94 -2
- data/.claude/settings.json +30 -52
- data/.claude/settings.local.json +3 -1
- data/.claude/skills/release/SKILL.md +168 -0
- 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 +47 -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 +30 -3
- 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 +27 -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.1
|
|
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"
|
|
@@ -81,6 +89,7 @@ files:
|
|
|
81
89
|
- ".claude/skills/memory-first-workflow"
|
|
82
90
|
- ".claude/skills/quality-update/SKILL.md"
|
|
83
91
|
- ".claude/skills/quality-update/implementation-guide.md"
|
|
92
|
+
- ".claude/skills/release/SKILL.md"
|
|
84
93
|
- ".claude/skills/review-commit/SKILL.md"
|
|
85
94
|
- ".claude/skills/review-for-quality/SKILL.md"
|
|
86
95
|
- ".claude/skills/review-for-quality/expert-checklists.md"
|
|
@@ -88,6 +97,7 @@ files:
|
|
|
88
97
|
- ".claude/skills/study-repo/SKILL.md"
|
|
89
98
|
- ".claude/skills/study-repo/analysis-template.md"
|
|
90
99
|
- ".claude/skills/study-repo/focus-examples.md"
|
|
100
|
+
- ".claude/skills/upgrade-dependencies/SKILL.md"
|
|
91
101
|
- ".gitattributes"
|
|
92
102
|
- ".lefthook/map_specs.rb"
|
|
93
103
|
- ".mcp.json"
|
|
@@ -114,6 +124,8 @@ files:
|
|
|
114
124
|
- db/migrations/010_add_llm_cache.rb
|
|
115
125
|
- db/migrations/011_add_tool_call_summaries.rb
|
|
116
126
|
- db/migrations/012_add_vec_indexing_support.rb
|
|
127
|
+
- db/migrations/013_add_mcp_tool_calls.rb
|
|
128
|
+
- db/migrations/014_canonicalize_predicates.rb
|
|
117
129
|
- docs/EXAMPLES.md
|
|
118
130
|
- docs/GETTING_STARTED.md
|
|
119
131
|
- docs/RELEASE_NOTES_v0.2.0.md
|
|
@@ -163,6 +175,7 @@ files:
|
|
|
163
175
|
- lib/claude_memory/commands/conflicts_command.rb
|
|
164
176
|
- lib/claude_memory/commands/db_init_command.rb
|
|
165
177
|
- lib/claude_memory/commands/doctor_command.rb
|
|
178
|
+
- lib/claude_memory/commands/embeddings_command.rb
|
|
166
179
|
- lib/claude_memory/commands/explain_command.rb
|
|
167
180
|
- lib/claude_memory/commands/export_command.rb
|
|
168
181
|
- lib/claude_memory/commands/git_lfs_command.rb
|
|
@@ -183,6 +196,8 @@ files:
|
|
|
183
196
|
- lib/claude_memory/commands/recall_command.rb
|
|
184
197
|
- lib/claude_memory/commands/recover_command.rb
|
|
185
198
|
- lib/claude_memory/commands/registry.rb
|
|
199
|
+
- lib/claude_memory/commands/reject_command.rb
|
|
200
|
+
- lib/claude_memory/commands/restore_command.rb
|
|
186
201
|
- lib/claude_memory/commands/search_command.rb
|
|
187
202
|
- lib/claude_memory/commands/serve_mcp_command.rb
|
|
188
203
|
- lib/claude_memory/commands/skills/distill-transcripts.md
|
|
@@ -225,6 +240,8 @@ files:
|
|
|
225
240
|
- lib/claude_memory/embeddings/dimension_check.rb
|
|
226
241
|
- lib/claude_memory/embeddings/fastembed_adapter.rb
|
|
227
242
|
- lib/claude_memory/embeddings/generator.rb
|
|
243
|
+
- lib/claude_memory/embeddings/inspector.rb
|
|
244
|
+
- lib/claude_memory/embeddings/model_registry.rb
|
|
228
245
|
- lib/claude_memory/embeddings/resolver.rb
|
|
229
246
|
- lib/claude_memory/embeddings/similarity.rb
|
|
230
247
|
- lib/claude_memory/hook/context_injector.rb
|
|
@@ -262,6 +279,7 @@ files:
|
|
|
262
279
|
- lib/claude_memory/mcp/response_formatter.rb
|
|
263
280
|
- lib/claude_memory/mcp/server.rb
|
|
264
281
|
- lib/claude_memory/mcp/setup_status_analyzer.rb
|
|
282
|
+
- lib/claude_memory/mcp/telemetry.rb
|
|
265
283
|
- lib/claude_memory/mcp/text_summary.rb
|
|
266
284
|
- lib/claude_memory/mcp/tool_definitions.rb
|
|
267
285
|
- lib/claude_memory/mcp/tool_helpers.rb
|
|
@@ -318,5 +336,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
318
336
|
requirements: []
|
|
319
337
|
rubygems_version: 4.0.6
|
|
320
338
|
specification_version: 4
|
|
321
|
-
summary: Long-term
|
|
339
|
+
summary: Long-term memory for Claude Code — architecture recall, convention enforcement,
|
|
340
|
+
decision tracking
|
|
322
341
|
test_files: []
|
data/.claude/memory.sqlite3-shm
DELETED
|
Binary file
|
data/.claude/memory.sqlite3-wal
DELETED
|
Binary file
|