claude_memory 0.1.0 → 0.2.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 (75) hide show
  1. checksums.yaml +4 -4
  2. data/.claude/.mind.mv2.aLCUZd +0 -0
  3. data/.claude/memory.sqlite3 +0 -0
  4. data/.claude/rules/claude_memory.generated.md +7 -1
  5. data/.claude/settings.json +0 -4
  6. data/.claude/settings.local.json +4 -1
  7. data/.claude-plugin/plugin.json +1 -1
  8. data/.claude.json +11 -0
  9. data/.ruby-version +1 -0
  10. data/CHANGELOG.md +62 -11
  11. data/CLAUDE.md +87 -24
  12. data/README.md +76 -159
  13. data/docs/EXAMPLES.md +436 -0
  14. data/docs/RELEASE_NOTES_v0.2.0.md +179 -0
  15. data/docs/RUBY_COMMUNITY_POST_v0.2.0.md +582 -0
  16. data/docs/SOCIAL_MEDIA_v0.2.0.md +420 -0
  17. data/docs/architecture.md +360 -0
  18. data/docs/expert_review.md +1718 -0
  19. data/docs/feature_adoption_plan.md +1241 -0
  20. data/docs/feature_adoption_plan_revised.md +2374 -0
  21. data/docs/improvements.md +1325 -0
  22. data/docs/quality_review.md +1544 -0
  23. data/docs/review_summary.md +480 -0
  24. data/lefthook.yml +10 -0
  25. data/lib/claude_memory/cli.rb +16 -844
  26. data/lib/claude_memory/commands/base_command.rb +95 -0
  27. data/lib/claude_memory/commands/changes_command.rb +39 -0
  28. data/lib/claude_memory/commands/conflicts_command.rb +37 -0
  29. data/lib/claude_memory/commands/db_init_command.rb +40 -0
  30. data/lib/claude_memory/commands/doctor_command.rb +147 -0
  31. data/lib/claude_memory/commands/explain_command.rb +65 -0
  32. data/lib/claude_memory/commands/help_command.rb +37 -0
  33. data/lib/claude_memory/commands/hook_command.rb +106 -0
  34. data/lib/claude_memory/commands/ingest_command.rb +47 -0
  35. data/lib/claude_memory/commands/init_command.rb +218 -0
  36. data/lib/claude_memory/commands/promote_command.rb +30 -0
  37. data/lib/claude_memory/commands/publish_command.rb +36 -0
  38. data/lib/claude_memory/commands/recall_command.rb +61 -0
  39. data/lib/claude_memory/commands/registry.rb +55 -0
  40. data/lib/claude_memory/commands/search_command.rb +43 -0
  41. data/lib/claude_memory/commands/serve_mcp_command.rb +16 -0
  42. data/lib/claude_memory/commands/sweep_command.rb +36 -0
  43. data/lib/claude_memory/commands/version_command.rb +13 -0
  44. data/lib/claude_memory/configuration.rb +38 -0
  45. data/lib/claude_memory/core/fact_id.rb +41 -0
  46. data/lib/claude_memory/core/null_explanation.rb +47 -0
  47. data/lib/claude_memory/core/null_fact.rb +30 -0
  48. data/lib/claude_memory/core/result.rb +143 -0
  49. data/lib/claude_memory/core/session_id.rb +37 -0
  50. data/lib/claude_memory/core/token_estimator.rb +33 -0
  51. data/lib/claude_memory/core/transcript_path.rb +37 -0
  52. data/lib/claude_memory/domain/conflict.rb +51 -0
  53. data/lib/claude_memory/domain/entity.rb +51 -0
  54. data/lib/claude_memory/domain/fact.rb +70 -0
  55. data/lib/claude_memory/domain/provenance.rb +48 -0
  56. data/lib/claude_memory/hook/exit_codes.rb +18 -0
  57. data/lib/claude_memory/hook/handler.rb +7 -2
  58. data/lib/claude_memory/index/index_query.rb +89 -0
  59. data/lib/claude_memory/index/index_query_logic.rb +41 -0
  60. data/lib/claude_memory/index/query_options.rb +67 -0
  61. data/lib/claude_memory/infrastructure/file_system.rb +29 -0
  62. data/lib/claude_memory/infrastructure/in_memory_file_system.rb +32 -0
  63. data/lib/claude_memory/ingest/content_sanitizer.rb +42 -0
  64. data/lib/claude_memory/ingest/ingester.rb +3 -0
  65. data/lib/claude_memory/ingest/privacy_tag.rb +48 -0
  66. data/lib/claude_memory/mcp/tools.rb +174 -1
  67. data/lib/claude_memory/publish.rb +29 -20
  68. data/lib/claude_memory/recall.rb +164 -16
  69. data/lib/claude_memory/resolve/resolver.rb +41 -37
  70. data/lib/claude_memory/shortcuts.rb +56 -0
  71. data/lib/claude_memory/store/store_manager.rb +35 -32
  72. data/lib/claude_memory/templates/hooks.example.json +0 -4
  73. data/lib/claude_memory/version.rb +1 -1
  74. data/lib/claude_memory.rb +59 -21
  75. metadata +55 -1
@@ -6,6 +6,24 @@ module ClaudeMemory
6
6
  SCOPE_GLOBAL = "global"
7
7
  SCOPE_ALL = "all"
8
8
 
9
+ class << self
10
+ def recent_decisions(manager, limit: 10)
11
+ Shortcuts.for(:decisions, manager, limit: limit)
12
+ end
13
+
14
+ def architecture_choices(manager, limit: 10)
15
+ Shortcuts.for(:architecture, manager, limit: limit)
16
+ end
17
+
18
+ def conventions(manager, limit: 20)
19
+ Shortcuts.for(:conventions, manager, limit: limit)
20
+ end
21
+
22
+ def project_config(manager, limit: 10)
23
+ Shortcuts.for(:project_config, manager, limit: limit)
24
+ end
25
+ end
26
+
9
27
  def initialize(store_or_manager, fts: nil, project_path: nil, env: ENV)
10
28
  @project_path = project_path || env["CLAUDE_PROJECT_DIR"] || Dir.pwd
11
29
 
@@ -27,6 +45,14 @@ module ClaudeMemory
27
45
  end
28
46
  end
29
47
 
48
+ def query_index(query_text, limit: 20, scope: SCOPE_ALL)
49
+ if @legacy_mode
50
+ query_index_legacy(query_text, limit: limit, scope: scope)
51
+ else
52
+ query_index_dual(query_text, limit: limit, scope: scope)
53
+ end
54
+ end
55
+
30
56
  def explain(fact_id, scope: nil)
31
57
  if @legacy_mode
32
58
  explain_from_store(@legacy_store, fact_id)
@@ -77,38 +103,141 @@ module ClaudeMemory
77
103
  dedupe_and_sort(results, limit)
78
104
  end
79
105
 
106
+ def query_index_dual(query_text, limit:, scope:)
107
+ results = []
108
+
109
+ if scope == SCOPE_ALL || scope == SCOPE_PROJECT
110
+ @manager.ensure_project! if @manager.project_exists?
111
+ if @manager.project_store
112
+ project_results = query_index_single_store(@manager.project_store, query_text, limit: limit, source: :project)
113
+ results.concat(project_results)
114
+ end
115
+ end
116
+
117
+ if scope == SCOPE_ALL || scope == SCOPE_GLOBAL
118
+ @manager.ensure_global! if @manager.global_exists?
119
+ if @manager.global_store
120
+ global_results = query_index_single_store(@manager.global_store, query_text, limit: limit, source: :global)
121
+ results.concat(global_results)
122
+ end
123
+ end
124
+
125
+ dedupe_and_sort_index(results, limit)
126
+ end
127
+
128
+ def query_index_single_store(store, query_text, limit:, source:)
129
+ options = Index::QueryOptions.new(
130
+ query_text: query_text,
131
+ limit: limit,
132
+ scope: :all,
133
+ source: source
134
+ )
135
+
136
+ query = Index::IndexQuery.new(store, options)
137
+ query.execute
138
+ end
139
+
140
+ def dedupe_and_sort_index(results, limit)
141
+ seen_signatures = Set.new
142
+ unique_results = []
143
+
144
+ results.each do |result|
145
+ sig = "#{result[:subject]}:#{result[:predicate]}:#{result[:object_preview]}"
146
+ next if seen_signatures.include?(sig)
147
+
148
+ seen_signatures.add(sig)
149
+ unique_results << result
150
+ end
151
+
152
+ # Sort by source priority (project first)
153
+ unique_results.sort_by do |item|
154
+ source_priority = (item[:source] == :project) ? 0 : 1
155
+ [source_priority]
156
+ end.first(limit)
157
+ end
158
+
80
159
  def query_single_store(store, query_text, limit:, source:)
81
160
  fts = Index::LexicalFTS.new(store)
82
161
  content_ids = fts.search(query_text, limit: limit * 3)
83
162
  return [] if content_ids.empty?
84
163
 
85
- facts_with_provenance = []
164
+ # Collect all fact_ids first
86
165
  seen_fact_ids = Set.new
166
+ ordered_fact_ids = []
87
167
 
88
168
  content_ids.each do |content_id|
89
169
  provenance_records = store.provenance
90
- .select(:id, :fact_id, :content_item_id, :quote, :strength)
170
+ .select(:fact_id)
91
171
  .where(content_item_id: content_id)
92
172
  .all
93
173
 
94
174
  provenance_records.each do |prov|
95
- next if seen_fact_ids.include?(prov[:fact_id])
175
+ fact_id = prov[:fact_id]
176
+ next if seen_fact_ids.include?(fact_id)
96
177
 
97
- fact = find_fact_from_store(store, prov[:fact_id])
98
- next unless fact
99
-
100
- seen_fact_ids.add(prov[:fact_id])
101
- facts_with_provenance << {
102
- fact: fact,
103
- receipts: find_receipts_from_store(store, prov[:fact_id]),
104
- source: source
105
- }
106
- break if facts_with_provenance.size >= limit
178
+ seen_fact_ids.add(fact_id)
179
+ ordered_fact_ids << fact_id
180
+ break if ordered_fact_ids.size >= limit
107
181
  end
108
- break if facts_with_provenance.size >= limit
182
+ break if ordered_fact_ids.size >= limit
109
183
  end
110
184
 
111
- facts_with_provenance
185
+ return [] if ordered_fact_ids.empty?
186
+
187
+ # Batch query all facts at once
188
+ facts_by_id = batch_find_facts(store, ordered_fact_ids)
189
+
190
+ # Batch query all receipts at once
191
+ receipts_by_fact_id = batch_find_receipts(store, ordered_fact_ids)
192
+
193
+ # Build results maintaining order
194
+ ordered_fact_ids.map do |fact_id|
195
+ fact = facts_by_id[fact_id]
196
+ next unless fact
197
+
198
+ {
199
+ fact: fact,
200
+ receipts: receipts_by_fact_id[fact_id] || [],
201
+ source: source
202
+ }
203
+ end.compact
204
+ end
205
+
206
+ def batch_find_facts(store, fact_ids)
207
+ store.facts
208
+ .left_join(:entities, id: :subject_entity_id)
209
+ .select(
210
+ Sequel[:facts][:id],
211
+ Sequel[:facts][:predicate],
212
+ Sequel[:facts][:object_literal],
213
+ Sequel[:facts][:status],
214
+ Sequel[:facts][:confidence],
215
+ Sequel[:facts][:valid_from],
216
+ Sequel[:facts][:valid_to],
217
+ Sequel[:facts][:created_at],
218
+ Sequel[:entities][:canonical_name].as(:subject_name),
219
+ Sequel[:facts][:scope],
220
+ Sequel[:facts][:project_path]
221
+ )
222
+ .where(Sequel[:facts][:id] => fact_ids)
223
+ .all
224
+ .each_with_object({}) { |fact, hash| hash[fact[:id]] = fact }
225
+ end
226
+
227
+ def batch_find_receipts(store, fact_ids)
228
+ store.provenance
229
+ .left_join(:content_items, id: :content_item_id)
230
+ .select(
231
+ Sequel[:provenance][:id],
232
+ Sequel[:provenance][:fact_id],
233
+ Sequel[:provenance][:quote],
234
+ Sequel[:provenance][:strength],
235
+ Sequel[:content_items][:session_id],
236
+ Sequel[:content_items][:occurred_at]
237
+ )
238
+ .where(Sequel[:provenance][:fact_id] => fact_ids)
239
+ .all
240
+ .group_by { |receipt| receipt[:fact_id] }
112
241
  end
113
242
 
114
243
  def dedupe_and_sort(results, limit)
@@ -189,7 +318,7 @@ module ClaudeMemory
189
318
 
190
319
  def explain_from_store(store, fact_id)
191
320
  fact = find_fact_from_store(store, fact_id)
192
- return nil unless fact
321
+ return Core::NullExplanation.new unless fact
193
322
 
194
323
  {
195
324
  fact: fact,
@@ -282,6 +411,25 @@ module ClaudeMemory
282
411
  sort_by_scope_priority(facts_with_provenance)
283
412
  end
284
413
 
414
+ def query_index_legacy(query_text, limit:, scope:)
415
+ options = Index::QueryOptions.new(
416
+ query_text: query_text,
417
+ limit: limit,
418
+ scope: :all,
419
+ source: :legacy
420
+ )
421
+
422
+ query = Index::IndexQuery.new(@legacy_store, options)
423
+ results = query.execute
424
+
425
+ # Filter by scope in legacy mode
426
+ results.select do |result|
427
+ # Need to get full fact to check scope
428
+ fact = find_fact(result[:id])
429
+ fact && fact_matches_scope?(fact, scope)
430
+ end
431
+ end
432
+
285
433
  def changes_legacy(since:, limit:, scope:)
286
434
  ds = @legacy_store.facts
287
435
  .select(:id, :subject_entity_id, :predicate, :object_literal, :status, :created_at, :scope, :project_path)
@@ -57,48 +57,51 @@ module ClaudeMemory
57
57
 
58
58
  existing_facts = @store.facts_for_slot(subject_id, predicate)
59
59
 
60
- if PredicatePolicy.single?(predicate) && existing_facts.any?
61
- matching = existing_facts.find { |f| values_match?(f, object_val, object_entity_id) }
62
- if matching
63
- add_provenance(matching[:id], content_item_id, fact_data)
64
- outcome[:provenance] = 1
65
- return outcome
66
- elsif supersession_signal?(fact_data)
67
- supersede_facts(existing_facts, occurred_at)
68
- outcome[:superseded] = existing_facts.size
69
- else
70
- create_conflict(existing_facts.first[:id], fact_data, subject_id, content_item_id, occurred_at)
71
- outcome[:conflicts] = 1
72
- return outcome
60
+ # Wrap all database operations in a transaction for atomicity
61
+ @store.db.transaction do
62
+ if PredicatePolicy.single?(predicate) && existing_facts.any?
63
+ matching = existing_facts.find { |f| values_match?(f, object_val, object_entity_id) }
64
+ if matching
65
+ add_provenance(matching[:id], content_item_id, fact_data)
66
+ outcome[:provenance] = 1
67
+ return outcome
68
+ elsif supersession_signal?(fact_data)
69
+ supersede_facts(existing_facts, occurred_at)
70
+ outcome[:superseded] = existing_facts.size
71
+ else
72
+ create_conflict(existing_facts.first[:id], fact_data, subject_id, content_item_id, occurred_at)
73
+ outcome[:conflicts] = 1
74
+ return outcome
75
+ end
73
76
  end
74
- end
75
-
76
- fact_scope = fact_data[:scope_hint] || @current_scope
77
- fact_project = (fact_scope == "global") ? nil : @current_project_path
78
-
79
- fact_id = @store.insert_fact(
80
- subject_entity_id: subject_id,
81
- predicate: predicate,
82
- object_entity_id: object_entity_id,
83
- object_literal: object_val,
84
- polarity: fact_data[:polarity] || "positive",
85
- confidence: fact_data[:confidence] || 1.0,
86
- valid_from: occurred_at,
87
- scope: fact_scope,
88
- project_path: fact_project
89
- )
90
- outcome[:created] = 1
91
77
 
92
- if existing_facts.any? && outcome[:superseded] > 0
93
- existing_facts.each do |old_fact|
94
- @store.insert_fact_link(from_fact_id: fact_id, to_fact_id: old_fact[:id], link_type: "supersedes")
78
+ fact_scope = fact_data[:scope_hint] || @current_scope
79
+ fact_project = (fact_scope == "global") ? nil : @current_project_path
80
+
81
+ fact_id = @store.insert_fact(
82
+ subject_entity_id: subject_id,
83
+ predicate: predicate,
84
+ object_entity_id: object_entity_id,
85
+ object_literal: object_val,
86
+ polarity: fact_data[:polarity] || "positive",
87
+ confidence: fact_data[:confidence] || 1.0,
88
+ valid_from: occurred_at,
89
+ scope: fact_scope,
90
+ project_path: fact_project
91
+ )
92
+ outcome[:created] = 1
93
+
94
+ if existing_facts.any? && outcome[:superseded] > 0
95
+ existing_facts.each do |old_fact|
96
+ @store.insert_fact_link(from_fact_id: fact_id, to_fact_id: old_fact[:id], link_type: "supersedes")
97
+ end
95
98
  end
96
- end
97
99
 
98
- add_provenance(fact_id, content_item_id, fact_data)
99
- outcome[:provenance] = 1
100
+ add_provenance(fact_id, content_item_id, fact_data)
101
+ outcome[:provenance] = 1
100
102
 
101
- outcome
103
+ outcome
104
+ end
102
105
  end
103
106
 
104
107
  def supersession_signal?(fact_data)
@@ -118,6 +121,7 @@ module ClaudeMemory
118
121
  end
119
122
 
120
123
  def create_conflict(existing_fact_id, new_fact_data, subject_id, content_item_id, occurred_at)
124
+ # Already within transaction from resolve_fact
121
125
  new_fact_id = @store.insert_fact(
122
126
  subject_entity_id: subject_id,
123
127
  predicate: new_fact_data[:predicate],
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ClaudeMemory
4
+ class Shortcuts
5
+ QUERIES = {
6
+ decisions: {
7
+ query: "decision constraint rule requirement",
8
+ scope: :all,
9
+ limit: 10
10
+ },
11
+ architecture: {
12
+ query: "uses framework implements architecture pattern",
13
+ scope: :all,
14
+ limit: 10
15
+ },
16
+ conventions: {
17
+ query: "convention style format pattern prefer",
18
+ scope: :global,
19
+ limit: 20
20
+ },
21
+ project_config: {
22
+ query: "uses requires depends_on configuration",
23
+ scope: :project,
24
+ limit: 10
25
+ }
26
+ }.freeze
27
+
28
+ def self.for(shortcut_name, manager, **overrides)
29
+ config = QUERIES.fetch(shortcut_name)
30
+ options = config.merge(overrides)
31
+
32
+ recall = Recall.new(manager)
33
+ recall.query(
34
+ options[:query],
35
+ limit: options[:limit],
36
+ scope: options[:scope]
37
+ )
38
+ end
39
+
40
+ def self.decisions(manager, **overrides)
41
+ self.for(:decisions, manager, **overrides)
42
+ end
43
+
44
+ def self.architecture(manager, **overrides)
45
+ self.for(:architecture, manager, **overrides)
46
+ end
47
+
48
+ def self.conventions(manager, **overrides)
49
+ self.for(:conventions, manager, **overrides)
50
+ end
51
+
52
+ def self.project_config(manager, **overrides)
53
+ self.for(:project_config, manager, **overrides)
54
+ end
55
+ end
56
+ end
@@ -85,40 +85,43 @@ module ClaudeMemory
85
85
  subject = @project_store.entities.where(id: fact[:subject_entity_id]).first
86
86
  return nil unless subject
87
87
 
88
- global_subject_id = @global_store.find_or_create_entity(
89
- type: subject[:type],
90
- name: subject[:canonical_name]
91
- )
92
-
93
- global_object_id = nil
94
- if fact[:object_entity_id]
95
- object = @project_store.entities.where(id: fact[:object_entity_id]).first
96
- if object
97
- global_object_id = @global_store.find_or_create_entity(
98
- type: object[:type],
99
- name: object[:canonical_name]
100
- )
88
+ # Wrap all database operations in a transaction for atomicity
89
+ @global_store.db.transaction do
90
+ global_subject_id = @global_store.find_or_create_entity(
91
+ type: subject[:type],
92
+ name: subject[:canonical_name]
93
+ )
94
+
95
+ global_object_id = nil
96
+ if fact[:object_entity_id]
97
+ object = @project_store.entities.where(id: fact[:object_entity_id]).first
98
+ if object
99
+ global_object_id = @global_store.find_or_create_entity(
100
+ type: object[:type],
101
+ name: object[:canonical_name]
102
+ )
103
+ end
101
104
  end
102
- end
103
105
 
104
- global_fact_id = @global_store.insert_fact(
105
- subject_entity_id: global_subject_id,
106
- predicate: fact[:predicate],
107
- object_entity_id: global_object_id,
108
- object_literal: fact[:object_literal],
109
- datatype: fact[:datatype],
110
- polarity: fact[:polarity],
111
- valid_from: fact[:valid_from],
112
- status: fact[:status],
113
- confidence: fact[:confidence],
114
- created_from: "promoted:#{@project_path}:#{fact_id}",
115
- scope: "global",
116
- project_path: nil
117
- )
118
-
119
- copy_provenance(fact_id, global_fact_id)
120
-
121
- global_fact_id
106
+ global_fact_id = @global_store.insert_fact(
107
+ subject_entity_id: global_subject_id,
108
+ predicate: fact[:predicate],
109
+ object_entity_id: global_object_id,
110
+ object_literal: fact[:object_literal],
111
+ datatype: fact[:datatype],
112
+ polarity: fact[:polarity],
113
+ valid_from: fact[:valid_from],
114
+ status: fact[:status],
115
+ confidence: fact[:confidence],
116
+ created_from: "promoted:#{@project_path}:#{fact_id}",
117
+ scope: "global",
118
+ project_path: nil
119
+ )
120
+
121
+ copy_provenance(fact_id, global_fact_id)
122
+
123
+ global_fact_id
124
+ end
122
125
  end
123
126
 
124
127
  private
@@ -2,7 +2,6 @@
2
2
  "hooks": {
3
3
  "Stop": [
4
4
  {
5
- "matcher": "",
6
5
  "hooks": [
7
6
  {
8
7
  "type": "command",
@@ -14,7 +13,6 @@
14
13
  ],
15
14
  "SessionStart": [
16
15
  {
17
- "matcher": "",
18
16
  "hooks": [
19
17
  {
20
18
  "type": "command",
@@ -26,7 +24,6 @@
26
24
  ],
27
25
  "PreCompact": [
28
26
  {
29
- "matcher": "",
30
27
  "hooks": [
31
28
  {
32
29
  "type": "command",
@@ -43,7 +40,6 @@
43
40
  ],
44
41
  "SessionEnd": [
45
42
  {
46
- "matcher": "",
47
43
  "hooks": [
48
44
  {
49
45
  "type": "command",
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ClaudeMemory
4
- VERSION = "0.1.0"
4
+ VERSION = "0.2.0"
5
5
  end
data/lib/claude_memory.rb CHANGED
@@ -2,10 +2,67 @@
2
2
 
3
3
  module ClaudeMemory
4
4
  class Error < StandardError; end
5
+ end
5
6
 
6
- LEGACY_DB_PATH = ".claude_memory.sqlite3"
7
- PROJECT_DB_PATH = ".claude/memory.sqlite3"
7
+ require_relative "claude_memory/core/result"
8
+ require_relative "claude_memory/core/session_id"
9
+ require_relative "claude_memory/core/transcript_path"
10
+ require_relative "claude_memory/core/fact_id"
11
+ require_relative "claude_memory/core/null_fact"
12
+ require_relative "claude_memory/core/null_explanation"
13
+ require_relative "claude_memory/core/token_estimator"
14
+ require_relative "claude_memory/commands/base_command"
15
+ require_relative "claude_memory/commands/help_command"
16
+ require_relative "claude_memory/commands/version_command"
17
+ require_relative "claude_memory/commands/doctor_command"
18
+ require_relative "claude_memory/commands/promote_command"
19
+ require_relative "claude_memory/commands/search_command"
20
+ require_relative "claude_memory/commands/explain_command"
21
+ require_relative "claude_memory/commands/conflicts_command"
22
+ require_relative "claude_memory/commands/changes_command"
23
+ require_relative "claude_memory/commands/recall_command"
24
+ require_relative "claude_memory/commands/sweep_command"
25
+ require_relative "claude_memory/commands/ingest_command"
26
+ require_relative "claude_memory/commands/publish_command"
27
+ require_relative "claude_memory/commands/db_init_command"
28
+ require_relative "claude_memory/commands/init_command"
29
+ require_relative "claude_memory/commands/serve_mcp_command"
30
+ require_relative "claude_memory/commands/hook_command"
31
+ require_relative "claude_memory/commands/registry"
32
+ require_relative "claude_memory/cli"
33
+ require_relative "claude_memory/configuration"
34
+ require_relative "claude_memory/distill/distiller"
35
+ require_relative "claude_memory/distill/extraction"
36
+ require_relative "claude_memory/distill/null_distiller"
37
+ require_relative "claude_memory/domain/fact"
38
+ require_relative "claude_memory/domain/entity"
39
+ require_relative "claude_memory/domain/provenance"
40
+ require_relative "claude_memory/domain/conflict"
41
+ require_relative "claude_memory/hook/exit_codes"
42
+ require_relative "claude_memory/hook/handler"
43
+ require_relative "claude_memory/index/query_options"
44
+ require_relative "claude_memory/index/index_query_logic"
45
+ require_relative "claude_memory/index/index_query"
46
+ require_relative "claude_memory/index/lexical_fts"
47
+ require_relative "claude_memory/ingest/privacy_tag"
48
+ require_relative "claude_memory/ingest/content_sanitizer"
49
+ require_relative "claude_memory/ingest/ingester"
50
+ require_relative "claude_memory/ingest/transcript_reader"
51
+ require_relative "claude_memory/infrastructure/file_system"
52
+ require_relative "claude_memory/infrastructure/in_memory_file_system"
53
+ require_relative "claude_memory/mcp/server"
54
+ require_relative "claude_memory/mcp/tools"
55
+ require_relative "claude_memory/publish"
56
+ require_relative "claude_memory/recall"
57
+ require_relative "claude_memory/shortcuts"
58
+ require_relative "claude_memory/resolve/predicate_policy"
59
+ require_relative "claude_memory/resolve/resolver"
60
+ require_relative "claude_memory/store/sqlite_store"
61
+ require_relative "claude_memory/store/store_manager"
62
+ require_relative "claude_memory/sweep/sweeper"
63
+ require_relative "claude_memory/version"
8
64
 
65
+ module ClaudeMemory
9
66
  def self.global_db_path(env = ENV)
10
67
  home = env["HOME"] || File.expand_path("~")
11
68
  File.join(home, ".claude", "memory.sqlite3")
@@ -15,22 +72,3 @@ module ClaudeMemory
15
72
  File.join(project_path, ".claude", "memory.sqlite3")
16
73
  end
17
74
  end
18
-
19
- require_relative "claude_memory/version"
20
- require_relative "claude_memory/cli"
21
- require_relative "claude_memory/store/sqlite_store"
22
- require_relative "claude_memory/store/store_manager"
23
- require_relative "claude_memory/ingest/transcript_reader"
24
- require_relative "claude_memory/ingest/ingester"
25
- require_relative "claude_memory/index/lexical_fts"
26
- require_relative "claude_memory/distill/extraction"
27
- require_relative "claude_memory/distill/distiller"
28
- require_relative "claude_memory/distill/null_distiller"
29
- require_relative "claude_memory/resolve/predicate_policy"
30
- require_relative "claude_memory/resolve/resolver"
31
- require_relative "claude_memory/recall"
32
- require_relative "claude_memory/sweep/sweeper"
33
- require_relative "claude_memory/mcp/tools"
34
- require_relative "claude_memory/mcp/server"
35
- require_relative "claude_memory/publish"
36
- require_relative "claude_memory/hook/handler"