superlocalmemory 3.6.23 → 3.7.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.
Files changed (285) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/README.md +271 -71
  3. package/bin/slm-npm +43 -89
  4. package/ide/configs/antigravity-mcp.json +2 -2
  5. package/ide/configs/chatgpt-desktop-mcp.json +1 -1
  6. package/ide/configs/claude-desktop-mcp.json +2 -2
  7. package/ide/configs/windsurf-mcp.json +2 -2
  8. package/ide/hooks/context-hook.js +6 -2
  9. package/ide/hooks/post-recall-hook.js +7 -3
  10. package/ide/hooks/tool-event-hook.sh +2 -1
  11. package/package.json +17 -9
  12. package/plugin/.claude-plugin/plugin.json +1 -1
  13. package/plugin/_GENERATED.md +1 -1
  14. package/plugin/agents/slm-memory-advisor.md +1 -1
  15. package/plugin/requirements.txt +1 -1
  16. package/plugin/skills/slm-session/SKILL.md +1 -1
  17. package/plugin-src/agents/slm-memory-advisor.md +1 -1
  18. package/plugin-src/manifest.json +1 -1
  19. package/plugin-src/requirements.txt +1 -1
  20. package/plugin-src/rules/AGENTS.md +1 -1
  21. package/plugin-src/skills/slm-session/SKILL.md +1 -1
  22. package/pyproject.toml +40 -8
  23. package/scripts/postinstall-interactive.js +17 -94
  24. package/scripts/postinstall.js +185 -258
  25. package/scripts/preuninstall.js +9 -50
  26. package/src/superlocalmemory/__init__.py +2 -2
  27. package/src/superlocalmemory/attribution/mathematical_dna.py +1 -1
  28. package/src/superlocalmemory/attribution/signer.py +34 -19
  29. package/src/superlocalmemory/attribution/watermark.py +1 -1
  30. package/src/superlocalmemory/cli/_lazy_init.py +7 -7
  31. package/src/superlocalmemory/cli/commands.py +453 -191
  32. package/src/superlocalmemory/cli/context_commands.py +5 -4
  33. package/src/superlocalmemory/cli/daemon.py +282 -187
  34. package/src/superlocalmemory/cli/db_migrate.py +3 -1
  35. package/src/superlocalmemory/cli/diagnostics_cmd.py +28 -0
  36. package/src/superlocalmemory/cli/evidence_cmd.py +103 -0
  37. package/src/superlocalmemory/cli/ingest_cmd.py +7 -3
  38. package/src/superlocalmemory/cli/main.py +128 -31
  39. package/src/superlocalmemory/cli/pending_store.py +54 -38
  40. package/src/superlocalmemory/cli/scale_engine_cmd.py +37 -0
  41. package/src/superlocalmemory/cli/service_installer.py +57 -52
  42. package/src/superlocalmemory/cli/setup_wizard.py +142 -88
  43. package/src/superlocalmemory/cli/version_banner.py +2 -1
  44. package/src/superlocalmemory/code_graph/config.py +3 -1
  45. package/src/superlocalmemory/core/backend_orchestrator.py +81 -21
  46. package/src/superlocalmemory/core/config.py +65 -20
  47. package/src/superlocalmemory/core/consolidation_engine.py +9 -7
  48. package/src/superlocalmemory/core/context_cache.py +56 -8
  49. package/src/superlocalmemory/core/derivation_lineage.py +246 -0
  50. package/src/superlocalmemory/core/embedding_worker.py +32 -20
  51. package/src/superlocalmemory/core/embeddings.py +54 -18
  52. package/src/superlocalmemory/core/engine.py +150 -104
  53. package/src/superlocalmemory/core/engine_ingestion.py +513 -0
  54. package/src/superlocalmemory/core/engine_wiring.py +32 -23
  55. package/src/superlocalmemory/core/evidence_bundle.py +526 -0
  56. package/src/superlocalmemory/core/fact_consolidator.py +5 -11
  57. package/src/superlocalmemory/core/graph_analyzer.py +2 -2
  58. package/src/superlocalmemory/core/health_monitor.py +4 -2
  59. package/src/superlocalmemory/core/ingestion_command.py +636 -0
  60. package/src/superlocalmemory/core/injection.py +69 -18
  61. package/src/superlocalmemory/core/lifecycle_state.py +153 -0
  62. package/src/superlocalmemory/core/maintenance.py +1 -1
  63. package/src/superlocalmemory/core/maintenance_scheduler.py +51 -35
  64. package/src/superlocalmemory/core/mutations.py +143 -0
  65. package/src/superlocalmemory/core/platform_utils.py +7 -4
  66. package/src/superlocalmemory/core/ram_lock.py +16 -5
  67. package/src/superlocalmemory/core/rate_limit.py +1 -1
  68. package/src/superlocalmemory/core/recall_pipeline.py +60 -101
  69. package/src/superlocalmemory/core/recall_worker.py +76 -59
  70. package/src/superlocalmemory/core/registry.py +1 -1
  71. package/src/superlocalmemory/core/scale_engine.py +293 -0
  72. package/src/superlocalmemory/core/score_contract.py +62 -0
  73. package/src/superlocalmemory/core/security_primitives.py +3 -1
  74. package/src/superlocalmemory/core/slm_disabled.py +3 -5
  75. package/src/superlocalmemory/core/store_pipeline.py +172 -40
  76. package/src/superlocalmemory/core/tier_manager.py +32 -20
  77. package/src/superlocalmemory/core/worker_pool.py +13 -4
  78. package/src/superlocalmemory/dynamics/activation_guided_quantization.py +1 -1
  79. package/src/superlocalmemory/dynamics/eap_scheduler.py +10 -3
  80. package/src/superlocalmemory/dynamics/ebbinghaus_langevin_coupling.py +1 -1
  81. package/src/superlocalmemory/dynamics/fisher_langevin_coupling.py +1 -1
  82. package/src/superlocalmemory/encoding/auto_linker.py +1 -1
  83. package/src/superlocalmemory/encoding/cognitive_consolidator.py +7 -16
  84. package/src/superlocalmemory/encoding/consolidator.py +22 -5
  85. package/src/superlocalmemory/encoding/fact_extractor.py +1 -1
  86. package/src/superlocalmemory/encoding/foresight.py +2 -0
  87. package/src/superlocalmemory/encoding/graph_builder.py +1 -1
  88. package/src/superlocalmemory/encoding/temporal_parser.py +2 -0
  89. package/src/superlocalmemory/evaluation/__init__.py +13 -0
  90. package/src/superlocalmemory/evaluation/calibration.py +308 -0
  91. package/src/superlocalmemory/evolution/skill_evolver.py +2 -1
  92. package/src/superlocalmemory/graph/cozo_backend.py +256 -23
  93. package/src/superlocalmemory/hooks/_outcome_common.py +21 -11
  94. package/src/superlocalmemory/hooks/antigravity_adapter.py +10 -31
  95. package/src/superlocalmemory/hooks/auto_invoker.py +25 -27
  96. package/src/superlocalmemory/hooks/auto_recall.py +31 -6
  97. package/src/superlocalmemory/hooks/auto_recall_hook.py +13 -33
  98. package/src/superlocalmemory/hooks/before_web_hook.py +9 -7
  99. package/src/superlocalmemory/hooks/claude_code_hooks.py +123 -35
  100. package/src/superlocalmemory/hooks/codex_assets.py +59 -0
  101. package/src/superlocalmemory/hooks/codex_hooks.py +186 -0
  102. package/src/superlocalmemory/hooks/context_payload.py +1 -1
  103. package/src/superlocalmemory/hooks/copilot_adapter.py +9 -24
  104. package/src/superlocalmemory/hooks/cursor_adapter.py +10 -32
  105. package/src/superlocalmemory/hooks/hook_daemon.py +4 -2
  106. package/src/superlocalmemory/hooks/hook_handlers.py +219 -32
  107. package/src/superlocalmemory/hooks/memory_protocol.py +5 -3
  108. package/src/superlocalmemory/hooks/post_tool_async_hook.py +4 -2
  109. package/src/superlocalmemory/hooks/session_registry.py +15 -8
  110. package/src/superlocalmemory/hooks/stop_outcome_hook.py +10 -6
  111. package/src/superlocalmemory/hooks/topic_shift_hook.py +42 -12
  112. package/src/superlocalmemory/hooks/user_prompt_hook.py +9 -14
  113. package/src/superlocalmemory/hooks/user_prompt_rehash_hook.py +19 -11
  114. package/src/superlocalmemory/infra/auth_middleware.py +38 -5
  115. package/src/superlocalmemory/infra/backup.py +7 -5
  116. package/src/superlocalmemory/infra/cloud_backup.py +18 -8
  117. package/src/superlocalmemory/infra/daemon_identity.py +248 -0
  118. package/src/superlocalmemory/infra/data_root.py +199 -0
  119. package/src/superlocalmemory/infra/event_bus.py +3 -1
  120. package/src/superlocalmemory/infra/local_diagnostics.py +327 -0
  121. package/src/superlocalmemory/infra/process_reaper.py +23 -0
  122. package/src/superlocalmemory/ingestion/adapter_manager.py +27 -9
  123. package/src/superlocalmemory/ingestion/base_adapter.py +25 -31
  124. package/src/superlocalmemory/ingestion/calendar_adapter.py +13 -4
  125. package/src/superlocalmemory/ingestion/credentials.py +14 -7
  126. package/src/superlocalmemory/ingestion/gmail_adapter.py +13 -4
  127. package/src/superlocalmemory/ingestion/transcript_adapter.py +7 -2
  128. package/src/superlocalmemory/learning/consolidation_quantization_worker.py +1 -1
  129. package/src/superlocalmemory/learning/ensemble.py +11 -0
  130. package/src/superlocalmemory/learning/entity_compiler.py +1 -1
  131. package/src/superlocalmemory/learning/feedback.py +1 -1
  132. package/src/superlocalmemory/learning/forgetting_scheduler.py +12 -7
  133. package/src/superlocalmemory/learning/quantization_scheduler.py +1 -1
  134. package/src/superlocalmemory/learning/ranker.py +4 -1
  135. package/src/superlocalmemory/learning/source_quality.py +1 -1
  136. package/src/superlocalmemory/learning/trigram_index.py +3 -2
  137. package/src/superlocalmemory/llm/backbone.py +1 -1
  138. package/src/superlocalmemory/math/ebbinghaus.py +1 -1
  139. package/src/superlocalmemory/math/fisher.py +1 -1
  140. package/src/superlocalmemory/math/fisher_quantized.py +1 -1
  141. package/src/superlocalmemory/math/hopfield.py +1 -1
  142. package/src/superlocalmemory/math/langevin.py +1 -1
  143. package/src/superlocalmemory/math/polar_quant.py +3 -4
  144. package/src/superlocalmemory/math/qjl.py +1 -1
  145. package/src/superlocalmemory/math/sheaf.py +1 -1
  146. package/src/superlocalmemory/math/turbo_quant.py +3 -2
  147. package/src/superlocalmemory/mcp/_daemon_proxy.py +12 -11
  148. package/src/superlocalmemory/mcp/_pool_adapter.py +27 -0
  149. package/src/superlocalmemory/mcp/http_transport.py +53 -0
  150. package/src/superlocalmemory/mcp/server.py +39 -13
  151. package/src/superlocalmemory/mcp/shared.py +69 -3
  152. package/src/superlocalmemory/mcp/tools_active.py +141 -31
  153. package/src/superlocalmemory/mcp/tools_core.py +130 -31
  154. package/src/superlocalmemory/mcp/tools_evolution.py +5 -7
  155. package/src/superlocalmemory/mcp/tools_learning.py +42 -2
  156. package/src/superlocalmemory/mcp/tools_mesh.py +7 -23
  157. package/src/superlocalmemory/mcp/tools_optimize.py +8 -1
  158. package/src/superlocalmemory/mcp/tools_v28.py +23 -2
  159. package/src/superlocalmemory/mcp/tools_v3.py +26 -1
  160. package/src/superlocalmemory/mcp/tools_v33.py +56 -17
  161. package/src/superlocalmemory/mesh/broker.py +2 -0
  162. package/src/superlocalmemory/mesh/remote_sync.py +50 -12
  163. package/src/superlocalmemory/optimize/cache/manager.py +77 -1
  164. package/src/superlocalmemory/optimize/cache/semantic.py +23 -3
  165. package/src/superlocalmemory/optimize/compress/ccr.py +4 -0
  166. package/src/superlocalmemory/optimize/compress/router.py +6 -1
  167. package/src/superlocalmemory/optimize/config/__init__.py +5 -0
  168. package/src/superlocalmemory/optimize/config/store.py +6 -4
  169. package/src/superlocalmemory/optimize/proxy/_helpers.py +15 -5
  170. package/src/superlocalmemory/optimize/proxy/capture.py +3 -2
  171. package/src/superlocalmemory/optimize/proxy/server.py +2 -2
  172. package/src/superlocalmemory/optimize/storage/db.py +12 -12
  173. package/src/superlocalmemory/retrieval/agentic.py +1 -1
  174. package/src/superlocalmemory/retrieval/ann_index.py +1 -1
  175. package/src/superlocalmemory/retrieval/bm25_channel.py +35 -11
  176. package/src/superlocalmemory/retrieval/bridge_discovery.py +73 -8
  177. package/src/superlocalmemory/retrieval/engine.py +169 -79
  178. package/src/superlocalmemory/retrieval/entity_channel.py +289 -67
  179. package/src/superlocalmemory/retrieval/forgetting_filter.py +1 -1
  180. package/src/superlocalmemory/retrieval/fusion.py +1 -1
  181. package/src/superlocalmemory/retrieval/hopfield_channel.py +118 -30
  182. package/src/superlocalmemory/retrieval/profile_channel.py +1 -1
  183. package/src/superlocalmemory/retrieval/quantization_aware_search.py +16 -10
  184. package/src/superlocalmemory/retrieval/reranker.py +56 -20
  185. package/src/superlocalmemory/retrieval/scope_policy.py +85 -0
  186. package/src/superlocalmemory/retrieval/semantic_channel.py +122 -14
  187. package/src/superlocalmemory/retrieval/spreading_activation.py +141 -25
  188. package/src/superlocalmemory/retrieval/strategy.py +1 -1
  189. package/src/superlocalmemory/retrieval/temporal_channel.py +30 -15
  190. package/src/superlocalmemory/retrieval/vector_store.py +1 -1
  191. package/src/superlocalmemory/server/api.py +10 -7
  192. package/src/superlocalmemory/server/bandit_loops.py +4 -2
  193. package/src/superlocalmemory/server/recall_serializer.py +24 -0
  194. package/src/superlocalmemory/server/route_mutations.py +84 -0
  195. package/src/superlocalmemory/server/routes/agents.py +8 -6
  196. package/src/superlocalmemory/server/routes/brain.py +14 -12
  197. package/src/superlocalmemory/server/routes/chat.py +29 -12
  198. package/src/superlocalmemory/server/routes/data_io.py +55 -24
  199. package/src/superlocalmemory/server/routes/helpers.py +8 -63
  200. package/src/superlocalmemory/server/routes/ingest.py +53 -36
  201. package/src/superlocalmemory/server/routes/memories.py +104 -43
  202. package/src/superlocalmemory/server/routes/mesh.py +31 -0
  203. package/src/superlocalmemory/server/routes/profiles.py +26 -4
  204. package/src/superlocalmemory/server/routes/tiers.py +43 -11
  205. package/src/superlocalmemory/server/routes/timeline.py +5 -1
  206. package/src/superlocalmemory/server/routes/v3_api.py +76 -21
  207. package/src/superlocalmemory/server/security_middleware.py +1 -1
  208. package/src/superlocalmemory/server/unified_daemon.py +680 -293
  209. package/src/superlocalmemory/server/write_identity.py +147 -0
  210. package/src/superlocalmemory/storage/access_log.py +4 -3
  211. package/src/superlocalmemory/storage/database.py +118 -25
  212. package/src/superlocalmemory/storage/migration_runner.py +84 -1
  213. package/src/superlocalmemory/storage/migration_v33.py +1 -1
  214. package/src/superlocalmemory/storage/migrations/M002_model_state_history.py +6 -60
  215. package/src/superlocalmemory/storage/migrations/M018_ingestion_operations.py +120 -0
  216. package/src/superlocalmemory/storage/migrations/M019_derivation_lineage.py +54 -0
  217. package/src/superlocalmemory/storage/migrations/M020_model_state_integrity.py +52 -0
  218. package/src/superlocalmemory/storage/migrations/__init__.py +5 -0
  219. package/src/superlocalmemory/storage/models.py +16 -0
  220. package/src/superlocalmemory/storage/quantized_store.py +20 -3
  221. package/src/superlocalmemory/storage/v2_migrator.py +5 -3
  222. package/src/superlocalmemory/ui/favicon.svg +5 -0
  223. package/src/superlocalmemory/ui/index.html +1 -0
  224. package/src/superlocalmemory/ui/js/compliance.js +1 -1
  225. package/src/superlocalmemory/ui/js/core.js +49 -8
  226. package/src/superlocalmemory/ui/js/dashboard.js +23 -2
  227. package/src/superlocalmemory/ui/js/feedback.js +1 -1
  228. package/src/superlocalmemory/ui/js/graph-filters.js +1 -1
  229. package/src/superlocalmemory/ui/js/graph-ui.js +1 -1
  230. package/src/superlocalmemory/ui/js/lifecycle.js +1 -1
  231. package/src/superlocalmemory/ui/js/ng-mesh.js +15 -49
  232. package/src/superlocalmemory/ui/js/settings.js +4 -2
  233. package/src/superlocalmemory/vector/lancedb_backend.py +57 -9
  234. package/bin/slm +0 -59
  235. package/bin/slm.bat +0 -77
  236. package/bin/slm.cmd +0 -5
  237. package/ide/integrations/langchain/README.md +0 -106
  238. package/ide/integrations/langchain/langchain_superlocalmemory/__init__.py +0 -9
  239. package/ide/integrations/langchain/langchain_superlocalmemory/chat_message_history.py +0 -201
  240. package/ide/integrations/langchain/pyproject.toml +0 -38
  241. package/ide/integrations/langchain/tests/__init__.py +0 -3
  242. package/ide/integrations/langchain/tests/test_chat_message_history.py +0 -215
  243. package/ide/integrations/langchain/tests/test_security.py +0 -117
  244. package/ide/integrations/llamaindex/README.md +0 -81
  245. package/ide/integrations/llamaindex/llama_index/storage/chat_store/superlocalmemory/__init__.py +0 -9
  246. package/ide/integrations/llamaindex/llama_index/storage/chat_store/superlocalmemory/base.py +0 -316
  247. package/ide/integrations/llamaindex/pyproject.toml +0 -43
  248. package/ide/integrations/llamaindex/tests/__init__.py +0 -3
  249. package/ide/integrations/llamaindex/tests/test_chat_store.py +0 -294
  250. package/ide/integrations/llamaindex/tests/test_security.py +0 -241
  251. package/scripts/__tests__/build-plugin.test.mjs +0 -613
  252. package/scripts/_savings_math.py +0 -270
  253. package/scripts/build-dmg.sh +0 -417
  254. package/scripts/build-plugin.js +0 -742
  255. package/scripts/build-slm-hook.ps1 +0 -40
  256. package/scripts/build-slm-hook.sh +0 -45
  257. package/scripts/build_entry.py +0 -452
  258. package/scripts/ci/stage5b_gate.sh +0 -50
  259. package/scripts/dogfood_savings.py +0 -490
  260. package/scripts/generate-thumbnails.py +0 -218
  261. package/scripts/install-skills.ps1 +0 -4
  262. package/scripts/install-skills.sh +0 -5
  263. package/scripts/install.ps1 +0 -701
  264. package/scripts/install.sh +0 -1015
  265. package/scripts/postinstall_binary.js +0 -287
  266. package/scripts/prepack.js +0 -33
  267. package/scripts/release_manifest.py +0 -273
  268. package/scripts/slm-hook.spec +0 -56
  269. package/scripts/start-dashboard.ps1 +0 -52
  270. package/scripts/start-dashboard.sh +0 -41
  271. package/scripts/sync-wiki.ps1 +0 -127
  272. package/scripts/sync-wiki.sh +0 -82
  273. package/scripts/test-dmg.sh +0 -161
  274. package/scripts/test-npm-package.ps1 +0 -252
  275. package/scripts/test-npm-package.sh +0 -207
  276. package/scripts/verify-install.ps1 +0 -294
  277. package/scripts/verify-install.sh +0 -266
  278. package/scripts/verify-v27.ps1 +0 -301
  279. package/scripts/verify-v27.sh +0 -233
  280. package/src/superlocalmemory.egg-info/PKG-INFO +0 -516
  281. package/src/superlocalmemory.egg-info/SOURCES.txt +0 -529
  282. package/src/superlocalmemory.egg-info/dependency_links.txt +0 -1
  283. package/src/superlocalmemory.egg-info/entry_points.txt +0 -2
  284. package/src/superlocalmemory.egg-info/requires.txt +0 -71
  285. package/src/superlocalmemory.egg-info/top_level.txt +0 -1
@@ -12,12 +12,11 @@ All adapters inherit this. Enforces stateless, safe, cross-platform operation:
12
12
  - Structured logging
13
13
 
14
14
  Part of Qualixar | Author: Varun Pratap Bhardwaj
15
- License: Elastic-2.0
15
+ License: AGPL-3.0-or-later
16
16
  """
17
17
 
18
18
  from __future__ import annotations
19
19
 
20
- import json
21
20
  import logging
22
21
  import os
23
22
  import signal
@@ -132,35 +131,30 @@ class BaseAdapter:
132
131
 
133
132
  def _ingest(self, item: IngestItem) -> bool:
134
133
  """POST to daemon /ingest endpoint. Returns True on success."""
135
- try:
136
- import urllib.request
137
- payload = json.dumps({
138
- "content": item.content,
139
- "source_type": self.source_type,
140
- "dedup_key": item.dedup_key,
141
- "metadata": item.metadata if item.metadata else {},
142
- }).encode()
143
- req = urllib.request.Request(
144
- f"{self.daemon_url}/ingest",
145
- data=payload,
146
- headers={"Content-Type": "application/json"},
147
- method="POST",
148
- )
149
- resp = urllib.request.urlopen(req, timeout=30)
150
- data = json.loads(resp.read().decode())
151
- if data.get("ingested"):
152
- self._items_this_hour += 1
153
- self._total_ingested += 1
154
- return True
155
- return False # Already ingested (dedup)
156
- except Exception as exc:
157
- error_str = str(exc)
158
- if "429" in error_str:
159
- logger.info("Daemon returned 429, backing off 5s")
160
- self._stop_event.wait(5)
161
- return self._ingest(item) # Retry once
162
- logger.debug("Ingest failed: %s", exc)
163
- return False
134
+ payload = {
135
+ "content": item.content,
136
+ "source_type": self.source_type,
137
+ "dedup_key": item.dedup_key,
138
+ "metadata": item.metadata if item.metadata else {},
139
+ }
140
+ for attempt in range(2):
141
+ try:
142
+ from superlocalmemory.cli.daemon import daemon_request
143
+
144
+ data = daemon_request("POST", "/ingest", payload)
145
+ if data and data.get("ingested"):
146
+ self._items_this_hour += 1
147
+ self._total_ingested += 1
148
+ return True
149
+ return False # Already ingested (dedup)
150
+ except Exception as exc:
151
+ if "429" in str(exc) and attempt == 0:
152
+ logger.info("Daemon returned 429, backing off 5s")
153
+ self._stop_event.wait(5)
154
+ continue
155
+ logger.debug("Ingest failed: %s", exc)
156
+ return False
157
+ return False
164
158
 
165
159
  def _rate_limited(self) -> bool:
166
160
  if time.time() - self._hour_start > 3600:
@@ -10,7 +10,7 @@ Tier 2: Google Calendar API with OAuth polling — shares Gmail OAuth credential
10
10
  OPT-IN only. Enabled via: slm adapters enable calendar
11
11
 
12
12
  Part of Qualixar | Author: Varun Pratap Bhardwaj
13
- License: Elastic-2.0
13
+ License: AGPL-3.0-or-later
14
14
  """
15
15
 
16
16
  from __future__ import annotations
@@ -22,10 +22,19 @@ from datetime import datetime, timezone
22
22
  from pathlib import Path
23
23
 
24
24
  from superlocalmemory.ingestion.base_adapter import BaseAdapter, AdapterConfig, IngestItem
25
+ from superlocalmemory.infra.data_root import state_path
25
26
 
26
27
  logger = logging.getLogger("superlocalmemory.ingestion.calendar")
27
28
 
28
29
 
30
+ def _adapters_config_path() -> Path:
31
+ return state_path("adapters.json")
32
+
33
+
34
+ def _import_dir() -> Path:
35
+ return state_path("import")
36
+
37
+
29
38
  class CalendarAdapter(BaseAdapter):
30
39
  """Google Calendar ingestion with automatic tier detection."""
31
40
 
@@ -62,7 +71,7 @@ class CalendarAdapter(BaseAdapter):
62
71
  if self._tier != "auto":
63
72
  return
64
73
 
65
- adapters_path = Path.home() / ".superlocalmemory" / "adapters.json"
74
+ adapters_path = _adapters_config_path()
66
75
  cfg = {}
67
76
  if adapters_path.exists():
68
77
  cfg = json.loads(adapters_path.read_text()).get("calendar", {})
@@ -79,7 +88,7 @@ class CalendarAdapter(BaseAdapter):
79
88
  return
80
89
 
81
90
  # Look for ICS files
82
- import_dir = Path.home() / ".superlocalmemory" / "import"
91
+ import_dir = _import_dir()
83
92
  ics_files = list(import_dir.glob("*.ics")) if import_dir.exists() else []
84
93
  if ics_files:
85
94
  self._tier = "ics"
@@ -330,7 +339,7 @@ if __name__ == "__main__":
330
339
  import logging as _logging
331
340
  _logging.basicConfig(level=_logging.INFO, format="%(asctime)s %(message)s")
332
341
 
333
- adapters_path = Path.home() / ".superlocalmemory" / "adapters.json"
342
+ adapters_path = _adapters_config_path()
334
343
  tier = "auto"
335
344
  if adapters_path.exists():
336
345
  cfg = json.loads(adapters_path.read_text()).get("calendar", {})
@@ -8,7 +8,7 @@ Uses OS keychain via keyring library (macOS Keychain, Windows Credential Locker,
8
8
  Linux SecretService). Falls back to file-based storage with restricted permissions.
9
9
 
10
10
  Part of Qualixar | Author: Varun Pratap Bhardwaj
11
- License: Elastic-2.0
11
+ License: AGPL-3.0-or-later
12
12
  """
13
13
 
14
14
  from __future__ import annotations
@@ -19,12 +19,18 @@ import os
19
19
  import sys
20
20
  from pathlib import Path
21
21
 
22
+ from superlocalmemory.infra.data_root import state_path
23
+
22
24
  logger = logging.getLogger("superlocalmemory.ingestion.credentials")
23
25
 
24
- _CRED_DIR = Path.home() / ".superlocalmemory" / "credentials"
26
+ _CRED_DIR = None # test-only compatibility override
25
27
  _SERVICE_PREFIX = "slm"
26
28
 
27
29
 
30
+ def _credential_dir() -> Path:
31
+ return Path(_CRED_DIR) if _CRED_DIR is not None else state_path("credentials")
32
+
33
+
28
34
  def store_credential(service: str, key: str, value: str) -> bool:
29
35
  """Store a credential securely. Returns True on success."""
30
36
  # Try OS keychain first
@@ -38,8 +44,9 @@ def store_credential(service: str, key: str, value: str) -> bool:
38
44
 
39
45
  # Fallback: encrypted file with restricted permissions
40
46
  try:
41
- _CRED_DIR.mkdir(parents=True, exist_ok=True)
42
- cred_file = _CRED_DIR / f"{service}.json"
47
+ cred_dir = _credential_dir()
48
+ cred_dir.mkdir(parents=True, exist_ok=True)
49
+ cred_file = cred_dir / f"{service}.json"
43
50
 
44
51
  existing = {}
45
52
  if cred_file.exists():
@@ -54,7 +61,7 @@ def store_credential(service: str, key: str, value: str) -> bool:
54
61
  # Restrict permissions (Unix only — Windows skipped)
55
62
  if sys.platform != "win32":
56
63
  os.chmod(cred_file, 0o600)
57
- os.chmod(_CRED_DIR, 0o700)
64
+ os.chmod(cred_dir, 0o700)
58
65
 
59
66
  logger.debug("Stored %s/%s in file (keychain unavailable)", service, key)
60
67
  return True
@@ -76,7 +83,7 @@ def load_credential(service: str, key: str) -> str | None:
76
83
 
77
84
  # Fallback: file
78
85
  try:
79
- cred_file = _CRED_DIR / f"{service}.json"
86
+ cred_file = _credential_dir() / f"{service}.json"
80
87
  if cred_file.exists():
81
88
  data = json.loads(cred_file.read_text())
82
89
  return data.get(key)
@@ -100,7 +107,7 @@ def delete_credential(service: str, key: str) -> bool:
100
107
 
101
108
  # Also remove from file
102
109
  try:
103
- cred_file = _CRED_DIR / f"{service}.json"
110
+ cred_file = _credential_dir() / f"{service}.json"
104
111
  if cred_file.exists():
105
112
  data = json.loads(cred_file.read_text())
106
113
  if key in data:
@@ -12,7 +12,7 @@ Tier 3: Gmail API with Pub/Sub push — full GCP (future)
12
12
  OPT-IN only. Enabled via: slm adapters enable gmail
13
13
 
14
14
  Part of Qualixar | Author: Varun Pratap Bhardwaj
15
- License: Elastic-2.0
15
+ License: AGPL-3.0-or-later
16
16
  """
17
17
 
18
18
  from __future__ import annotations
@@ -23,10 +23,19 @@ import sys
23
23
  from pathlib import Path
24
24
 
25
25
  from superlocalmemory.ingestion.base_adapter import BaseAdapter, AdapterConfig, IngestItem
26
+ from superlocalmemory.infra.data_root import state_path
26
27
 
27
28
  logger = logging.getLogger("superlocalmemory.ingestion.gmail")
28
29
 
29
30
 
31
+ def _adapters_config_path() -> Path:
32
+ return state_path("adapters.json")
33
+
34
+
35
+ def _import_dir() -> Path:
36
+ return state_path("import")
37
+
38
+
30
39
  class GmailAdapter(BaseAdapter):
31
40
  """Gmail ingestion with automatic tier detection."""
32
41
 
@@ -71,7 +80,7 @@ class GmailAdapter(BaseAdapter):
71
80
  if self._tier != "auto":
72
81
  return
73
82
 
74
- adapters_path = Path.home() / ".superlocalmemory" / "adapters.json"
83
+ adapters_path = _adapters_config_path()
75
84
  cfg = {}
76
85
  if adapters_path.exists():
77
86
  cfg = json.loads(adapters_path.read_text()).get("gmail", {})
@@ -93,7 +102,7 @@ class GmailAdapter(BaseAdapter):
93
102
  return
94
103
 
95
104
  # Default: look for mbox file
96
- mbox_dir = Path.home() / ".superlocalmemory" / "import"
105
+ mbox_dir = _import_dir()
97
106
  mbox_files = list(mbox_dir.glob("*.mbox")) if mbox_dir.exists() else []
98
107
  if mbox_files:
99
108
  self._tier = "mbox"
@@ -359,7 +368,7 @@ if __name__ == "__main__":
359
368
  import logging as _logging
360
369
  _logging.basicConfig(level=_logging.INFO, format="%(asctime)s %(message)s")
361
370
 
362
- adapters_path = Path.home() / ".superlocalmemory" / "adapters.json"
371
+ adapters_path = _adapters_config_path()
363
372
  tier = "auto"
364
373
  if adapters_path.exists():
365
374
  cfg = json.loads(adapters_path.read_text()).get("gmail", {})
@@ -11,7 +11,7 @@ to the daemon's /ingest endpoint.
11
11
  OPT-IN only. Enabled via: slm adapters enable transcript
12
12
 
13
13
  Part of Qualixar | Author: Varun Pratap Bhardwaj
14
- License: Elastic-2.0
14
+ License: AGPL-3.0-or-later
15
15
  """
16
16
 
17
17
  from __future__ import annotations
@@ -23,12 +23,17 @@ import time
23
23
  from pathlib import Path
24
24
 
25
25
  from superlocalmemory.ingestion.base_adapter import BaseAdapter, AdapterConfig, IngestItem
26
+ from superlocalmemory.infra.data_root import state_path
26
27
 
27
28
  logger = logging.getLogger("superlocalmemory.ingestion.transcript")
28
29
 
29
30
  _WATCH_EXTENSIONS = {".srt", ".vtt", ".txt"}
30
31
 
31
32
 
33
+ def _adapters_config_path() -> Path:
34
+ return state_path("adapters.json")
35
+
36
+
32
37
  class TranscriptAdapter(BaseAdapter):
33
38
  """Watches a directory for transcript files and ingests them."""
34
39
 
@@ -142,7 +147,7 @@ if __name__ == "__main__":
142
147
 
143
148
  # Load config
144
149
  watch_dir = ""
145
- adapters_path = Path.home() / ".superlocalmemory" / "adapters.json"
150
+ adapters_path = _adapters_config_path()
146
151
  if adapters_path.exists():
147
152
  cfg = json.loads(adapters_path.read_text())
148
153
  watch_dir = cfg.get("transcript", {}).get("watch_dir", "")
@@ -12,7 +12,7 @@ Wraps CognitiveConsolidator with scheduling logic:
12
12
  Integration point: ConsolidationEngine._step7_ccq() calls this worker.
13
13
 
14
14
  Part of Qualixar | Author: Varun Pratap Bhardwaj
15
- License: Elastic-2.0
15
+ License: AGPL-3.0-or-later
16
16
  """
17
17
 
18
18
  from __future__ import annotations
@@ -269,6 +269,17 @@ def ensemble_rerank(
269
269
  for b, l in zip(n_bandit, n_lgbm)
270
270
  ]
271
271
 
272
+ # Retain the model/policy utility for auditability without overwriting the
273
+ # public query-relative relevance score.
274
+ for candidate, utility in zip(candidates, blended):
275
+ if isinstance(candidate, dict):
276
+ candidate["ranking_score"] = float(utility)
277
+ else:
278
+ try:
279
+ candidate.ranking_score = float(utility)
280
+ except (AttributeError, TypeError):
281
+ pass
282
+
272
283
  # Stable-sort descending so equal scores preserve original order.
273
284
  indexed = list(enumerate(candidates))
274
285
  indexed.sort(key=lambda pair: -blended[pair[0]])
@@ -11,7 +11,7 @@ Builds knowledge summaries using PageRank centrality + Louvain community detecti
11
11
  Runs after consolidation (every 6 hours or on-demand).
12
12
 
13
13
  Part of Qualixar | Author: Varun Pratap Bhardwaj
14
- License: Elastic-2.0
14
+ License: AGPL-3.0-or-later
15
15
  """
16
16
 
17
17
  from __future__ import annotations
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env python3
2
- # SPDX-License-Identifier: Elastic-2.0
2
+ # SPDX-License-Identifier: AGPL-3.0-or-later
3
3
  # Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
4
4
  # Part of Qualixar | Author: Varun Pratap Bhardwaj (qualixar.com | varunpratap.com)
5
5
  """
@@ -18,7 +18,7 @@ HR-08: Runs synchronously in main thread.
18
18
  HR-09: Access events are idempotent.
19
19
 
20
20
  Part of Qualixar | Author: Varun Pratap Bhardwaj
21
- License: Elastic-2.0
21
+ License: AGPL-3.0-or-later
22
22
  """
23
23
 
24
24
  from __future__ import annotations
@@ -60,7 +60,7 @@ class ForgettingScheduler:
60
60
  self._last_run_times: dict[str, float] = {}
61
61
 
62
62
  def run_decay_cycle(
63
- self, profile_id: str, *, force: bool = False,
63
+ self, profile_id: str, *, force: bool = False, dry_run: bool = False,
64
64
  ) -> dict:
65
65
  """Run a full decay cycle for all facts in a profile.
66
66
 
@@ -70,6 +70,7 @@ class ForgettingScheduler:
70
70
  Args:
71
71
  profile_id: Profile to process.
72
72
  force: If True, bypass interval check.
73
+ dry_run: Compute transitions without persisting retention or lifecycle.
73
74
 
74
75
  Returns:
75
76
  Stats dict: {total, active, warm, cold, archive, forgotten,
@@ -87,7 +88,8 @@ class ForgettingScheduler:
87
88
  facts_data = self._fetch_facts_with_metadata(profile_id)
88
89
 
89
90
  if not facts_data:
90
- self._last_run_times[profile_id] = now
91
+ if not dry_run:
92
+ self._last_run_times[profile_id] = now
91
93
  return {
92
94
  "total": 0, "active": 0, "warm": 0, "cold": 0,
93
95
  "archive": 0, "forgotten": 0, "transitions": 0,
@@ -100,7 +102,8 @@ class ForgettingScheduler:
100
102
  retention_results = self._ebbinghaus.batch_compute_retention(facts_data)
101
103
 
102
104
  # Step 4: Batch UPSERT into fact_retention
103
- self._db.batch_upsert_retention(retention_results, profile_id)
105
+ if not dry_run:
106
+ self._db.batch_upsert_retention(retention_results, profile_id)
104
107
 
105
108
  # Step 5: Count zones and transitions
106
109
  zone_counts = {"active": 0, "warm": 0, "cold": 0, "archive": 0, "forgotten": 0}
@@ -121,11 +124,13 @@ class ForgettingScheduler:
121
124
  forgotten_fact_ids.append(result["fact_id"])
122
125
 
123
126
  # Step 6: Soft-delete forgotten facts (HR-04)
124
- for fact_id in forgotten_fact_ids:
125
- self._soft_delete_with_audit(fact_id, profile_id)
127
+ if not dry_run:
128
+ for fact_id in forgotten_fact_ids:
129
+ self._soft_delete_with_audit(fact_id, profile_id)
126
130
 
127
131
  # Update last run time
128
- self._last_run_times[profile_id] = now
132
+ if not dry_run:
133
+ self._last_run_times[profile_id] = now
129
134
 
130
135
  return {
131
136
  "total": len(retention_results),
@@ -17,7 +17,7 @@ HR-08: Synchronous execution (no threading).
17
17
  HR-09: Audit trail for every change.
18
18
 
19
19
  Part of Qualixar | Author: Varun Pratap Bhardwaj
20
- License: Elastic-2.0
20
+ License: AGPL-3.0-or-later
21
21
  """
22
22
 
23
23
  from __future__ import annotations
@@ -208,7 +208,10 @@ class AdaptiveRanker:
208
208
  return self._rerank_heuristic(results, query_context)
209
209
 
210
210
  order = np.argsort(-scores, kind="stable")
211
- return [results[int(i)] for i in order]
211
+ return [
212
+ {**results[int(i)], "_adaptive_score": float(scores[int(i)])}
213
+ for i in order
214
+ ]
212
215
 
213
216
  # --- legacy load path (back-compat) --------------------------------
214
217
 
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env python3
2
- # SPDX-License-Identifier: Elastic-2.0
2
+ # SPDX-License-Identifier: AGPL-3.0-or-later
3
3
  # Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
4
4
  # Part of Qualixar | Author: Varun Pratap Bhardwaj (qualixar.com | varunpratap.com)
5
5
  """
@@ -44,6 +44,7 @@ from typing import Optional
44
44
  # Import the RAM semaphore at module scope so tests can monkeypatch
45
45
  # ``trigram_index.ram_reservation`` to a no-op on CI boxes with tight RAM.
46
46
  from superlocalmemory.core.ram_lock import ram_reservation
47
+ from superlocalmemory.infra.data_root import DynamicStatePath, state_path
47
48
 
48
49
 
49
50
  # --------------------------------------------------------------------------
@@ -205,7 +206,7 @@ class TrigramIndex:
205
206
  ``(entity_id, hits)`` candidates.
206
207
  """
207
208
 
208
- CACHE_DB_PATH: Path = Path.home() / ".superlocalmemory" / "active_brain_cache.db"
209
+ CACHE_DB_PATH: Path = DynamicStatePath("active_brain_cache.db")
209
210
  MAX_TRIGRAMS: int = 1_000_000
210
211
  LOOKUP_LIMIT: int = 10
211
212
  LOOKUP_MIN_HITS: int = 2
@@ -537,7 +538,7 @@ def get_or_none() -> Optional[TrigramIndex]:
537
538
  return _SINGLETON
538
539
  if not TrigramIndex.CACHE_DB_PATH.exists():
539
540
  return None
540
- default_source = Path.home() / ".superlocalmemory" / "memory.db"
541
+ default_source = state_path("memory.db")
541
542
  if not default_source.exists():
542
543
  return None
543
544
  _SINGLETON = TrigramIndex(source_db_path=default_source)
@@ -14,7 +14,7 @@ Providers:
14
14
  - ``"azure"``: Azure OpenAI (via AI Foundry deployment).
15
15
 
16
16
  Part of Qualixar | Author: Varun Pratap Bhardwaj
17
- License: Elastic-2.0
17
+ License: AGPL-3.0-or-later
18
18
  """
19
19
 
20
20
  from __future__ import annotations
@@ -34,7 +34,7 @@ References:
34
34
  Long-Term Memory. AAAI 2024.
35
35
 
36
36
  Part of Qualixar | Author: Varun Pratap Bhardwaj
37
- License: Elastic-2.0
37
+ License: AGPL-3.0-or-later
38
38
  """
39
39
 
40
40
  from __future__ import annotations
@@ -42,7 +42,7 @@ References:
42
42
  cases, bounds and applications. Entropy 22(4):404.
43
43
 
44
44
  Part of Qualixar | Author: Varun Pratap Bhardwaj
45
- License: Elastic-2.0
45
+ License: AGPL-3.0-or-later
46
46
  """
47
47
 
48
48
  from __future__ import annotations
@@ -19,7 +19,7 @@ Mathematical basis:
19
19
  on the statistical manifold of diagonal Gaussians
20
20
 
21
21
  Part of Qualixar | Author: Varun Pratap Bhardwaj
22
- License: Elastic-2.0
22
+ License: AGPL-3.0-or-later
23
23
  """
24
24
 
25
25
  from __future__ import annotations
@@ -19,7 +19,7 @@ Key properties:
19
19
  - Convergence: 1 step for well-separated patterns
20
20
 
21
21
  Part of Qualixar | Author: Varun Pratap Bhardwaj
22
- License: Elastic-2.0
22
+ License: AGPL-3.0-or-later
23
23
  """
24
24
 
25
25
  from __future__ import annotations
@@ -42,7 +42,7 @@ References:
42
42
  Probability Letters, 91, 59--67.
43
43
 
44
44
  Part of Qualixar | Author: Varun Pratap Bhardwaj
45
- License: Elastic-2.0
45
+ License: AGPL-3.0-or-later
46
46
  """
47
47
 
48
48
  from __future__ import annotations
@@ -26,7 +26,7 @@ References:
26
26
  the classical compact groups.
27
27
 
28
28
  Part of Qualixar | Author: Varun Pratap Bhardwaj
29
- License: Elastic-2.0
29
+ License: AGPL-3.0-or-later
30
30
  """
31
31
 
32
32
  from __future__ import annotations
@@ -41,6 +41,7 @@ import numpy as np
41
41
  from numpy.typing import NDArray
42
42
 
43
43
  from superlocalmemory.core.config import PolarQuantConfig
44
+ from superlocalmemory.infra.data_root import state_path
44
45
 
45
46
  logger = logging.getLogger(__name__)
46
47
 
@@ -113,9 +114,7 @@ class PolarQuantEncoder:
113
114
  """
114
115
  path_str = self._config.rotation_matrix_path
115
116
  if not path_str:
116
- path_str = str(
117
- Path.home() / ".superlocalmemory" / f"polar_rotation_{self._d}.npy",
118
- )
117
+ path_str = str(state_path(f"polar_rotation_{self._d}.npy"))
119
118
 
120
119
  path = Path(path_str)
121
120
 
@@ -27,7 +27,7 @@ References:
27
27
  - TurboQuant (ICLR 2026, arXiv 2504.19874).
28
28
 
29
29
  Part of Qualixar | Author: Varun Pratap Bhardwaj
30
- License: Elastic-2.0
30
+ License: AGPL-3.0-or-later
31
31
  """
32
32
 
33
33
  from __future__ import annotations
@@ -14,7 +14,7 @@ Severity = ||delta_0 f(e)|| / (||R_a emb_a|| + ||R_b emb_b||).
14
14
  Refs: Curry 2014 (arXiv:1303.3255), Hansen & Ghrist 2019, Robinson 2020.
15
15
 
16
16
  Part of Qualixar | Author: Varun Pratap Bhardwaj
17
- License: Elastic-2.0
17
+ License: AGPL-3.0-or-later
18
18
  """
19
19
  from __future__ import annotations
20
20
 
@@ -9,7 +9,7 @@ D_mse <= sqrt(3*pi/2) / 4^b. No scipy (HR-SCIPY-01). 2-byte "TQ" prefix on
9
9
  all BLOBs (HR-MIG-02). Bit-widths: 2, 4, 8 only (HR-3BIT-01).
10
10
 
11
11
  References: TurboQuant (arXiv 2504.19874), PolarQuant (arXiv 2502.02617).
12
- Part of Qualixar | Author: Varun Pratap Bhardwaj | License: Elastic-2.0
12
+ Part of Qualixar | Author: Varun Pratap Bhardwaj | License: AGPL-3.0-or-later
13
13
  """
14
14
 
15
15
  from __future__ import annotations
@@ -24,6 +24,7 @@ import numpy as np
24
24
  from numpy.typing import NDArray
25
25
 
26
26
  from superlocalmemory.core.config import PolarQuantConfig
27
+ from superlocalmemory.infra.data_root import canonical_data_root
27
28
 
28
29
  logger = logging.getLogger(__name__)
29
30
 
@@ -173,7 +174,7 @@ class TurboQuantEncoder:
173
174
  def _load_or_create_rotation_matrix(self) -> NDArray:
174
175
  """Load/create rotation matrix with copy-on-detect (AUDIT C4-MED-01)."""
175
176
  d = self._d
176
- slm_dir = Path.home() / ".superlocalmemory"
177
+ slm_dir = canonical_data_root()
177
178
 
178
179
  turbo_path_str = self._config.rotation_matrix_path
179
180
  if not turbo_path_str:
@@ -79,25 +79,26 @@ class DaemonPoolProxy:
79
79
  def store(
80
80
  self, content: str, metadata: dict | None = None,
81
81
  ) -> dict[str, Any]:
82
- body = json.dumps({
82
+ body = {
83
83
  "content": content,
84
84
  "tags": (metadata or {}).get("tags", ""),
85
85
  "metadata": metadata or {},
86
- }).encode()
87
- req = urllib.request.Request(
88
- self._url("/remember"),
89
- data=body,
90
- headers={"Content-Type": "application/json"},
91
- method="POST",
92
- )
86
+ "session_id": (metadata or {}).get("session_id", ""),
87
+ "idempotency_key": (metadata or {}).get("idempotency_key") or None,
88
+ }
93
89
  try:
94
- with urllib.request.urlopen(req, timeout=self._timeout) as resp:
95
- data = json.loads(resp.read().decode() or "{}")
90
+ # One identity-aware daemon client owns descriptor validation,
91
+ # capability delivery, and exact-instance targeting. A raw urllib
92
+ # POST here previously became unauthenticated when /remember was
93
+ # hardened and could also attach to a stale/foreign port.
94
+ from superlocalmemory.cli.daemon import daemon_request
95
+
96
+ data = daemon_request("POST", "/remember", body)
96
97
  except Exception as exc:
97
98
  logger.warning("daemon /remember failed: %s", exc)
98
99
  return {"ok": False, "error": str(exc)}
99
100
  if not isinstance(data, dict):
100
- return {"ok": False, "error": "non-dict response"}
101
+ return {"ok": False, "error": "owned daemon unavailable"}
101
102
  data.setdefault("ok", True)
102
103
  return data
103
104