superlocalmemory 3.4.5 → 3.4.8

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 (232) hide show
  1. package/ide/hooks/tool-event-hook.sh +46 -0
  2. package/package.json +1 -1
  3. package/pyproject.toml +1 -1
  4. package/src/superlocalmemory/attribution/mathematical_dna.py +1 -1
  5. package/src/superlocalmemory/attribution/signer.py +1 -1
  6. package/src/superlocalmemory/attribution/watermark.py +1 -1
  7. package/src/superlocalmemory/cli/__init__.py +1 -1
  8. package/src/superlocalmemory/cli/commands.py +9 -1
  9. package/src/superlocalmemory/cli/daemon.py +57 -27
  10. package/src/superlocalmemory/cli/ingest_cmd.py +261 -0
  11. package/src/superlocalmemory/cli/json_output.py +1 -1
  12. package/src/superlocalmemory/cli/main.py +21 -1
  13. package/src/superlocalmemory/cli/migrate_cmd.py +1 -1
  14. package/src/superlocalmemory/cli/pending_store.py +1 -1
  15. package/src/superlocalmemory/cli/post_install.py +1 -1
  16. package/src/superlocalmemory/cli/service_installer.py +1 -1
  17. package/src/superlocalmemory/cli/setup_wizard.py +1 -1
  18. package/src/superlocalmemory/code_graph/__init__.py +1 -1
  19. package/src/superlocalmemory/code_graph/blast_radius.py +1 -1
  20. package/src/superlocalmemory/code_graph/bridge/__init__.py +1 -1
  21. package/src/superlocalmemory/code_graph/bridge/entity_resolver.py +1 -1
  22. package/src/superlocalmemory/code_graph/bridge/event_listeners.py +1 -1
  23. package/src/superlocalmemory/code_graph/bridge/fact_enricher.py +1 -1
  24. package/src/superlocalmemory/code_graph/bridge/hebbian_linker.py +1 -1
  25. package/src/superlocalmemory/code_graph/bridge/temporal_checker.py +1 -1
  26. package/src/superlocalmemory/code_graph/changes.py +1 -1
  27. package/src/superlocalmemory/code_graph/communities.py +1 -1
  28. package/src/superlocalmemory/code_graph/config.py +1 -1
  29. package/src/superlocalmemory/code_graph/database.py +1 -1
  30. package/src/superlocalmemory/code_graph/extractors/__init__.py +1 -1
  31. package/src/superlocalmemory/code_graph/extractors/python.py +1 -1
  32. package/src/superlocalmemory/code_graph/extractors/typescript.py +1 -1
  33. package/src/superlocalmemory/code_graph/flows.py +1 -1
  34. package/src/superlocalmemory/code_graph/git_hooks.py +1 -1
  35. package/src/superlocalmemory/code_graph/graph_engine.py +1 -1
  36. package/src/superlocalmemory/code_graph/graph_store.py +1 -1
  37. package/src/superlocalmemory/code_graph/incremental.py +1 -1
  38. package/src/superlocalmemory/code_graph/models.py +1 -1
  39. package/src/superlocalmemory/code_graph/parser.py +1 -1
  40. package/src/superlocalmemory/code_graph/resolver.py +1 -1
  41. package/src/superlocalmemory/code_graph/search.py +1 -1
  42. package/src/superlocalmemory/code_graph/service.py +1 -1
  43. package/src/superlocalmemory/code_graph/watcher.py +1 -1
  44. package/src/superlocalmemory/compliance/abac.py +1 -1
  45. package/src/superlocalmemory/compliance/audit.py +1 -1
  46. package/src/superlocalmemory/compliance/eu_ai_act.py +1 -1
  47. package/src/superlocalmemory/compliance/gdpr.py +1 -1
  48. package/src/superlocalmemory/compliance/lifecycle.py +1 -1
  49. package/src/superlocalmemory/compliance/retention.py +1 -1
  50. package/src/superlocalmemory/compliance/scheduler.py +1 -1
  51. package/src/superlocalmemory/core/config.py +1 -1
  52. package/src/superlocalmemory/core/consolidation_engine.py +52 -1
  53. package/src/superlocalmemory/core/embedding_worker.py +1 -1
  54. package/src/superlocalmemory/core/embeddings.py +1 -1
  55. package/src/superlocalmemory/core/engine.py +17 -1
  56. package/src/superlocalmemory/core/engine_wiring.py +21 -1
  57. package/src/superlocalmemory/core/graph_analyzer.py +15 -1
  58. package/src/superlocalmemory/core/health_monitor.py +1 -1
  59. package/src/superlocalmemory/core/hooks.py +1 -1
  60. package/src/superlocalmemory/core/maintenance.py +1 -1
  61. package/src/superlocalmemory/core/maintenance_scheduler.py +1 -1
  62. package/src/superlocalmemory/core/modes.py +1 -1
  63. package/src/superlocalmemory/core/ollama_embedder.py +1 -1
  64. package/src/superlocalmemory/core/profiles.py +1 -1
  65. package/src/superlocalmemory/core/recall_pipeline.py +16 -3
  66. package/src/superlocalmemory/core/recall_worker.py +1 -1
  67. package/src/superlocalmemory/core/registry.py +1 -1
  68. package/src/superlocalmemory/core/reranker_worker.py +1 -1
  69. package/src/superlocalmemory/core/store_pipeline.py +1 -1
  70. package/src/superlocalmemory/core/summarizer.py +1 -1
  71. package/src/superlocalmemory/core/worker_pool.py +1 -1
  72. package/src/superlocalmemory/dynamics/activation_guided_quantization.py +1 -1
  73. package/src/superlocalmemory/dynamics/eap_scheduler.py +1 -1
  74. package/src/superlocalmemory/dynamics/ebbinghaus_langevin_coupling.py +1 -1
  75. package/src/superlocalmemory/dynamics/fisher_langevin_coupling.py +1 -1
  76. package/src/superlocalmemory/encoding/auto_linker.py +1 -1
  77. package/src/superlocalmemory/encoding/cognitive_consolidator.py +1 -1
  78. package/src/superlocalmemory/encoding/consolidator.py +1 -1
  79. package/src/superlocalmemory/encoding/context_generator.py +1 -1
  80. package/src/superlocalmemory/encoding/emotional.py +1 -1
  81. package/src/superlocalmemory/encoding/entity_resolver.py +45 -6
  82. package/src/superlocalmemory/encoding/entropy_gate.py +1 -1
  83. package/src/superlocalmemory/encoding/fact_extractor.py +1 -1
  84. package/src/superlocalmemory/encoding/foresight.py +1 -1
  85. package/src/superlocalmemory/encoding/graph_builder.py +1 -1
  86. package/src/superlocalmemory/encoding/observation_builder.py +1 -1
  87. package/src/superlocalmemory/encoding/scene_builder.py +1 -1
  88. package/src/superlocalmemory/encoding/signal_inference.py +1 -1
  89. package/src/superlocalmemory/encoding/temporal_parser.py +1 -1
  90. package/src/superlocalmemory/encoding/temporal_validator.py +1 -1
  91. package/src/superlocalmemory/encoding/type_router.py +1 -1
  92. package/src/superlocalmemory/hooks/__init__.py +1 -1
  93. package/src/superlocalmemory/hooks/auto_capture.py +1 -1
  94. package/src/superlocalmemory/hooks/auto_invoker.py +1 -1
  95. package/src/superlocalmemory/hooks/auto_parameterize.py +1 -1
  96. package/src/superlocalmemory/hooks/auto_recall.py +1 -1
  97. package/src/superlocalmemory/hooks/claude_code_hooks.py +1 -1
  98. package/src/superlocalmemory/hooks/hook_handlers.py +1 -1
  99. package/src/superlocalmemory/hooks/ide_connector.py +1 -1
  100. package/src/superlocalmemory/hooks/rules_engine.py +1 -1
  101. package/src/superlocalmemory/infra/__init__.py +1 -1
  102. package/src/superlocalmemory/infra/auth_middleware.py +1 -1
  103. package/src/superlocalmemory/infra/backup.py +1 -1
  104. package/src/superlocalmemory/infra/cache_manager.py +1 -1
  105. package/src/superlocalmemory/infra/event_bus.py +1 -1
  106. package/src/superlocalmemory/infra/heartbeat_monitor.py +1 -1
  107. package/src/superlocalmemory/infra/pid_manager.py +1 -1
  108. package/src/superlocalmemory/infra/process_reaper.py +1 -1
  109. package/src/superlocalmemory/infra/rate_limiter.py +1 -1
  110. package/src/superlocalmemory/infra/webhook_dispatcher.py +1 -1
  111. package/src/superlocalmemory/ingestion/__init__.py +1 -1
  112. package/src/superlocalmemory/ingestion/adapter_manager.py +1 -1
  113. package/src/superlocalmemory/ingestion/base_adapter.py +1 -1
  114. package/src/superlocalmemory/ingestion/calendar_adapter.py +1 -1
  115. package/src/superlocalmemory/ingestion/credentials.py +1 -1
  116. package/src/superlocalmemory/ingestion/gmail_adapter.py +1 -1
  117. package/src/superlocalmemory/ingestion/parsers.py +1 -1
  118. package/src/superlocalmemory/ingestion/transcript_adapter.py +1 -1
  119. package/src/superlocalmemory/learning/adaptive.py +1 -1
  120. package/src/superlocalmemory/learning/assertion_miner.py +403 -0
  121. package/src/superlocalmemory/learning/behavioral.py +1 -1
  122. package/src/superlocalmemory/learning/behavioral_listener.py +1 -1
  123. package/src/superlocalmemory/learning/bootstrap.py +1 -1
  124. package/src/superlocalmemory/learning/consolidation_quantization_worker.py +1 -1
  125. package/src/superlocalmemory/learning/consolidation_worker.py +25 -9
  126. package/src/superlocalmemory/learning/cross_project.py +1 -1
  127. package/src/superlocalmemory/learning/database.py +1 -1
  128. package/src/superlocalmemory/learning/engagement.py +2 -3
  129. package/src/superlocalmemory/learning/entity_compiler.py +1 -1
  130. package/src/superlocalmemory/learning/features.py +1 -1
  131. package/src/superlocalmemory/learning/forgetting_scheduler.py +1 -1
  132. package/src/superlocalmemory/learning/outcomes.py +1 -1
  133. package/src/superlocalmemory/learning/project_context.py +1 -1
  134. package/src/superlocalmemory/learning/quantization_scheduler.py +1 -1
  135. package/src/superlocalmemory/learning/ranker.py +1 -1
  136. package/src/superlocalmemory/learning/signals.py +1 -1
  137. package/src/superlocalmemory/learning/workflows.py +1 -1
  138. package/src/superlocalmemory/llm/backbone.py +1 -1
  139. package/src/superlocalmemory/math/ebbinghaus.py +1 -1
  140. package/src/superlocalmemory/math/fisher.py +1 -1
  141. package/src/superlocalmemory/math/fisher_quantized.py +1 -1
  142. package/src/superlocalmemory/math/hopfield.py +1 -1
  143. package/src/superlocalmemory/math/langevin.py +1 -1
  144. package/src/superlocalmemory/math/polar_quant.py +1 -1
  145. package/src/superlocalmemory/math/qjl.py +1 -1
  146. package/src/superlocalmemory/math/sheaf.py +1 -1
  147. package/src/superlocalmemory/math/turbo_quant.py +1 -1
  148. package/src/superlocalmemory/mcp/resources.py +1 -1
  149. package/src/superlocalmemory/mcp/server.py +17 -2
  150. package/src/superlocalmemory/mcp/shared.py +1 -1
  151. package/src/superlocalmemory/mcp/tools.py +1 -1
  152. package/src/superlocalmemory/mcp/tools_active.py +1 -1
  153. package/src/superlocalmemory/mcp/tools_code_graph.py +1 -1
  154. package/src/superlocalmemory/mcp/tools_core.py +1 -1
  155. package/src/superlocalmemory/mcp/tools_learning.py +221 -0
  156. package/src/superlocalmemory/mcp/tools_mesh.py +55 -12
  157. package/src/superlocalmemory/mcp/tools_v28.py +23 -1
  158. package/src/superlocalmemory/mcp/tools_v3.py +1 -1
  159. package/src/superlocalmemory/mcp/tools_v33.py +1 -1
  160. package/src/superlocalmemory/mesh/__init__.py +1 -1
  161. package/src/superlocalmemory/mesh/broker.py +194 -38
  162. package/src/superlocalmemory/parameterization/__init__.py +1 -1
  163. package/src/superlocalmemory/parameterization/pattern_extractor.py +35 -1
  164. package/src/superlocalmemory/parameterization/pii_filter.py +1 -1
  165. package/src/superlocalmemory/parameterization/prompt_injector.py +3 -2
  166. package/src/superlocalmemory/parameterization/prompt_lifecycle.py +1 -1
  167. package/src/superlocalmemory/parameterization/soft_prompt_generator.py +7 -1
  168. package/src/superlocalmemory/retrieval/agentic.py +1 -1
  169. package/src/superlocalmemory/retrieval/ann_index.py +1 -1
  170. package/src/superlocalmemory/retrieval/bm25_channel.py +1 -1
  171. package/src/superlocalmemory/retrieval/bridge_discovery.py +1 -1
  172. package/src/superlocalmemory/retrieval/channel_registry.py +1 -1
  173. package/src/superlocalmemory/retrieval/engine.py +1 -1
  174. package/src/superlocalmemory/retrieval/entity_channel.py +1 -1
  175. package/src/superlocalmemory/retrieval/forgetting_filter.py +1 -1
  176. package/src/superlocalmemory/retrieval/fusion.py +1 -1
  177. package/src/superlocalmemory/retrieval/hopfield_channel.py +1 -1
  178. package/src/superlocalmemory/retrieval/profile_channel.py +1 -1
  179. package/src/superlocalmemory/retrieval/quantization_aware_search.py +1 -1
  180. package/src/superlocalmemory/retrieval/reranker.py +1 -1
  181. package/src/superlocalmemory/retrieval/semantic_channel.py +1 -1
  182. package/src/superlocalmemory/retrieval/spreading_activation.py +1 -1
  183. package/src/superlocalmemory/retrieval/strategy.py +1 -1
  184. package/src/superlocalmemory/retrieval/temporal_channel.py +1 -1
  185. package/src/superlocalmemory/retrieval/vector_store.py +1 -1
  186. package/src/superlocalmemory/server/api.py +1 -1
  187. package/src/superlocalmemory/server/routes/__init__.py +1 -1
  188. package/src/superlocalmemory/server/routes/adapters.py +1 -1
  189. package/src/superlocalmemory/server/routes/agents.py +2 -2
  190. package/src/superlocalmemory/server/routes/backup.py +2 -2
  191. package/src/superlocalmemory/server/routes/behavioral.py +129 -2
  192. package/src/superlocalmemory/server/routes/compliance.py +2 -2
  193. package/src/superlocalmemory/server/routes/data_io.py +2 -2
  194. package/src/superlocalmemory/server/routes/entity.py +1 -1
  195. package/src/superlocalmemory/server/routes/events.py +2 -2
  196. package/src/superlocalmemory/server/routes/helpers.py +2 -2
  197. package/src/superlocalmemory/server/routes/ingest.py +1 -1
  198. package/src/superlocalmemory/server/routes/learning.py +22 -5
  199. package/src/superlocalmemory/server/routes/lifecycle.py +2 -2
  200. package/src/superlocalmemory/server/routes/memories.py +2 -2
  201. package/src/superlocalmemory/server/routes/mesh.py +25 -7
  202. package/src/superlocalmemory/server/routes/profiles.py +2 -2
  203. package/src/superlocalmemory/server/routes/stats.py +26 -7
  204. package/src/superlocalmemory/server/routes/v3_api.py +1 -1
  205. package/src/superlocalmemory/server/routes/ws.py +2 -2
  206. package/src/superlocalmemory/server/ui.py +1 -1
  207. package/src/superlocalmemory/server/unified_daemon.py +42 -1
  208. package/src/superlocalmemory/storage/access_control.py +1 -1
  209. package/src/superlocalmemory/storage/access_log.py +1 -1
  210. package/src/superlocalmemory/storage/database.py +1 -1
  211. package/src/superlocalmemory/storage/embedding_migrator.py +1 -1
  212. package/src/superlocalmemory/storage/migration_v33.py +1 -1
  213. package/src/superlocalmemory/storage/migrations.py +1 -1
  214. package/src/superlocalmemory/storage/models.py +1 -1
  215. package/src/superlocalmemory/storage/quantized_store.py +1 -1
  216. package/src/superlocalmemory/storage/schema.py +1 -1
  217. package/src/superlocalmemory/storage/schema_code_graph.py +1 -1
  218. package/src/superlocalmemory/storage/schema_v32.py +1 -1
  219. package/src/superlocalmemory/storage/schema_v343.py +75 -1
  220. package/src/superlocalmemory/storage/schema_v347.py +136 -0
  221. package/src/superlocalmemory/storage/v2_migrator.py +1 -1
  222. package/src/superlocalmemory/trust/gate.py +1 -1
  223. package/src/superlocalmemory/trust/provenance.py +1 -1
  224. package/src/superlocalmemory/trust/scorer.py +1 -1
  225. package/src/superlocalmemory/trust/signals.py +1 -1
  226. package/src/superlocalmemory/ui/js/behavioral.js +174 -3
  227. package/src/superlocalmemory.egg-info/PKG-INFO +0 -601
  228. package/src/superlocalmemory.egg-info/SOURCES.txt +0 -313
  229. package/src/superlocalmemory.egg-info/dependency_links.txt +0 -1
  230. package/src/superlocalmemory.egg-info/entry_points.txt +0 -2
  231. package/src/superlocalmemory.egg-info/requires.txt +0 -55
  232. package/src/superlocalmemory.egg-info/top_level.txt +0 -1
@@ -1,5 +1,5 @@
1
1
  # Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
2
- # Licensed under the Elastic License 2.0 - see LICENSE file
2
+ # Licensed under AGPL-3.0-or-later - see LICENSE file
3
3
  # Part of SuperLocalMemory V3 | https://qualixar.com | https://varunpratap.com
4
4
 
5
5
  """SLM Mesh Broker — core orchestration for P2P agent communication.
@@ -23,10 +23,16 @@ from pathlib import Path
23
23
  logger = logging.getLogger("superlocalmemory.mesh")
24
24
 
25
25
 
26
+ MAX_MESSAGE_SIZE = 4096 # 4KB cap — mesh messages are notifications, not data dumps
27
+ MESSAGE_TTL_HOURS = 48 # Offline messages expire after 48h
28
+ MAX_QUEUED_PER_TARGET = 50 # Max unread messages per broadcast/project target
29
+
30
+
26
31
  class MeshBroker:
27
32
  """Lightweight mesh broker for SLM's unified daemon.
28
33
 
29
34
  Provides peer management, messaging, state, locks, and events.
35
+ v3.4.6: broadcast, project-based routing, offline message queue.
30
36
  All methods are synchronous (called from FastAPI via run_in_executor
31
37
  or directly for quick operations).
32
38
  """
@@ -59,7 +65,8 @@ class MeshBroker:
59
65
  # -- Peers --
60
66
 
61
67
  def register_peer(self, session_id: str, summary: str = "",
62
- host: str = "127.0.0.1", port: int = 0) -> dict:
68
+ host: str = "127.0.0.1", port: int = 0,
69
+ project_path: str = "", agent_type: str = "unknown") -> dict:
63
70
  conn = self._conn()
64
71
  try:
65
72
  now = datetime.now(timezone.utc).isoformat()
@@ -71,20 +78,26 @@ class MeshBroker:
71
78
  if existing:
72
79
  peer_id = existing["peer_id"]
73
80
  conn.execute(
74
- "UPDATE mesh_peers SET summary=?, host=?, port=?, last_heartbeat=?, status='active' "
75
- "WHERE peer_id=?",
76
- (summary, host, port, now, peer_id),
81
+ "UPDATE mesh_peers SET summary=?, host=?, port=?, last_heartbeat=?, "
82
+ "status='active', project_path=?, agent_type=? WHERE peer_id=?",
83
+ (summary, host, port, now, project_path, agent_type, peer_id),
77
84
  )
78
85
  else:
79
86
  peer_id = str(uuid.uuid4())[:12]
80
87
  conn.execute(
81
- "INSERT INTO mesh_peers (peer_id, session_id, summary, status, host, port, registered_at, last_heartbeat) "
82
- "VALUES (?, ?, ?, 'active', ?, ?, ?, ?)",
83
- (peer_id, session_id, summary, host, port, now, now),
88
+ "INSERT INTO mesh_peers (peer_id, session_id, summary, status, host, port, "
89
+ "registered_at, last_heartbeat, project_path, agent_type) "
90
+ "VALUES (?, ?, ?, 'active', ?, ?, ?, ?, ?, ?)",
91
+ (peer_id, session_id, summary, host, port, now, now, project_path, agent_type),
84
92
  )
85
- self._log_event(conn, "peer_registered", peer_id, {"session_id": session_id})
93
+ self._log_event(conn, "peer_registered", peer_id, {
94
+ "session_id": session_id, "project_path": project_path,
95
+ })
86
96
  conn.commit()
87
- return {"peer_id": peer_id, "ok": True}
97
+
98
+ # v3.4.6: Deliver pending broadcast/project messages on registration
99
+ pending = self._get_pending_for_peer(conn, peer_id, project_path)
100
+ return {"peer_id": peer_id, "ok": True, "pending_messages": len(pending)}
88
101
  finally:
89
102
  conn.close()
90
103
 
@@ -134,7 +147,8 @@ class MeshBroker:
134
147
  conn = self._conn()
135
148
  try:
136
149
  rows = conn.execute(
137
- "SELECT peer_id, session_id, summary, status, host, port, registered_at, last_heartbeat "
150
+ "SELECT peer_id, session_id, summary, status, host, port, "
151
+ "registered_at, last_heartbeat, project_path, agent_type "
138
152
  "FROM mesh_peers ORDER BY last_heartbeat DESC",
139
153
  ).fetchall()
140
154
  return [dict(r) for r in rows]
@@ -144,46 +158,136 @@ class MeshBroker:
144
158
  # -- Messages --
145
159
 
146
160
  def send_message(self, from_peer: str, to_peer: str, content: str,
147
- msg_type: str = "text") -> dict:
161
+ msg_type: str = "text", project_path: str = "") -> dict:
162
+ # Guard: 4KB message size cap
163
+ if len(content) > MAX_MESSAGE_SIZE:
164
+ return {"ok": False, "error": f"message too large ({len(content)} bytes, max {MAX_MESSAGE_SIZE}). "
165
+ "Mesh messages are notifications — reference a file path instead."}
166
+
148
167
  conn = self._conn()
149
168
  try:
150
- # Verify recipient exists
151
- if not conn.execute("SELECT 1 FROM mesh_peers WHERE peer_id=?", (to_peer,)).fetchone():
152
- return {"ok": False, "error": "recipient peer not found"}
153
169
  now = datetime.now(timezone.utc).isoformat()
170
+ expires_at = self._compute_expires(now)
171
+
172
+ # Determine target type
173
+ if to_peer == "broadcast":
174
+ target_type = "broadcast"
175
+ elif to_peer.startswith("project:"):
176
+ target_type = "project"
177
+ project_path = to_peer[len("project:"):]
178
+ to_peer = "project"
179
+ else:
180
+ target_type = "peer"
181
+ # Verify recipient exists for direct messages
182
+ if not conn.execute("SELECT 1 FROM mesh_peers WHERE peer_id=?", (to_peer,)).fetchone():
183
+ return {"ok": False, "error": "recipient peer not found"}
184
+
185
+ # Enforce per-target queue cap
186
+ if target_type in ("broadcast", "project"):
187
+ count = conn.execute(
188
+ "SELECT COUNT(*) FROM mesh_messages WHERE target_type=? AND project_path=? AND read=0",
189
+ (target_type, project_path),
190
+ ).fetchone()[0]
191
+ if count >= MAX_QUEUED_PER_TARGET:
192
+ # Delete oldest to make room
193
+ conn.execute(
194
+ "DELETE FROM mesh_messages WHERE id IN ("
195
+ " SELECT id FROM mesh_messages WHERE target_type=? AND project_path=? AND read=0 "
196
+ " ORDER BY created_at ASC LIMIT ?)",
197
+ (target_type, project_path, count - MAX_QUEUED_PER_TARGET + 1),
198
+ )
199
+
154
200
  cursor = conn.execute(
155
- "INSERT INTO mesh_messages (from_peer, to_peer, msg_type, content, read, created_at) "
156
- "VALUES (?, ?, ?, ?, 0, ?)",
157
- (from_peer, to_peer, msg_type, content, now),
201
+ "INSERT INTO mesh_messages (from_peer, to_peer, msg_type, content, read, "
202
+ "created_at, expires_at, target_type, project_path) "
203
+ "VALUES (?, ?, ?, ?, 0, ?, ?, ?, ?)",
204
+ (from_peer, to_peer, msg_type, content, now, expires_at, target_type, project_path),
158
205
  )
159
- self._log_event(conn, "message_sent", from_peer, {"to": to_peer})
206
+ self._log_event(conn, "message_sent", from_peer, {
207
+ "to": to_peer, "target_type": target_type, "project": project_path,
208
+ })
160
209
  conn.commit()
161
- return {"ok": True, "id": cursor.lastrowid}
210
+ return {"ok": True, "id": cursor.lastrowid, "target_type": target_type,
211
+ "expires_at": expires_at}
162
212
  finally:
163
213
  conn.close()
164
214
 
165
- def get_inbox(self, peer_id: str) -> list[dict]:
215
+ def get_inbox(self, peer_id: str, project_path: str = "") -> list[dict]:
216
+ """Get all messages for this peer: direct + broadcast + project."""
166
217
  conn = self._conn()
167
218
  try:
168
- rows = conn.execute(
169
- "SELECT id, from_peer, to_peer, msg_type, content, read, created_at "
170
- "FROM mesh_messages WHERE to_peer=? ORDER BY created_at DESC LIMIT 100",
171
- (peer_id,),
219
+ now = datetime.now(timezone.utc).isoformat()
220
+ # Direct messages to this peer
221
+ direct = conn.execute(
222
+ "SELECT id, from_peer, to_peer, msg_type, content, read, created_at, "
223
+ "target_type, project_path FROM mesh_messages "
224
+ "WHERE to_peer=? AND target_type='peer' "
225
+ "AND (expires_at IS NULL OR expires_at > ?) "
226
+ "ORDER BY created_at DESC LIMIT 100",
227
+ (peer_id, now),
172
228
  ).fetchall()
173
- return [dict(r) for r in rows]
229
+
230
+ # Broadcast messages not from this peer and not yet read by this peer
231
+ broadcast = conn.execute(
232
+ "SELECT m.id, m.from_peer, m.to_peer, m.msg_type, m.content, "
233
+ "CASE WHEN r.peer_id IS NOT NULL THEN 1 ELSE 0 END AS read, "
234
+ "m.created_at, m.target_type, m.project_path "
235
+ "FROM mesh_messages m "
236
+ "LEFT JOIN mesh_reads r ON m.id = r.message_id AND r.peer_id = ? "
237
+ "WHERE m.target_type='broadcast' AND m.from_peer != ? "
238
+ "AND (m.expires_at IS NULL OR m.expires_at > ?) "
239
+ "ORDER BY m.created_at DESC LIMIT 50",
240
+ (peer_id, peer_id, now),
241
+ ).fetchall()
242
+
243
+ # Project messages for my project, not from me, not yet read
244
+ project_msgs = []
245
+ if project_path:
246
+ project_msgs = conn.execute(
247
+ "SELECT m.id, m.from_peer, m.to_peer, m.msg_type, m.content, "
248
+ "CASE WHEN r.peer_id IS NOT NULL THEN 1 ELSE 0 END AS read, "
249
+ "m.created_at, m.target_type, m.project_path "
250
+ "FROM mesh_messages m "
251
+ "LEFT JOIN mesh_reads r ON m.id = r.message_id AND r.peer_id = ? "
252
+ "WHERE m.target_type='project' AND m.project_path=? AND m.from_peer != ? "
253
+ "AND (m.expires_at IS NULL OR m.expires_at > ?) "
254
+ "ORDER BY m.created_at DESC LIMIT 50",
255
+ (peer_id, project_path, peer_id, now),
256
+ ).fetchall()
257
+
258
+ all_msgs = [dict(r) for r in direct] + [dict(r) for r in broadcast] + [dict(r) for r in project_msgs]
259
+ # Sort by created_at descending
260
+ all_msgs.sort(key=lambda m: m.get("created_at", ""), reverse=True)
261
+ return all_msgs[:100]
174
262
  finally:
175
263
  conn.close()
176
264
 
177
265
  def mark_read(self, peer_id: str, message_ids: list[int]) -> dict:
178
266
  conn = self._conn()
179
267
  try:
180
- placeholders = ",".join("?" * len(message_ids))
181
- conn.execute(
182
- f"UPDATE mesh_messages SET read=1 WHERE to_peer=? AND id IN ({placeholders})",
183
- [peer_id, *message_ids],
184
- )
268
+ now = datetime.now(timezone.utc).isoformat()
269
+ for msg_id in message_ids:
270
+ # Check if this is a direct message or broadcast/project
271
+ row = conn.execute(
272
+ "SELECT target_type FROM mesh_messages WHERE id=?", (msg_id,),
273
+ ).fetchone()
274
+ if not row:
275
+ continue
276
+ if row["target_type"] == "peer":
277
+ # Direct: update read flag on the message itself
278
+ conn.execute(
279
+ "UPDATE mesh_messages SET read=1 WHERE id=? AND to_peer=?",
280
+ (msg_id, peer_id),
281
+ )
282
+ else:
283
+ # Broadcast/project: insert into mesh_reads
284
+ conn.execute(
285
+ "INSERT OR IGNORE INTO mesh_reads (message_id, peer_id, read_at) "
286
+ "VALUES (?, ?, ?)",
287
+ (msg_id, peer_id, now),
288
+ )
185
289
  conn.commit()
186
- return {"ok": True}
290
+ return {"ok": True, "marked": len(message_ids)}
187
291
  finally:
188
292
  conn.close()
189
293
 
@@ -262,6 +366,40 @@ class MeshBroker:
262
366
  finally:
263
367
  conn.close()
264
368
 
369
+ # -- Helpers (v3.4.6) --
370
+
371
+ @staticmethod
372
+ def _compute_expires(now_iso: str) -> str:
373
+ """Compute expiry timestamp MESSAGE_TTL_HOURS from now."""
374
+ from datetime import timedelta
375
+ now = datetime.fromisoformat(now_iso)
376
+ return (now + timedelta(hours=MESSAGE_TTL_HOURS)).isoformat()
377
+
378
+ def _get_pending_for_peer(self, conn: sqlite3.Connection,
379
+ peer_id: str, project_path: str) -> list[dict]:
380
+ """Get unread broadcast/project messages for a newly registered peer."""
381
+ now = datetime.now(timezone.utc).isoformat()
382
+ rows = conn.execute(
383
+ "SELECT m.id, m.from_peer, m.content, m.target_type, m.project_path, m.created_at "
384
+ "FROM mesh_messages m "
385
+ "LEFT JOIN mesh_reads r ON m.id = r.message_id AND r.peer_id = ? "
386
+ "WHERE r.peer_id IS NULL AND m.from_peer != ? "
387
+ "AND (m.expires_at IS NULL OR m.expires_at > ?) "
388
+ "AND (m.target_type = 'broadcast' "
389
+ " OR (m.target_type = 'project' AND m.project_path = ?)) "
390
+ "ORDER BY m.created_at DESC LIMIT 50",
391
+ (peer_id, peer_id, now, project_path),
392
+ ).fetchall()
393
+ return [dict(r) for r in rows]
394
+
395
+ def get_pending(self, peer_id: str, project_path: str = "") -> list[dict]:
396
+ """Public API to get pending broadcast/project messages."""
397
+ conn = self._conn()
398
+ try:
399
+ return self._get_pending_for_peer(conn, peer_id, project_path)
400
+ finally:
401
+ conn.close()
402
+
265
403
  # -- Events --
266
404
 
267
405
  def get_events(self, limit: int = 100) -> list[dict]:
@@ -316,28 +454,46 @@ class MeshBroker:
316
454
  conn = self._conn()
317
455
  try:
318
456
  now = datetime.now(timezone.utc)
457
+ now_iso = now.isoformat()
319
458
  # Mark stale peers (no heartbeat for 5 min)
320
459
  conn.execute(
321
460
  "UPDATE mesh_peers SET status='stale' "
322
461
  "WHERE status='active' AND datetime(last_heartbeat) < datetime(?, '-5 minutes')",
323
- (now.isoformat(),),
462
+ (now_iso,),
324
463
  )
325
464
  # Delete dead peers (stale > 30 min)
326
465
  conn.execute(
327
466
  "UPDATE mesh_peers SET status='dead' "
328
467
  "WHERE status='stale' AND datetime(last_heartbeat) < datetime(?, '-30 minutes')",
329
- (now.isoformat(),),
468
+ (now_iso,),
330
469
  )
331
470
  conn.execute("DELETE FROM mesh_peers WHERE status='dead'")
332
- # Delete read messages > 24hr old
471
+ # Delete read direct messages > 24hr old
472
+ conn.execute(
473
+ "DELETE FROM mesh_messages WHERE target_type='peer' AND read=1 "
474
+ "AND datetime(created_at) < datetime(?, '-24 hours')",
475
+ (now_iso,),
476
+ )
477
+ # v3.4.6: Delete EXPIRED messages (48h TTL for broadcast/project)
333
478
  conn.execute(
334
- "DELETE FROM mesh_messages WHERE read=1 AND datetime(created_at) < datetime(?, '-24 hours')",
335
- (now.isoformat(),),
479
+ "DELETE FROM mesh_messages WHERE expires_at IS NOT NULL "
480
+ "AND datetime(expires_at) < datetime(?)",
481
+ (now_iso,),
482
+ )
483
+ # v3.4.6: Clean up orphaned mesh_reads entries
484
+ conn.execute(
485
+ "DELETE FROM mesh_reads WHERE message_id NOT IN "
486
+ "(SELECT id FROM mesh_messages)",
336
487
  )
337
488
  # Delete expired locks
338
489
  conn.execute(
339
490
  "DELETE FROM mesh_locks WHERE datetime(expires_at) < datetime(?)",
340
- (now.isoformat(),),
491
+ (now_iso,),
492
+ )
493
+ # v3.4.6: Delete old events (keep last 7 days)
494
+ conn.execute(
495
+ "DELETE FROM mesh_events WHERE datetime(created_at) < datetime(?, '-7 days')",
496
+ (now_iso,),
341
497
  )
342
498
  conn.commit()
343
499
  finally:
@@ -1,5 +1,5 @@
1
1
  # Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
2
- # Licensed under the Elastic License 2.0 - see LICENSE file
2
+ # Licensed under AGPL-3.0-or-later - see LICENSE file
3
3
  # Part of SuperLocalMemory V3.3
4
4
 
5
5
  """Phase F: The Learning Brain — Memory Parameterization.
@@ -1,5 +1,5 @@
1
1
  # Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
2
- # Licensed under the Elastic License 2.0 - see LICENSE file
2
+ # Licensed under AGPL-3.0-or-later - see LICENSE file
3
3
  # Part of SuperLocalMemory V3.3
4
4
 
5
5
  """PatternExtractor — Mine patterns from 4 sources for soft prompt generation.
@@ -159,6 +159,8 @@ class PatternExtractor:
159
159
  all_patterns.extend(self._extract_from_behavioral(profile_id))
160
160
  all_patterns.extend(self._extract_from_cross_project())
161
161
  all_patterns.extend(self._extract_from_workflows(profile_id))
162
+ # v3.4.7: Extract from behavioral assertions (learned patterns)
163
+ all_patterns.extend(self._extract_from_assertions(profile_id))
162
164
 
163
165
  if not all_patterns:
164
166
  return []
@@ -320,6 +322,38 @@ class PatternExtractor:
320
322
  ))
321
323
  return patterns
322
324
 
325
+ # ------------------------------------------------------------------
326
+ # v3.4.7: Behavioral assertions → soft prompts
327
+ # ------------------------------------------------------------------
328
+
329
+ def _extract_from_assertions(
330
+ self, profile_id: str,
331
+ ) -> list[PatternAssertion]:
332
+ """Extract high-confidence behavioral assertions for soft prompt injection."""
333
+ patterns: list[PatternAssertion] = []
334
+ try:
335
+ rows = self._db.execute(
336
+ "SELECT trigger_condition, action, confidence, evidence_count, "
337
+ "created_at FROM behavioral_assertions "
338
+ "WHERE profile_id = ? AND confidence >= 0.5 "
339
+ "ORDER BY confidence DESC LIMIT 10",
340
+ (profile_id,),
341
+ )
342
+ for row in rows:
343
+ r = dict(row)
344
+ patterns.append(PatternAssertion(
345
+ category=PatternCategory.WORKFLOW_PATTERN,
346
+ key=f"behavioral:{r['trigger_condition'][:30]}",
347
+ value=f"When {r['trigger_condition']}, {r['action']}",
348
+ confidence=r["confidence"],
349
+ evidence_count=r["evidence_count"],
350
+ source="behavioral_assertion",
351
+ created_at=r.get("created_at", ""),
352
+ ))
353
+ except Exception as exc:
354
+ logger.debug("Behavioral assertion extraction: %s", exc)
355
+ return patterns
356
+
323
357
  # ------------------------------------------------------------------
324
358
  # Deduplication & contradiction resolution
325
359
  # ------------------------------------------------------------------
@@ -1,5 +1,5 @@
1
1
  # Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
2
- # Licensed under the Elastic License 2.0 - see LICENSE file
2
+ # Licensed under AGPL-3.0-or-later - see LICENSE file
3
3
  # Part of SuperLocalMemory V3.3
4
4
 
5
5
  """PII Filter — Stateless PII detection and redaction for soft prompts.
@@ -1,5 +1,5 @@
1
1
  # Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
2
- # Licensed under the Elastic License 2.0 - see LICENSE file
2
+ # Licensed under AGPL-3.0-or-later - see LICENSE file
3
3
  # Part of SuperLocalMemory V3.3
4
4
 
5
5
  """PromptInjector — Inject soft prompts into context with token budget.
@@ -186,7 +186,8 @@ class PromptInjector:
186
186
  )
187
187
  max_version = 0
188
188
  if version_rows:
189
- max_version = version_rows[0].get("max_version", 0) or 0
189
+ row = version_rows[0]
190
+ max_version = (dict(row) if hasattr(row, "keys") else {"max_version": row[0]}).get("max_version", 0) or 0
190
191
  new_version = max_version + 1
191
192
 
192
193
  # Insert new prompt
@@ -1,5 +1,5 @@
1
1
  # Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
2
- # Licensed under the Elastic License 2.0 - see LICENSE file
2
+ # Licensed under AGPL-3.0-or-later - see LICENSE file
3
3
  # Part of SuperLocalMemory V3.3
4
4
 
5
5
  """PromptLifecycleManager — Ebbinghaus decay and effectiveness for soft prompts.
@@ -1,5 +1,5 @@
1
1
  # Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
2
- # Licensed under the Elastic License 2.0 - see LICENSE file
2
+ # Licensed under AGPL-3.0-or-later - see LICENSE file
3
3
  # Part of SuperLocalMemory V3.3
4
4
 
5
5
  """SoftPromptGenerator — Convert extracted patterns to text soft prompts.
@@ -61,12 +61,18 @@ CATEGORY_TEMPLATES: dict[str, str] = {
61
61
  "The user has explicitly asked to avoid: {avoid_list}. "
62
62
  "Do not suggest or use these."
63
63
  ),
64
+ # v3.4.7: Behavioral assertions — learned patterns from tool usage
65
+ "behavioral": (
66
+ "Learned behavior: When {trigger}, {action}. "
67
+ "(Confidence: {confidence}%, based on {evidence} observations)"
68
+ ),
64
69
  }
65
70
 
66
71
  CATEGORY_PRIORITY_ORDER: list[str] = [
67
72
  "identity",
68
73
  "tech_preference",
69
74
  "communication_style",
75
+ "behavioral", # v3.4.7: behavioral assertions after communication style
70
76
  "workflow_pattern",
71
77
  "project_context",
72
78
  "decision_history",
@@ -1,5 +1,5 @@
1
1
  # Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
2
- # Licensed under the Elastic License 2.0 - see LICENSE file
2
+ # Licensed under AGPL-3.0-or-later - see LICENSE file
3
3
  # Part of SuperLocalMemory V3 | https://qualixar.com | https://varunpratap.com
4
4
 
5
5
  """SuperLocalMemory V3 — 2-Round Sufficiency Verification (EverMemOS Pattern).
@@ -1,5 +1,5 @@
1
1
  # Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
2
- # Licensed under the Elastic License 2.0 - see LICENSE file
2
+ # Licensed under AGPL-3.0-or-later - see LICENSE file
3
3
  # Part of SuperLocalMemory V3 | https://qualixar.com | https://varunpratap.com
4
4
 
5
5
  """SuperLocalMemory V3 — Approximate Nearest Neighbor Index.
@@ -1,5 +1,5 @@
1
1
  # Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
2
- # Licensed under the Elastic License 2.0 - see LICENSE file
2
+ # Licensed under AGPL-3.0-or-later - see LICENSE file
3
3
  # Part of SuperLocalMemory V3 | https://qualixar.com | https://varunpratap.com
4
4
 
5
5
  """SuperLocalMemory V3 — BM25 Keyword Search Channel.
@@ -1,5 +1,5 @@
1
1
  # Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
2
- # Licensed under the Elastic License 2.0 - see LICENSE file
2
+ # Licensed under AGPL-3.0-or-later - see LICENSE file
3
3
  # Part of SuperLocalMemory V3 | https://qualixar.com | https://varunpratap.com
4
4
 
5
5
  """SuperLocalMemory V3 — Bridge Discovery + Spreading Activation.
@@ -1,5 +1,5 @@
1
1
  # Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
2
- # Licensed under the Elastic License 2.0 - see LICENSE file
2
+ # Licensed under AGPL-3.0-or-later - see LICENSE file
3
3
  # Part of SuperLocalMemory V3
4
4
 
5
5
  """SuperLocalMemory V3.2 -- Channel Registry.
@@ -1,5 +1,5 @@
1
1
  # Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
2
- # Licensed under the Elastic License 2.0 - see LICENSE file
2
+ # Licensed under AGPL-3.0-or-later - see LICENSE file
3
3
  # Part of SuperLocalMemory V3 | https://qualixar.com | https://varunpratap.com
4
4
 
5
5
  """SuperLocalMemory V3 — Retrieval Engine (6-Channel Orchestrator).
@@ -1,5 +1,5 @@
1
1
  # Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
2
- # Licensed under the Elastic License 2.0 - see LICENSE file
2
+ # Licensed under AGPL-3.0-or-later - see LICENSE file
3
3
  # Part of SuperLocalMemory V3 | https://qualixar.com | https://varunpratap.com
4
4
 
5
5
  """SuperLocalMemory V3 — Entity Graph Channel with Spreading Activation.
@@ -1,5 +1,5 @@
1
1
  # Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
2
- # Licensed under the Elastic License 2.0 - see LICENSE file
2
+ # Licensed under AGPL-3.0-or-later - see LICENSE file
3
3
  # Part of SuperLocalMemory V3 | https://qualixar.com | https://varunpratap.com
4
4
 
5
5
  """Forgetting filter for retrieval pipeline.
@@ -1,5 +1,5 @@
1
1
  # Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
2
- # Licensed under the Elastic License 2.0 - see LICENSE file
2
+ # Licensed under AGPL-3.0-or-later - see LICENSE file
3
3
  # Part of SuperLocalMemory V3 | https://qualixar.com | https://varunpratap.com
4
4
 
5
5
  """SuperLocalMemory V3 — Weighted Reciprocal Rank Fusion.
@@ -1,5 +1,5 @@
1
1
  # Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
2
- # Licensed under the Elastic License 2.0 - see LICENSE file
2
+ # Licensed under AGPL-3.0-or-later - see LICENSE file
3
3
  # Part of SuperLocalMemory V3
4
4
 
5
5
  """SuperLocalMemory V3.3 -- Hopfield Associative Memory (6th Retrieval Channel).
@@ -1,5 +1,5 @@
1
1
  # Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
2
- # Licensed under the Elastic License 2.0 - see LICENSE file
2
+ # Licensed under AGPL-3.0-or-later - see LICENSE file
3
3
  # Part of SuperLocalMemory V3 | https://qualixar.com | https://varunpratap.com
4
4
 
5
5
  """SuperLocalMemory V3 — Profile Channel (Entity-Profile Retrieval).
@@ -1,5 +1,5 @@
1
1
  # Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
2
- # Licensed under the Elastic License 2.0 - see LICENSE file
2
+ # Licensed under AGPL-3.0-or-later - see LICENSE file
3
3
  # Part of SuperLocalMemory V3
4
4
 
5
5
  """Three-tier mixed-precision search.
@@ -1,5 +1,5 @@
1
1
  # Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
2
- # Licensed under the Elastic License 2.0 - see LICENSE file
2
+ # Licensed under AGPL-3.0-or-later - see LICENSE file
3
3
  # Part of SuperLocalMemory V3 | https://qualixar.com | https://varunpratap.com
4
4
 
5
5
  """SuperLocalMemory V3 — Cross-Encoder Reranker (Subprocess-Isolated).
@@ -1,5 +1,5 @@
1
1
  # Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
2
- # Licensed under the Elastic License 2.0 - see LICENSE file
2
+ # Licensed under AGPL-3.0-or-later - see LICENSE file
3
3
  # Part of SuperLocalMemory V3 | https://qualixar.com | https://varunpratap.com
4
4
 
5
5
  """SuperLocalMemory V3 — Semantic Retrieval Channel.
@@ -1,5 +1,5 @@
1
1
  # Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
2
- # Licensed under the Elastic License 2.0 - see LICENSE file
2
+ # Licensed under AGPL-3.0-or-later - see LICENSE file
3
3
  # Part of SuperLocalMemory V3
4
4
 
5
5
  """SYNAPSE spreading activation -- 5th retrieval channel.
@@ -1,5 +1,5 @@
1
1
  # Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
2
- # Licensed under the Elastic License 2.0 - see LICENSE file
2
+ # Licensed under AGPL-3.0-or-later - see LICENSE file
3
3
  # Part of SuperLocalMemory V3 | https://qualixar.com | https://varunpratap.com
4
4
 
5
5
  """SuperLocalMemory V3 — Query-Adaptive Strategy.
@@ -1,5 +1,5 @@
1
1
  # Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
2
- # Licensed under the Elastic License 2.0 - see LICENSE file
2
+ # Licensed under AGPL-3.0-or-later - see LICENSE file
3
3
  # Part of SuperLocalMemory V3 | https://qualixar.com | https://varunpratap.com
4
4
 
5
5
  """SuperLocalMemory V3 — Temporal Retrieval Channel (3-Date Model).
@@ -1,5 +1,5 @@
1
1
  # Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
2
- # Licensed under the Elastic License 2.0 - see LICENSE file
2
+ # Licensed under AGPL-3.0-or-later - see LICENSE file
3
3
  # Part of SuperLocalMemory V3
4
4
 
5
5
  """VectorStore -- sqlite-vec backed KNN search with profile isolation.
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env python3
2
2
  # Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
3
- # Licensed under the Elastic License 2.0 - see LICENSE file
3
+ # Licensed under AGPL-3.0-or-later - see LICENSE file
4
4
  # Part of SuperLocalMemory V3 | https://qualixar.com | https://varunpratap.com
5
5
  """
6
6
  SuperLocalMemory V3 - FastAPI API Server
@@ -1,4 +1,4 @@
1
1
  # Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
2
- # Licensed under the Elastic License 2.0 - see LICENSE file
2
+ # Licensed under AGPL-3.0-or-later - see LICENSE file
3
3
  # Part of SuperLocalMemory V3 | https://qualixar.com | https://varunpratap.com
4
4
  # SuperLocalMemory V3 - API Routes Package
@@ -1,5 +1,5 @@
1
1
  # Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
2
- # Licensed under the Elastic License 2.0 - see LICENSE file
2
+ # Licensed under AGPL-3.0-or-later - see LICENSE file
3
3
  # Part of SuperLocalMemory V3 | https://qualixar.com | https://varunpratap.com
4
4
 
5
5
  """Ingestion adapter management API — enable/disable/start/stop from dashboard.
@@ -1,8 +1,8 @@
1
1
  # Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
2
- # Licensed under the Elastic License 2.0 - see LICENSE file
2
+ # Licensed under AGPL-3.0-or-later - see LICENSE file
3
3
  # Part of SuperLocalMemory V3 | https://qualixar.com | https://varunpratap.com
4
4
  """SuperLocalMemory V3 - Agent Registry + Trust Routes
5
- - Elastic License 2.0
5
+ - AGPL-3.0-or-later
6
6
 
7
7
  Routes: /api/agents, /api/agents/stats, /api/trust/stats, /api/trust/signals/{agent_id}
8
8
  Uses V3 TrustScorer and core.registry.