superlocalmemory 3.6.22 → 3.7.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 (303) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/README.md +275 -72
  3. package/bin/slm-npm +43 -89
  4. package/docs/pi-dev-integration.md +43 -0
  5. package/ide/configs/antigravity-mcp.json +2 -2
  6. package/ide/configs/chatgpt-desktop-mcp.json +1 -1
  7. package/ide/configs/claude-desktop-mcp.json +2 -2
  8. package/ide/configs/windsurf-mcp.json +2 -2
  9. package/ide/hooks/context-hook.js +6 -2
  10. package/ide/hooks/post-recall-hook.js +7 -3
  11. package/ide/hooks/tool-event-hook.sh +2 -1
  12. package/package.json +19 -10
  13. package/plugin/.claude-plugin/plugin.json +1 -1
  14. package/plugin/_GENERATED.md +1 -1
  15. package/plugin/agents/slm-memory-advisor.md +1 -1
  16. package/plugin/requirements.txt +1 -1
  17. package/plugin/skills/slm-session/SKILL.md +1 -1
  18. package/plugin-src/rules/AGENTS.md +1 -1
  19. package/pyproject.toml +40 -8
  20. package/scripts/postinstall-interactive.js +17 -94
  21. package/scripts/postinstall.js +185 -258
  22. package/scripts/preuninstall.js +9 -50
  23. package/src/superlocalmemory/__init__.py +2 -2
  24. package/src/superlocalmemory/attribution/mathematical_dna.py +1 -1
  25. package/src/superlocalmemory/attribution/signer.py +34 -19
  26. package/src/superlocalmemory/attribution/watermark.py +1 -1
  27. package/src/superlocalmemory/cli/_lazy_init.py +3 -5
  28. package/src/superlocalmemory/cli/commands.py +490 -195
  29. package/src/superlocalmemory/cli/context_commands.py +5 -4
  30. package/src/superlocalmemory/cli/daemon.py +282 -187
  31. package/src/superlocalmemory/cli/db_migrate.py +3 -1
  32. package/src/superlocalmemory/cli/diagnostics_cmd.py +28 -0
  33. package/src/superlocalmemory/cli/evidence_cmd.py +103 -0
  34. package/src/superlocalmemory/cli/ingest_cmd.py +7 -3
  35. package/src/superlocalmemory/cli/main.py +128 -31
  36. package/src/superlocalmemory/cli/pending_store.py +54 -38
  37. package/src/superlocalmemory/cli/scale_engine_cmd.py +37 -0
  38. package/src/superlocalmemory/cli/service_installer.py +57 -52
  39. package/src/superlocalmemory/cli/setup_wizard.py +142 -88
  40. package/src/superlocalmemory/cli/version_banner.py +2 -1
  41. package/src/superlocalmemory/code_graph/config.py +3 -1
  42. package/src/superlocalmemory/core/backend_orchestrator.py +81 -21
  43. package/src/superlocalmemory/core/config.py +65 -20
  44. package/src/superlocalmemory/core/consolidation_engine.py +9 -7
  45. package/src/superlocalmemory/core/context_cache.py +56 -8
  46. package/src/superlocalmemory/core/derivation_lineage.py +246 -0
  47. package/src/superlocalmemory/core/embedding_worker.py +32 -20
  48. package/src/superlocalmemory/core/embeddings.py +54 -18
  49. package/src/superlocalmemory/core/engine.py +150 -104
  50. package/src/superlocalmemory/core/engine_ingestion.py +513 -0
  51. package/src/superlocalmemory/core/engine_wiring.py +2 -0
  52. package/src/superlocalmemory/core/evidence_bundle.py +526 -0
  53. package/src/superlocalmemory/core/fact_consolidator.py +5 -11
  54. package/src/superlocalmemory/core/graph_analyzer.py +2 -2
  55. package/src/superlocalmemory/core/health_monitor.py +4 -2
  56. package/src/superlocalmemory/core/ingestion_command.py +636 -0
  57. package/src/superlocalmemory/core/injection.py +69 -18
  58. package/src/superlocalmemory/core/lifecycle_state.py +153 -0
  59. package/src/superlocalmemory/core/maintenance.py +23 -22
  60. package/src/superlocalmemory/core/maintenance_scheduler.py +51 -35
  61. package/src/superlocalmemory/core/mutations.py +143 -0
  62. package/src/superlocalmemory/core/platform_utils.py +7 -4
  63. package/src/superlocalmemory/core/ram_lock.py +16 -5
  64. package/src/superlocalmemory/core/rate_limit.py +1 -1
  65. package/src/superlocalmemory/core/recall_pipeline.py +60 -101
  66. package/src/superlocalmemory/core/recall_worker.py +76 -59
  67. package/src/superlocalmemory/core/registry.py +1 -1
  68. package/src/superlocalmemory/core/scale_engine.py +293 -0
  69. package/src/superlocalmemory/core/score_contract.py +62 -0
  70. package/src/superlocalmemory/core/security_primitives.py +3 -1
  71. package/src/superlocalmemory/core/slm_disabled.py +3 -5
  72. package/src/superlocalmemory/core/store_pipeline.py +172 -40
  73. package/src/superlocalmemory/core/tier_manager.py +32 -20
  74. package/src/superlocalmemory/core/worker_pool.py +13 -4
  75. package/src/superlocalmemory/dynamics/activation_guided_quantization.py +1 -1
  76. package/src/superlocalmemory/dynamics/eap_scheduler.py +10 -3
  77. package/src/superlocalmemory/dynamics/ebbinghaus_langevin_coupling.py +1 -1
  78. package/src/superlocalmemory/dynamics/fisher_langevin_coupling.py +1 -1
  79. package/src/superlocalmemory/encoding/auto_linker.py +1 -1
  80. package/src/superlocalmemory/encoding/cognitive_consolidator.py +7 -16
  81. package/src/superlocalmemory/encoding/consolidator.py +22 -5
  82. package/src/superlocalmemory/encoding/fact_extractor.py +1 -1
  83. package/src/superlocalmemory/encoding/foresight.py +2 -0
  84. package/src/superlocalmemory/encoding/graph_builder.py +1 -1
  85. package/src/superlocalmemory/encoding/temporal_parser.py +2 -0
  86. package/src/superlocalmemory/evaluation/__init__.py +13 -0
  87. package/src/superlocalmemory/evaluation/calibration.py +308 -0
  88. package/src/superlocalmemory/evolution/skill_evolver.py +2 -1
  89. package/src/superlocalmemory/graph/cozo_backend.py +256 -23
  90. package/src/superlocalmemory/hooks/_outcome_common.py +21 -11
  91. package/src/superlocalmemory/hooks/antigravity_adapter.py +10 -31
  92. package/src/superlocalmemory/hooks/auto_invoker.py +25 -27
  93. package/src/superlocalmemory/hooks/auto_recall.py +31 -6
  94. package/src/superlocalmemory/hooks/auto_recall_hook.py +13 -33
  95. package/src/superlocalmemory/hooks/before_web_hook.py +9 -7
  96. package/src/superlocalmemory/hooks/claude_code_hooks.py +126 -39
  97. package/src/superlocalmemory/hooks/codex_assets.py +59 -0
  98. package/src/superlocalmemory/hooks/codex_hooks.py +186 -0
  99. package/src/superlocalmemory/hooks/context_payload.py +1 -1
  100. package/src/superlocalmemory/hooks/copilot_adapter.py +9 -24
  101. package/src/superlocalmemory/hooks/cursor_adapter.py +10 -32
  102. package/src/superlocalmemory/hooks/hook_daemon.py +4 -2
  103. package/src/superlocalmemory/hooks/hook_handlers.py +241 -55
  104. package/src/superlocalmemory/hooks/memory_protocol.py +5 -3
  105. package/src/superlocalmemory/hooks/post_tool_async_hook.py +4 -2
  106. package/src/superlocalmemory/hooks/session_registry.py +15 -8
  107. package/src/superlocalmemory/hooks/stop_outcome_hook.py +10 -6
  108. package/src/superlocalmemory/hooks/topic_shift_hook.py +42 -12
  109. package/src/superlocalmemory/hooks/user_prompt_hook.py +9 -14
  110. package/src/superlocalmemory/hooks/user_prompt_rehash_hook.py +19 -11
  111. package/src/superlocalmemory/infra/auth_middleware.py +38 -5
  112. package/src/superlocalmemory/infra/backup.py +7 -5
  113. package/src/superlocalmemory/infra/cloud_backup.py +18 -8
  114. package/src/superlocalmemory/infra/daemon_identity.py +248 -0
  115. package/src/superlocalmemory/infra/data_root.py +199 -0
  116. package/src/superlocalmemory/infra/event_bus.py +3 -1
  117. package/src/superlocalmemory/infra/local_diagnostics.py +327 -0
  118. package/src/superlocalmemory/infra/process_reaper.py +23 -0
  119. package/src/superlocalmemory/ingestion/adapter_manager.py +27 -9
  120. package/src/superlocalmemory/ingestion/base_adapter.py +25 -31
  121. package/src/superlocalmemory/ingestion/calendar_adapter.py +13 -4
  122. package/src/superlocalmemory/ingestion/credentials.py +14 -7
  123. package/src/superlocalmemory/ingestion/gmail_adapter.py +13 -4
  124. package/src/superlocalmemory/ingestion/transcript_adapter.py +7 -2
  125. package/src/superlocalmemory/learning/consolidation_quantization_worker.py +1 -1
  126. package/src/superlocalmemory/learning/ensemble.py +11 -0
  127. package/src/superlocalmemory/learning/entity_compiler.py +1 -1
  128. package/src/superlocalmemory/learning/feedback.py +1 -1
  129. package/src/superlocalmemory/learning/forgetting_scheduler.py +12 -7
  130. package/src/superlocalmemory/learning/quantization_scheduler.py +1 -1
  131. package/src/superlocalmemory/learning/ranker.py +4 -1
  132. package/src/superlocalmemory/learning/source_quality.py +1 -1
  133. package/src/superlocalmemory/learning/trigram_index.py +3 -2
  134. package/src/superlocalmemory/llm/backbone.py +13 -8
  135. package/src/superlocalmemory/math/ebbinghaus.py +1 -1
  136. package/src/superlocalmemory/math/fisher.py +1 -1
  137. package/src/superlocalmemory/math/fisher_quantized.py +1 -1
  138. package/src/superlocalmemory/math/hopfield.py +1 -1
  139. package/src/superlocalmemory/math/langevin.py +1 -1
  140. package/src/superlocalmemory/math/polar_quant.py +3 -4
  141. package/src/superlocalmemory/math/qjl.py +1 -1
  142. package/src/superlocalmemory/math/sheaf.py +1 -1
  143. package/src/superlocalmemory/math/turbo_quant.py +3 -2
  144. package/src/superlocalmemory/mcp/_daemon_proxy.py +12 -11
  145. package/src/superlocalmemory/mcp/_pool_adapter.py +27 -0
  146. package/src/superlocalmemory/mcp/http_transport.py +53 -0
  147. package/src/superlocalmemory/mcp/server.py +39 -13
  148. package/src/superlocalmemory/mcp/shared.py +69 -3
  149. package/src/superlocalmemory/mcp/tools_active.py +141 -31
  150. package/src/superlocalmemory/mcp/tools_core.py +128 -29
  151. package/src/superlocalmemory/mcp/tools_evolution.py +5 -7
  152. package/src/superlocalmemory/mcp/tools_learning.py +42 -2
  153. package/src/superlocalmemory/mcp/tools_mesh.py +7 -23
  154. package/src/superlocalmemory/mcp/tools_optimize.py +8 -1
  155. package/src/superlocalmemory/mcp/tools_v28.py +23 -2
  156. package/src/superlocalmemory/mcp/tools_v3.py +26 -1
  157. package/src/superlocalmemory/mcp/tools_v33.py +56 -17
  158. package/src/superlocalmemory/mesh/broker.py +2 -0
  159. package/src/superlocalmemory/mesh/remote_sync.py +50 -12
  160. package/src/superlocalmemory/optimize/cache/manager.py +77 -1
  161. package/src/superlocalmemory/optimize/cache/semantic.py +23 -3
  162. package/src/superlocalmemory/optimize/compress/ccr.py +4 -0
  163. package/src/superlocalmemory/optimize/compress/router.py +6 -1
  164. package/src/superlocalmemory/optimize/config/__init__.py +5 -0
  165. package/src/superlocalmemory/optimize/config/store.py +6 -4
  166. package/src/superlocalmemory/optimize/proxy/_helpers.py +15 -5
  167. package/src/superlocalmemory/optimize/proxy/capture.py +3 -2
  168. package/src/superlocalmemory/optimize/proxy/server.py +2 -2
  169. package/src/superlocalmemory/optimize/storage/db.py +14 -13
  170. package/src/superlocalmemory/retrieval/agentic.py +1 -1
  171. package/src/superlocalmemory/retrieval/ann_index.py +1 -1
  172. package/src/superlocalmemory/retrieval/bm25_channel.py +35 -11
  173. package/src/superlocalmemory/retrieval/bridge_discovery.py +73 -8
  174. package/src/superlocalmemory/retrieval/engine.py +169 -79
  175. package/src/superlocalmemory/retrieval/entity_channel.py +289 -67
  176. package/src/superlocalmemory/retrieval/forgetting_filter.py +1 -1
  177. package/src/superlocalmemory/retrieval/fusion.py +1 -1
  178. package/src/superlocalmemory/retrieval/hopfield_channel.py +118 -30
  179. package/src/superlocalmemory/retrieval/profile_channel.py +1 -1
  180. package/src/superlocalmemory/retrieval/quantization_aware_search.py +16 -10
  181. package/src/superlocalmemory/retrieval/reranker.py +56 -20
  182. package/src/superlocalmemory/retrieval/scope_policy.py +85 -0
  183. package/src/superlocalmemory/retrieval/semantic_channel.py +122 -14
  184. package/src/superlocalmemory/retrieval/spreading_activation.py +141 -25
  185. package/src/superlocalmemory/retrieval/strategy.py +1 -1
  186. package/src/superlocalmemory/retrieval/temporal_channel.py +30 -15
  187. package/src/superlocalmemory/retrieval/vector_store.py +1 -1
  188. package/src/superlocalmemory/server/api.py +10 -7
  189. package/src/superlocalmemory/server/bandit_loops.py +4 -2
  190. package/src/superlocalmemory/server/recall_serializer.py +24 -0
  191. package/src/superlocalmemory/server/route_mutations.py +84 -0
  192. package/src/superlocalmemory/server/routes/agents.py +8 -6
  193. package/src/superlocalmemory/server/routes/brain.py +14 -12
  194. package/src/superlocalmemory/server/routes/chat.py +29 -12
  195. package/src/superlocalmemory/server/routes/data_io.py +55 -24
  196. package/src/superlocalmemory/server/routes/helpers.py +29 -4
  197. package/src/superlocalmemory/server/routes/ingest.py +53 -36
  198. package/src/superlocalmemory/server/routes/memories.py +104 -43
  199. package/src/superlocalmemory/server/routes/mesh.py +31 -0
  200. package/src/superlocalmemory/server/routes/profiles.py +26 -4
  201. package/src/superlocalmemory/server/routes/tiers.py +43 -11
  202. package/src/superlocalmemory/server/routes/timeline.py +5 -1
  203. package/src/superlocalmemory/server/routes/v3_api.py +76 -21
  204. package/src/superlocalmemory/server/security_middleware.py +1 -1
  205. package/src/superlocalmemory/server/ui.py +6 -3
  206. package/src/superlocalmemory/server/unified_daemon.py +680 -293
  207. package/src/superlocalmemory/server/write_identity.py +147 -0
  208. package/src/superlocalmemory/storage/access_log.py +4 -3
  209. package/src/superlocalmemory/storage/database.py +118 -25
  210. package/src/superlocalmemory/storage/migration_runner.py +84 -1
  211. package/src/superlocalmemory/storage/migration_v33.py +1 -1
  212. package/src/superlocalmemory/storage/migrations/M002_model_state_history.py +6 -60
  213. package/src/superlocalmemory/storage/migrations/M018_ingestion_operations.py +120 -0
  214. package/src/superlocalmemory/storage/migrations/M019_derivation_lineage.py +54 -0
  215. package/src/superlocalmemory/storage/migrations/M020_model_state_integrity.py +52 -0
  216. package/src/superlocalmemory/storage/migrations/__init__.py +5 -0
  217. package/src/superlocalmemory/storage/models.py +16 -0
  218. package/src/superlocalmemory/storage/quantized_store.py +20 -3
  219. package/src/superlocalmemory/storage/v2_migrator.py +5 -3
  220. package/src/superlocalmemory/ui/favicon.svg +5 -0
  221. package/src/superlocalmemory/ui/index.html +1 -0
  222. package/src/superlocalmemory/ui/js/compliance.js +1 -1
  223. package/src/superlocalmemory/ui/js/core.js +49 -8
  224. package/src/superlocalmemory/ui/js/dashboard.js +23 -2
  225. package/src/superlocalmemory/ui/js/feedback.js +1 -1
  226. package/src/superlocalmemory/ui/js/graph-filters.js +1 -1
  227. package/src/superlocalmemory/ui/js/graph-ui.js +1 -1
  228. package/src/superlocalmemory/ui/js/lifecycle.js +1 -1
  229. package/src/superlocalmemory/ui/js/ng-mesh.js +15 -49
  230. package/src/superlocalmemory/ui/js/settings.js +4 -2
  231. package/src/superlocalmemory/vector/lancedb_backend.py +57 -9
  232. package/bin/slm +0 -59
  233. package/bin/slm.bat +0 -77
  234. package/bin/slm.cmd +0 -5
  235. package/ide/integrations/langchain/README.md +0 -106
  236. package/ide/integrations/langchain/langchain_superlocalmemory/__init__.py +0 -9
  237. package/ide/integrations/langchain/langchain_superlocalmemory/chat_message_history.py +0 -201
  238. package/ide/integrations/langchain/pyproject.toml +0 -38
  239. package/ide/integrations/langchain/tests/__init__.py +0 -3
  240. package/ide/integrations/langchain/tests/test_chat_message_history.py +0 -215
  241. package/ide/integrations/langchain/tests/test_security.py +0 -117
  242. package/ide/integrations/llamaindex/README.md +0 -81
  243. package/ide/integrations/llamaindex/llama_index/storage/chat_store/superlocalmemory/__init__.py +0 -9
  244. package/ide/integrations/llamaindex/llama_index/storage/chat_store/superlocalmemory/base.py +0 -316
  245. package/ide/integrations/llamaindex/pyproject.toml +0 -43
  246. package/ide/integrations/llamaindex/tests/__init__.py +0 -3
  247. package/ide/integrations/llamaindex/tests/test_chat_store.py +0 -294
  248. package/ide/integrations/llamaindex/tests/test_security.py +0 -241
  249. package/plugin-src/.mcp.json +0 -12
  250. package/plugin-src/agents/slm-memory-advisor.md +0 -44
  251. package/plugin-src/agents/slm-optimize-advisor.md +0 -38
  252. package/plugin-src/hooks/.gitkeep +0 -0
  253. package/plugin-src/hooks/hooks.json +0 -23
  254. package/plugin-src/manifest.json +0 -25
  255. package/plugin-src/requirements.txt +0 -1
  256. package/plugin-src/rules/CLAUDE.md.fragment +0 -44
  257. package/plugin-src/scripts/ensure-venv.bat +0 -122
  258. package/plugin-src/scripts/ensure-venv.sh +0 -105
  259. package/plugin-src/scripts/slm-launch +0 -15
  260. package/plugin-src/scripts/slm-launch.bat +0 -17
  261. package/plugin-src/settings.json +0 -16
  262. package/plugin-src/skills/slm-cache/SKILL.md +0 -140
  263. package/plugin-src/skills/slm-compress/SKILL.md +0 -143
  264. package/plugin-src/skills/slm-graph/SKILL.md +0 -300
  265. package/plugin-src/skills/slm-recall/SKILL.md +0 -204
  266. package/plugin-src/skills/slm-remember/SKILL.md +0 -194
  267. package/plugin-src/skills/slm-session/SKILL.md +0 -207
  268. package/plugin-src/skills/slm-status/SKILL.md +0 -149
  269. package/scripts/__tests__/build-plugin.test.mjs +0 -613
  270. package/scripts/_savings_math.py +0 -270
  271. package/scripts/build-dmg.sh +0 -417
  272. package/scripts/build-plugin.js +0 -742
  273. package/scripts/build-slm-hook.ps1 +0 -40
  274. package/scripts/build-slm-hook.sh +0 -45
  275. package/scripts/build_entry.py +0 -452
  276. package/scripts/ci/stage5b_gate.sh +0 -50
  277. package/scripts/dogfood_savings.py +0 -490
  278. package/scripts/generate-thumbnails.py +0 -218
  279. package/scripts/install-skills.ps1 +0 -4
  280. package/scripts/install-skills.sh +0 -5
  281. package/scripts/install.ps1 +0 -701
  282. package/scripts/install.sh +0 -1015
  283. package/scripts/postinstall_binary.js +0 -287
  284. package/scripts/prepack.js +0 -33
  285. package/scripts/release_manifest.py +0 -273
  286. package/scripts/slm-hook.spec +0 -56
  287. package/scripts/start-dashboard.ps1 +0 -52
  288. package/scripts/start-dashboard.sh +0 -41
  289. package/scripts/sync-wiki.ps1 +0 -127
  290. package/scripts/sync-wiki.sh +0 -82
  291. package/scripts/test-dmg.sh +0 -161
  292. package/scripts/test-npm-package.ps1 +0 -252
  293. package/scripts/test-npm-package.sh +0 -207
  294. package/scripts/verify-install.ps1 +0 -294
  295. package/scripts/verify-install.sh +0 -266
  296. package/scripts/verify-v27.ps1 +0 -301
  297. package/scripts/verify-v27.sh +0 -233
  298. package/src/superlocalmemory.egg-info/PKG-INFO +0 -513
  299. package/src/superlocalmemory.egg-info/SOURCES.txt +0 -529
  300. package/src/superlocalmemory.egg-info/dependency_links.txt +0 -1
  301. package/src/superlocalmemory.egg-info/entry_points.txt +0 -2
  302. package/src/superlocalmemory.egg-info/requires.txt +0 -71
  303. package/src/superlocalmemory.egg-info/top_level.txt +0 -1
@@ -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
@@ -103,7 +103,9 @@ class LLMBackbone:
103
103
  self._default_temperature = config.temperature
104
104
  self._default_max_tokens = config.max_tokens
105
105
 
106
- # Resolve API key: config > environment variable.
106
+ # Resolve API key: config > environment variable. A custom api_base
107
+ # with an empty api_key is treated as intentionally keyless so local
108
+ # OpenAI-compatible endpoints do not inherit ambient cloud keys.
107
109
  if self._provider == "ollama":
108
110
  self._api_key = ""
109
111
  host = config.api_base or os.environ.get(
@@ -111,19 +113,22 @@ class LLMBackbone:
111
113
  )
112
114
  self._base_url = f"{host.rstrip('/')}/api/chat"
113
115
  elif self._provider == "openrouter":
114
- self._api_key = config.api_key or os.environ.get(
115
- _ENV_KEYS.get(self._provider, ""), "",
116
- )
116
+ self._api_key = self._resolve_api_key(config)
117
117
  self._base_url = config.api_base or _OPENROUTER_URL
118
118
  elif self._provider:
119
- self._api_key = config.api_key or os.environ.get(
120
- _ENV_KEYS.get(self._provider, ""), "",
121
- )
119
+ self._api_key = self._resolve_api_key(config)
122
120
  self._base_url = config.api_base
123
121
  else:
124
122
  self._api_key = ""
125
123
  self._base_url = ""
126
124
 
125
+ def _resolve_api_key(self, config: LLMConfig) -> str:
126
+ if config.api_key:
127
+ return config.api_key
128
+ if config.api_base:
129
+ return ""
130
+ return os.environ.get(_ENV_KEYS.get(self._provider, ""), "")
131
+
127
132
  # -- Properties ---------------------------------------------------------
128
133
 
129
134
  def is_available(self) -> bool:
@@ -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
 
@@ -34,6 +34,10 @@ class PoolRecallItem:
34
34
  fact: PoolFact = field(default_factory=PoolFact)
35
35
  score: float = 0.0
36
36
  confidence: float = 0.0
37
+ relevance_score: float = 0.0
38
+ ranking_score: float | None = None
39
+ memory_confidence: float = 0.0
40
+ rank_position: int = 0
37
41
  trust_score: float = 0.0
38
42
  channel_scores: dict[str, float] = field(default_factory=dict)
39
43
  evidence_chain: list[Any] = field(default_factory=list)
@@ -46,6 +50,12 @@ class PoolRecallResponse:
46
50
  retrieval_time_ms: float = 0.0
47
51
  channel_weights: dict[str, float] = field(default_factory=dict)
48
52
  total_candidates: int = 0
53
+ score_contract_version: str = "2"
54
+ calibration_status: str = "uncalibrated"
55
+ calibration_id: str | None = None
56
+ answer_confidence: float | None = None
57
+ abstained: bool = False
58
+ abstention_reason: str | None = None
49
59
 
50
60
 
51
61
  class PoolError(RuntimeError):
@@ -107,6 +117,15 @@ def pool_recall(query: str, limit: int = 10, **kwargs: Any) -> PoolRecallRespons
107
117
  ),
108
118
  score=float(item.get("score", 0.0)),
109
119
  confidence=float(item.get("confidence", 0.0)),
120
+ relevance_score=float(item.get("relevance_score", item.get("score", 0.0))),
121
+ ranking_score=(
122
+ float(item["ranking_score"])
123
+ if item.get("ranking_score") is not None else None
124
+ ),
125
+ memory_confidence=float(
126
+ item.get("memory_confidence", item.get("confidence", 0.0))
127
+ ),
128
+ rank_position=int(item.get("rank_position", 0)),
110
129
  trust_score=float(item.get("trust_score", 0.0)),
111
130
  channel_scores=item.get("channel_scores", {}) or {},
112
131
  evidence_chain=list(item.get("evidence_chain", []) or []),
@@ -122,6 +141,14 @@ def pool_recall(query: str, limit: int = 10, **kwargs: Any) -> PoolRecallRespons
122
141
  if isinstance(raw, dict) else {},
123
142
  total_candidates=int(raw.get("total_candidates", 0))
124
143
  if isinstance(raw, dict) else 0,
144
+ score_contract_version=str(raw.get("score_contract_version", "2"))
145
+ if isinstance(raw, dict) else "2",
146
+ calibration_status=str(raw.get("calibration_status", "uncalibrated"))
147
+ if isinstance(raw, dict) else "uncalibrated",
148
+ calibration_id=raw.get("calibration_id") if isinstance(raw, dict) else None,
149
+ answer_confidence=raw.get("answer_confidence") if isinstance(raw, dict) else None,
150
+ abstained=bool(raw.get("abstained", False)) if isinstance(raw, dict) else False,
151
+ abstention_reason=raw.get("abstention_reason") if isinstance(raw, dict) else None,
125
152
  )
126
153
 
127
154
 
@@ -0,0 +1,53 @@
1
+ # Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
2
+ # Licensed under AGPL-3.0-or-later - see LICENSE file
3
+ # Part of SuperLocalMemory V3 | https://qualixar.com | https://varunpratap.com
4
+
5
+ """Resource-safe FastMCP Streamable-HTTP integration.
6
+
7
+ MCP SDK 1.27.1 passes an AnyIO ``MemoryObjectReceiveStream`` directly to
8
+ ``EventSourceResponse`` for every JSON-RPC POST. The response consumes that
9
+ stream but does not close it after normal iteration, leaving one receive
10
+ endpoint per request for the garbage collector. The response is the owner of
11
+ that per-request iterator, so SLM closes it at the response boundary.
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ from mcp.server.fastmcp import FastMCP
17
+ from sse_starlette.sse import EventSourceResponse
18
+ from starlette.types import Receive, Scope, Send
19
+
20
+
21
+ class ClosingEventSourceResponse(EventSourceResponse):
22
+ """EventSourceResponse that closes the async iterator it consumes."""
23
+
24
+ async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
25
+ try:
26
+ await super().__call__(scope, receive, send)
27
+ finally:
28
+ close = getattr(self.body_iterator, "aclose", None)
29
+ if close is not None:
30
+ await close()
31
+
32
+
33
+ def install_streamable_http_resource_guard() -> None:
34
+ """Install the response owner used by MCP's Streamable-HTTP transport."""
35
+ from mcp.server import streamable_http
36
+
37
+ streamable_http.EventSourceResponse = ClosingEventSourceResponse
38
+
39
+
40
+ class SLMFastMCP(FastMCP):
41
+ """FastMCP with SLM release identity and deterministic SSE cleanup."""
42
+
43
+ def __init__(self, *args, product_version: str = "3.7.0", **kwargs) -> None:
44
+ super().__init__(*args, **kwargs)
45
+ # FastMCP delegates the initialize response to the low-level MCP
46
+ # server. Without an explicit value it reports the installed ``mcp``
47
+ # library version, which makes an SLM 3.7 server identify itself as
48
+ # (for example) 1.27.1 to every IDE client.
49
+ self._mcp_server.version = product_version
50
+
51
+ def streamable_http_app(self):
52
+ install_streamable_http_resource_guard()
53
+ return super().streamable_http_app()
@@ -27,11 +27,11 @@ _os.environ.setdefault('SLM_SKIP_DEP_CHECK', '1')
27
27
  import logging
28
28
  import sys
29
29
 
30
- from mcp.server.fastmcp import FastMCP
30
+ from superlocalmemory.mcp.http_transport import SLMFastMCP
31
31
 
32
32
  logger = logging.getLogger(__name__)
33
33
 
34
- server = FastMCP("SuperLocalMemory V3")
34
+ server = SLMFastMCP("SuperLocalMemory V3")
35
35
 
36
36
  # Lazy engine singleton -------------------------------------------------------
37
37
 
@@ -175,6 +175,18 @@ _PROFILE_DEFINITIONS: dict[str, frozenset[str]] = {
175
175
  "mesh": _PROFILE_MESH,
176
176
  } # "whole" intentionally absent — maps to raw server (D-2 LOCKED)
177
177
 
178
+ # Compatibility aliases published by the v3.6 README. Keep these explicit so
179
+ # a stale client configuration has one deterministic meaning and emits a
180
+ # migration warning. Any other value is a configuration error (fail closed).
181
+ _PROFILE_ALIASES: dict[str, str] = {
182
+ "core14": "core",
183
+ "code20": "code",
184
+ "full38": "full",
185
+ "power50": "power",
186
+ "mesh8": "mesh",
187
+ "whole81": "whole",
188
+ }
189
+
178
190
  _profile = _os_reg.environ.get("SLM_MCP_PROFILE", "").strip().lower()
179
191
 
180
192
 
@@ -188,19 +200,26 @@ def _resolve_profile_allowed(
188
200
  Returns:
189
201
  None — for "" (no selection) or "whole" (raw server, all tools).
190
202
  frozenset — the profile's tool set for known profiles.
191
- essential — fail-open fallback for unknown non-empty profiles (+ warning).
203
+
204
+ Raises:
205
+ ValueError: if ``profile`` is neither canonical nor an explicitly
206
+ supported compatibility alias.
192
207
  """
193
- if not profile or profile == "whole":
208
+ canonical = _PROFILE_ALIASES.get(profile, profile)
209
+ if canonical != profile:
210
+ logger.warning(
211
+ "SLM_MCP_PROFILE=%r is deprecated; use %r instead.",
212
+ profile,
213
+ canonical,
214
+ )
215
+ if not canonical or canonical == "whole":
194
216
  return None
195
- if profile in definitions:
196
- return definitions[profile]
197
- logger.warning(
198
- "SLM_MCP_PROFILE=%r is not a recognised profile "
199
- "(valid: %s, whole); falling back to essential tools.",
200
- profile,
201
- ", ".join(sorted(definitions)),
217
+ if canonical in definitions:
218
+ return definitions[canonical]
219
+ valid = ", ".join((*sorted(definitions), "whole"))
220
+ raise ValueError(
221
+ f"SLM_MCP_PROFILE={profile!r} is not recognised; valid profiles: {valid}"
202
222
  )
203
- return essential
204
223
 
205
224
 
206
225
  class _FilteredServer:
@@ -237,7 +256,14 @@ elif _user_allowlist_str:
237
256
  elif _profile == "whole":
238
257
  _target = server # NEW raw-server
239
258
  elif _profile:
240
- _target = _FilteredServer(server, _resolve_profile_allowed(_profile, _PROFILE_DEFINITIONS, _ESSENTIAL_TOOLS)) # NEW
259
+ _profile_allowed = _resolve_profile_allowed(
260
+ _profile, _PROFILE_DEFINITIONS, _ESSENTIAL_TOOLS
261
+ )
262
+ _target = (
263
+ server
264
+ if _profile_allowed is None
265
+ else _FilteredServer(server, _profile_allowed)
266
+ )
241
267
  else:
242
268
  _target = _FilteredServer(server, _ESSENTIAL_TOOLS) # default (unchanged)
243
269