superlocalmemory 3.6.13 → 3.6.15

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 (147) hide show
  1. package/.claude-plugin/marketplace.json +17 -0
  2. package/CHANGELOG.md +28 -0
  3. package/README.md +189 -740
  4. package/package.json +12 -5
  5. package/plugin/.claude-plugin/plugin.json +20 -0
  6. package/plugin/.mcp.json +12 -0
  7. package/plugin/CLAUDE.md +44 -0
  8. package/plugin/_GENERATED.md +6 -0
  9. package/plugin/agents/slm-memory-advisor.md +44 -0
  10. package/plugin/agents/slm-optimize-advisor.md +38 -0
  11. package/plugin/hooks/hooks.json +14 -0
  12. package/plugin/requirements.txt +1 -0
  13. package/plugin/scripts/ensure-venv.bat +122 -0
  14. package/plugin/scripts/ensure-venv.sh +105 -0
  15. package/plugin/scripts/slm-launch +15 -0
  16. package/plugin/scripts/slm-launch.bat +17 -0
  17. package/plugin/settings.json +16 -0
  18. package/plugin/skills/slm-cache/SKILL.md +140 -0
  19. package/plugin/skills/slm-compress/SKILL.md +143 -0
  20. package/plugin/skills/slm-graph/SKILL.md +300 -0
  21. package/plugin/skills/slm-recall/SKILL.md +204 -0
  22. package/plugin/skills/slm-remember/SKILL.md +194 -0
  23. package/plugin/skills/slm-session/SKILL.md +207 -0
  24. package/plugin/skills/slm-status/SKILL.md +149 -0
  25. package/plugin-src/.mcp.json +12 -0
  26. package/plugin-src/agents/slm-memory-advisor.md +44 -0
  27. package/plugin-src/agents/slm-optimize-advisor.md +38 -0
  28. package/plugin-src/commands/slm-optimize.md +22 -0
  29. package/plugin-src/commands/slm-recall.md +16 -0
  30. package/plugin-src/commands/slm-remember.md +16 -0
  31. package/plugin-src/commands/slm-status.md +15 -0
  32. package/plugin-src/hooks/.gitkeep +0 -0
  33. package/plugin-src/hooks/hooks.json +14 -0
  34. package/plugin-src/manifest.json +25 -0
  35. package/plugin-src/requirements.txt +1 -0
  36. package/plugin-src/rules/AGENTS.md +91 -0
  37. package/plugin-src/rules/CLAUDE.md.fragment +44 -0
  38. package/plugin-src/scripts/ensure-venv.bat +122 -0
  39. package/plugin-src/scripts/ensure-venv.sh +105 -0
  40. package/plugin-src/scripts/slm-launch +15 -0
  41. package/plugin-src/scripts/slm-launch.bat +17 -0
  42. package/plugin-src/settings.json +16 -0
  43. package/plugin-src/skills/slm-cache/SKILL.md +140 -0
  44. package/plugin-src/skills/slm-compress/SKILL.md +143 -0
  45. package/plugin-src/skills/slm-graph/SKILL.md +300 -0
  46. package/plugin-src/skills/slm-recall/SKILL.md +204 -0
  47. package/plugin-src/skills/slm-remember/SKILL.md +194 -0
  48. package/plugin-src/skills/slm-session/SKILL.md +207 -0
  49. package/plugin-src/skills/slm-status/SKILL.md +149 -0
  50. package/pyproject.toml +6 -2
  51. package/scripts/__tests__/build-plugin.test.mjs +613 -0
  52. package/scripts/_savings_math.py +270 -0
  53. package/scripts/build-plugin.js +742 -0
  54. package/scripts/dogfood_savings.py +490 -0
  55. package/scripts/install-skills.ps1 +4 -334
  56. package/scripts/install-skills.sh +4 -435
  57. package/scripts/postinstall-interactive.js +0 -27
  58. package/scripts/postinstall.js +21 -2
  59. package/src/superlocalmemory/__init__.py +1 -1
  60. package/src/superlocalmemory/cli/_lazy_init.py +115 -0
  61. package/src/superlocalmemory/cli/commands.py +439 -41
  62. package/src/superlocalmemory/cli/main.py +92 -4
  63. package/src/superlocalmemory/cli/setup_wizard.py +47 -6
  64. package/src/superlocalmemory/core/backend_orchestrator.py +12 -8
  65. package/src/superlocalmemory/core/config.py +194 -9
  66. package/src/superlocalmemory/core/embeddings.py +10 -5
  67. package/src/superlocalmemory/core/engine.py +76 -5
  68. package/src/superlocalmemory/core/fact_consolidator.py +20 -3
  69. package/src/superlocalmemory/core/platform_utils.py +8 -0
  70. package/src/superlocalmemory/core/recall_pipeline.py +7 -0
  71. package/src/superlocalmemory/core/recall_worker.py +7 -0
  72. package/src/superlocalmemory/core/store_pipeline.py +23 -1
  73. package/src/superlocalmemory/core/worker_pool.py +14 -2
  74. package/src/superlocalmemory/hooks/claude_code_hooks.py +27 -3
  75. package/src/superlocalmemory/hooks/portable_kit.py +506 -0
  76. package/src/superlocalmemory/hooks/session_registry.py +8 -4
  77. package/src/superlocalmemory/infra/cloud_backup.py +99 -23
  78. package/src/superlocalmemory/mcp/_daemon_proxy.py +12 -2
  79. package/src/superlocalmemory/mcp/_pool_adapter.py +15 -6
  80. package/src/superlocalmemory/mcp/cli_fallback.py +602 -0
  81. package/src/superlocalmemory/mcp/server.py +75 -4
  82. package/src/superlocalmemory/mcp/tools_code_graph.py +3 -3
  83. package/src/superlocalmemory/mcp/tools_core.py +37 -4
  84. package/src/superlocalmemory/mcp/tools_v3.py +6 -1
  85. package/src/superlocalmemory/mcp/tools_v33.py +8 -4
  86. package/src/superlocalmemory/optimize/cache/boundary_store.py +25 -6
  87. package/src/superlocalmemory/optimize/cache/centroid_store.py +27 -4
  88. package/src/superlocalmemory/optimize/cache/manager.py +92 -6
  89. package/src/superlocalmemory/optimize/cache/semantic.py +20 -1
  90. package/src/superlocalmemory/optimize/compress/ccr.py +12 -0
  91. package/src/superlocalmemory/optimize/compress/router.py +46 -13
  92. package/src/superlocalmemory/optimize/config/schema.py +6 -0
  93. package/src/superlocalmemory/optimize/proxy/_helpers.py +111 -8
  94. package/src/superlocalmemory/optimize/proxy/anthropic_surface.py +14 -4
  95. package/src/superlocalmemory/optimize/proxy/gemini_surface.py +23 -6
  96. package/src/superlocalmemory/optimize/proxy/openai_surface.py +10 -4
  97. package/src/superlocalmemory/optimize/proxy/server.py +11 -0
  98. package/src/superlocalmemory/optimize/proxy/vertex_surface.py +246 -0
  99. package/src/superlocalmemory/optimize/storage/db.py +30 -0
  100. package/src/superlocalmemory/retrieval/bm25_channel.py +12 -2
  101. package/src/superlocalmemory/retrieval/engine.py +36 -3
  102. package/src/superlocalmemory/retrieval/entity_channel.py +5 -5
  103. package/src/superlocalmemory/retrieval/hopfield_channel.py +10 -2
  104. package/src/superlocalmemory/retrieval/semantic_channel.py +10 -2
  105. package/src/superlocalmemory/server/recall_serializer.py +3 -1
  106. package/src/superlocalmemory/server/unified_daemon.py +156 -16
  107. package/src/superlocalmemory/storage/database.py +215 -43
  108. package/src/superlocalmemory/storage/migration_runner.py +17 -1
  109. package/src/superlocalmemory/storage/migrations/M016_add_scope_support.py +120 -0
  110. package/src/superlocalmemory/storage/models.py +10 -0
  111. package/src/superlocalmemory/storage/schema.py +15 -10
  112. package/src/superlocalmemory/ui/css/legacy-dashboard.css +18 -0
  113. package/src/superlocalmemory/ui/css/neural-glass.css +5 -0
  114. package/src/superlocalmemory/ui/index.html +2 -2
  115. package/src/superlocalmemory/ui/js/core.js +98 -0
  116. package/src/superlocalmemory/ui/js/dashboard.js +8 -1
  117. package/src/superlocalmemory/ui/js/ide-status.js +16 -3
  118. package/src/superlocalmemory/ui/js/math-health.js +15 -3
  119. package/src/superlocalmemory/ui/js/optimize.js +18 -2
  120. package/src/superlocalmemory/ui/js/trust-dashboard.js +10 -1
  121. package/src/superlocalmemory.egg-info/PKG-INFO +191 -741
  122. package/src/superlocalmemory.egg-info/SOURCES.txt +7 -9
  123. package/src/superlocalmemory.egg-info/requires.txt +1 -0
  124. package/ide/skills/slm-build-graph/SKILL.md +0 -423
  125. package/ide/skills/slm-list-recent/SKILL.md +0 -348
  126. package/ide/skills/slm-recall/SKILL.md +0 -326
  127. package/ide/skills/slm-remember/SKILL.md +0 -194
  128. package/ide/skills/slm-show-patterns/SKILL.md +0 -224
  129. package/ide/skills/slm-status/SKILL.md +0 -363
  130. package/ide/skills/slm-switch-profile/SKILL.md +0 -442
  131. package/skills/slm-build-graph/SKILL.md +0 -423
  132. package/skills/slm-list-recent/SKILL.md +0 -348
  133. package/skills/slm-optimize/README.md +0 -55
  134. package/skills/slm-optimize/SKILL.md +0 -139
  135. package/skills/slm-recall/SKILL.md +0 -343
  136. package/skills/slm-remember/SKILL.md +0 -194
  137. package/skills/slm-show-patterns/SKILL.md +0 -224
  138. package/skills/slm-status/SKILL.md +0 -363
  139. package/skills/slm-switch-profile/SKILL.md +0 -442
  140. package/src/superlocalmemory/cli/doctor_cmd.py +0 -152
  141. package/src/superlocalmemory/skills/slm-build-graph/SKILL.md +0 -423
  142. package/src/superlocalmemory/skills/slm-list-recent/SKILL.md +0 -348
  143. package/src/superlocalmemory/skills/slm-recall/SKILL.md +0 -343
  144. package/src/superlocalmemory/skills/slm-remember/SKILL.md +0 -194
  145. package/src/superlocalmemory/skills/slm-show-patterns/SKILL.md +0 -224
  146. package/src/superlocalmemory/skills/slm-status/SKILL.md +0 -363
  147. package/src/superlocalmemory/skills/slm-switch-profile/SKILL.md +0 -442
@@ -50,6 +50,8 @@ from fastapi.middleware.cors import CORSMiddleware
50
50
  from fastapi.middleware.gzip import GZipMiddleware
51
51
  from pydantic import BaseModel
52
52
 
53
+ from superlocalmemory.core.config import CANONICAL_RECALL_LIMIT
54
+
53
55
  logger = logging.getLogger("superlocalmemory.unified_daemon")
54
56
 
55
57
  _DEFAULT_PORT = 8765
@@ -66,6 +68,24 @@ class RememberRequest(BaseModel):
66
68
  content: str
67
69
  tags: str = ""
68
70
  metadata: dict | None = None # v3.4.26: pass-through from MCP pool_store
71
+ # v3.6.15 multi-scope: visibility of the new memory. ``None`` scope means
72
+ # "use the configured default_scope" (personal). shared_with is the list of
73
+ # profile_ids for scope='shared'.
74
+ scope: str | None = None
75
+ shared_with: list[str] | None = None
76
+
77
+
78
+ class SessionOpenRequest(BaseModel):
79
+ # #49: local session-open warm (no model roundtrip needed)
80
+ project_path: str = ""
81
+ query: str = ""
82
+ max_results: int = 10
83
+
84
+
85
+ class SessionCloseRequest(BaseModel):
86
+ # #49: local session-close (e.g. a Claude /quit hook). Empty session_id
87
+ # closes the most recent real session.
88
+ session_id: str = ""
69
89
 
70
90
 
71
91
  class ObserveRequest(BaseModel):
@@ -237,16 +257,32 @@ class ObserveBuffer:
237
257
  try:
238
258
  from superlocalmemory.hooks.auto_capture import AutoCapture
239
259
  auto = AutoCapture(engine=self._engine)
260
+ captured_count = 0
261
+ failed_count = 0
240
262
  for content in batch:
241
263
  try:
242
264
  decision = auto.evaluate(content)
243
265
  if decision.capture:
244
266
  auto.capture(content, category=decision.category)
245
- except Exception:
246
- pass
247
- logger.info("Observe debounce: processed %d observations", len(batch))
248
- except Exception:
249
- pass
267
+ # Stage-9: count only what was actually WRITTEN to memory.
268
+ # The prior 'processed N' counted skipped (capture=False)
269
+ # items as successes a false-positive write count.
270
+ captured_count += 1
271
+ except Exception as exc:
272
+ failed_count += 1
273
+ logger.warning(
274
+ "ObserveBuffer: auto.capture failed for content %.40r: %s",
275
+ content,
276
+ exc,
277
+ )
278
+ logger.info(
279
+ "Observe debounce: evaluated=%d captured=%d failed=%d",
280
+ len(batch),
281
+ captured_count,
282
+ failed_count,
283
+ )
284
+ except Exception as exc:
285
+ logger.error("ObserveBuffer: flush batch failed: %s", exc)
250
286
 
251
287
  def flush_sync(self) -> None:
252
288
  """Force flush for shutdown."""
@@ -858,8 +894,14 @@ async def lifespan(application: FastAPI):
858
894
  from superlocalmemory.optimize.storage.db import CacheDB
859
895
  application.include_router(optimize_router)
860
896
 
861
- # Restore persisted metrics counters on startup
862
- MetricsPersistence().load(MetricsCollector.get_instance(), CacheDB())
897
+ # Restore persisted metrics counters on startup.
898
+ # #48 fix: build ONE CacheDB + MetricsPersistence and reuse them for the
899
+ # life of the daemon. The old code constructed a new CacheDB() on every
900
+ # 60s flush, which re-ran schema init ("Schema initialized" log spam),
901
+ # the corruption check, and AES-key derivation on every tick.
902
+ _metrics_db = CacheDB()
903
+ _metrics_persistence = MetricsPersistence()
904
+ _metrics_persistence.load(MetricsCollector.get_instance(), _metrics_db)
863
905
 
864
906
  # Periodic flush — every 60s (OPT-005: guard + task ref for shutdown)
865
907
  _metrics_flush_task = getattr(application.state, "_optimize_flush_task", None)
@@ -868,8 +910,8 @@ async def lifespan(application: FastAPI):
868
910
  while True:
869
911
  await asyncio.sleep(60)
870
912
  try:
871
- MetricsPersistence().flush(
872
- MetricsCollector.get_instance(), CacheDB()
913
+ _metrics_persistence.flush(
914
+ MetricsCollector.get_instance(), _metrics_db
873
915
  )
874
916
  except Exception as e:
875
917
  logger.warning("metrics flush error: %s", e)
@@ -1620,11 +1662,13 @@ def _register_daemon_routes(application: FastAPI) -> None:
1620
1662
  @application.get("/recall")
1621
1663
  async def recall(
1622
1664
  request: Request,
1623
- q: str = "", query: str = "", limit: int = 20,
1665
+ q: str = "", query: str = "", limit: int = CANONICAL_RECALL_LIMIT,
1624
1666
  session_id: str = "",
1625
1667
  fast: bool = False,
1626
1668
  full: bool = False,
1627
1669
  include_source: bool = False,
1670
+ include_global: bool | None = None,
1671
+ include_shared: bool | None = None,
1628
1672
  ):
1629
1673
  _update_activity()
1630
1674
  search_query = q or query # Accept both ?q= and ?query= for compatibility
@@ -1660,6 +1704,8 @@ def _register_daemon_routes(application: FastAPI) -> None:
1660
1704
  engine.recall,
1661
1705
  search_query, limit=limit, session_id=effective_sid,
1662
1706
  fast=fast,
1707
+ include_global=include_global,
1708
+ include_shared=include_shared,
1663
1709
  )
1664
1710
  # v3.4.26: return the same field shape as recall_worker so
1665
1711
  # MCP processes proxying through the daemon get recall_trace-
@@ -1721,13 +1767,23 @@ def _register_daemon_routes(application: FastAPI) -> None:
1721
1767
  _update_activity()
1722
1768
  engine = _get_engine_or_503()
1723
1769
 
1770
+ # v3.6.15 multi-scope: resolve the write scope. ``None`` (not specified
1771
+ # by the caller) → the configured default_scope (personal). Shared
1772
+ # memory is opt-in, so the default keeps every write private.
1773
+ _scope_cfg = getattr(engine._config, "scope", None)
1774
+ scope = req.scope or getattr(_scope_cfg, "default_scope", "personal")
1775
+ shared_with = req.shared_with
1776
+
1724
1777
  if wait:
1725
1778
  try:
1726
1779
  metadata = {"tags": req.tags} if req.tags else {}
1727
1780
  extra = getattr(req, "metadata", None)
1728
1781
  if isinstance(extra, dict):
1729
1782
  metadata.update(extra)
1730
- fact_ids = engine.store(req.content, metadata=metadata)
1783
+ fact_ids = engine.store(
1784
+ req.content, metadata=metadata,
1785
+ scope=scope, shared_with=shared_with,
1786
+ )
1731
1787
  return {"ok": True, "fact_ids": fact_ids, "count": len(fact_ids)}
1732
1788
  except Exception as exc:
1733
1789
  raise HTTPException(500, detail=str(exc))
@@ -1740,13 +1796,25 @@ def _register_daemon_routes(application: FastAPI) -> None:
1740
1796
  extra = getattr(req, "metadata", None)
1741
1797
  if isinstance(extra, dict):
1742
1798
  meta.update(extra)
1799
+ # v3.6.15 multi-scope: persist the resolved scope INSIDE the pending
1800
+ # metadata so the materializer (_process_pending_memories) replays
1801
+ # the write with the correct visibility instead of defaulting to
1802
+ # personal. Non-personal only — keeps personal rows byte-identical
1803
+ # to pre-3.6.15 so nothing downstream sees a new key by default.
1804
+ if scope and scope != "personal":
1805
+ meta["scope"] = scope
1806
+ if shared_with:
1807
+ meta["shared_with"] = shared_with
1743
1808
  # v3.5.5 WRITE-THROUGH: synchronous verbatim insert → the memory is
1744
1809
  # keyword/BM25-recallable the instant this returns (~ms). Closes the
1745
1810
  # recall window so a parallel/next agent finds memories saved seconds
1746
1811
  # ago. Embedding/graph enrichment is deferred to the materializer.
1747
1812
  fact_ids: list[str] = []
1748
1813
  try:
1749
- fact_ids = engine.store_fast(req.content, metadata=meta)
1814
+ fact_ids = engine.store_fast(
1815
+ req.content, metadata=meta,
1816
+ scope=scope, shared_with=shared_with,
1817
+ )
1750
1818
  except Exception as fexc:
1751
1819
  logger.warning("store_fast failed, falling back to pending-only: %s", fexc)
1752
1820
  # Enqueue for async enrichment (embedding + entities + graph). The
@@ -1883,6 +1951,65 @@ def _register_daemon_routes(application: FastAPI) -> None:
1883
1951
  os.kill(os.getpid(), signal.SIGTERM)
1884
1952
  return {"status": "stopping"}
1885
1953
 
1954
+ @application.post("/session/open")
1955
+ async def session_open(req: SessionOpenRequest):
1956
+ """#49: Open a session locally — warm recall context with no model
1957
+ roundtrip, so a shell/session-start hook can call it directly
1958
+ (`slm session open`) instead of going through the MCP tool.
1959
+ """
1960
+ _update_activity()
1961
+ engine = _get_engine_or_503()
1962
+ if req.query:
1963
+ query = req.query
1964
+ elif req.project_path:
1965
+ query = f"project context {req.project_path}"
1966
+ else:
1967
+ query = "recent important decisions"
1968
+ try:
1969
+ resp = engine.recall(query, limit=req.max_results)
1970
+ results = (
1971
+ getattr(resp, "results", None)
1972
+ or getattr(resp, "memories", None)
1973
+ or []
1974
+ )
1975
+ return {"ok": True, "query": query, "warmed": len(results)}
1976
+ except Exception as exc:
1977
+ # Warming is best-effort — never fail the session-open hook.
1978
+ return {"ok": True, "query": query, "warmed": 0, "warning": str(exc)}
1979
+
1980
+ @application.post("/session/close")
1981
+ async def session_close(req: SessionCloseRequest):
1982
+ """#49: Close a session locally (e.g. a Claude /quit hook calling
1983
+ `slm session close`). Creates per-entity temporal summary events.
1984
+ An empty session_id closes the most recent real session.
1985
+ """
1986
+ _update_activity()
1987
+ engine = _get_engine_or_503()
1988
+ sid = req.session_id
1989
+ if not sid:
1990
+ # Fall back to the most recent session that has memories.
1991
+ try:
1992
+ db = getattr(engine, "_db", None) or getattr(engine, "db", None)
1993
+ if db is not None and hasattr(db, "execute"):
1994
+ rows = db.execute(
1995
+ "SELECT session_id FROM memories "
1996
+ "WHERE session_id != '' ORDER BY created_at DESC LIMIT 1",
1997
+ (),
1998
+ )
1999
+ if rows:
2000
+ sid = str(rows[0][0])
2001
+ except Exception as exc:
2002
+ logger.debug("session_close fallback lookup failed: %s", exc)
2003
+ if not sid:
2004
+ return {"ok": True, "session_id": "", "summary_events_created": 0,
2005
+ "message": "no session to close"}
2006
+ try:
2007
+ created = engine.close_session(sid)
2008
+ return {"ok": True, "session_id": sid,
2009
+ "summary_events_created": int(created)}
2010
+ except Exception as exc:
2011
+ raise HTTPException(500, detail=str(exc))
2012
+
1886
2013
 
1887
2014
  def _update_activity():
1888
2015
  global _last_activity
@@ -1998,10 +2125,14 @@ def _start_pending_materializer() -> None:
1998
2125
  # embedding, ENRICH it in place (compute embedding +
1999
2126
  # upsert vector store) rather than skipping — otherwise
2000
2127
  # the fact would never be semantically searchable.
2128
+ # v3.6.15: scope the dedup to THIS profile. Without the
2129
+ # profile_id filter, a memory whose verbatim text matches
2130
+ # another profile's fact was treated as a duplicate and
2131
+ # silently dropped — cross-profile data loss + leakage.
2001
2132
  dup = engine._db.execute(
2002
2133
  "SELECT fact_id, embedding FROM atomic_facts "
2003
- "WHERE content = ? LIMIT 1",
2004
- (content,),
2134
+ "WHERE content = ? AND profile_id = ? LIMIT 1",
2135
+ (content, engine._profile_id),
2005
2136
  )
2006
2137
  if dup:
2007
2138
  try:
@@ -2032,6 +2163,12 @@ def _start_pending_materializer() -> None:
2032
2163
  md = {}
2033
2164
  if item.get("tags"):
2034
2165
  md.setdefault("tags", item["tags"])
2166
+ # v3.6.15: replay the scope the async /remember path
2167
+ # stashed in metadata, so a queued non-personal write
2168
+ # materializes with the right visibility (not personal).
2169
+ _mscope = md.get("scope") or "personal"
2170
+ _mshared = md.get("shared_with")
2171
+ _shared_json = _json.dumps(_mshared) if _mshared else None
2035
2172
  # Create memory row (FK target for atomic_facts)
2036
2173
  from datetime import datetime, timezone
2037
2174
  from superlocalmemory.storage.models import (
@@ -2042,17 +2179,20 @@ def _start_pending_materializer() -> None:
2042
2179
  "INSERT OR IGNORE INTO memories "
2043
2180
  "(memory_id, profile_id, content, "
2044
2181
  "session_id, speaker, role, created_at, "
2045
- "metadata_json) VALUES (?,?,?,?,?,?,?,?)",
2182
+ "metadata_json, scope, shared_with) "
2183
+ "VALUES (?,?,?,?,?,?,?,?,?,?)",
2046
2184
  (mem_id, engine._profile_id, content,
2047
2185
  "", "", "user",
2048
2186
  datetime.now(timezone.utc).isoformat(),
2049
- _json.dumps(md)),
2187
+ _json.dumps(md), _mscope, _shared_json),
2050
2188
  )
2051
2189
  fact = AtomicFact(
2052
2190
  content=content,
2053
2191
  fact_type=FactType.EPISODIC,
2054
2192
  memory_id=mem_id,
2055
2193
  profile_id=engine._profile_id,
2194
+ scope=_mscope,
2195
+ shared_with=_mshared,
2056
2196
  )
2057
2197
  engine.store_fact_direct(fact)
2058
2198
  mark_done(item["id"])