loop-memory 0.4.11__tar.gz → 0.4.12__tar.gz

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 (156) hide show
  1. {loop_memory-0.4.11 → loop_memory-0.4.12}/PKG-INFO +3 -1
  2. {loop_memory-0.4.11 → loop_memory-0.4.12}/README.md +2 -0
  3. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/cli/commands/cognitive.py +46 -0
  4. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/cli/main.py +4 -0
  5. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/serve/routes/system.py +43 -0
  6. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/storage/sqlite_store.py +572 -1
  7. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory.egg-info/PKG-INFO +3 -1
  8. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory.egg-info/SOURCES.txt +2 -0
  9. {loop_memory-0.4.11 → loop_memory-0.4.12}/pyproject.toml +1 -1
  10. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_agents_init.py +3 -3
  11. loop_memory-0.4.12/tests/test_audit_triggers_2026_09_27.py +188 -0
  12. loop_memory-0.4.12/tests/test_import_okf_2026_09_27.py +425 -0
  13. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_supersession_chain.py +1 -1
  14. {loop_memory-0.4.11 → loop_memory-0.4.12}/LICENSE +0 -0
  15. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/__init__.py +0 -0
  16. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/backends/__init__.py +0 -0
  17. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/backends/embedding.py +0 -0
  18. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/backends/sentence_embedder.py +0 -0
  19. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/backends/vector_store.py +0 -0
  20. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/cli/__init__.py +0 -0
  21. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/cli/_common.py +0 -0
  22. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/cli/commands/__init__.py +0 -0
  23. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/cli/commands/diag.py +0 -0
  24. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/cli/commands/graph.py +0 -0
  25. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/cli/commands/hooks.py +0 -0
  26. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/cli/commands/read.py +0 -0
  27. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/cli/commands/rules.py +0 -0
  28. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/cli/commands/serve.py +0 -0
  29. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/cli/commands/write.py +0 -0
  30. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/engine/__init__.py +0 -0
  31. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/engine/loop.py +0 -0
  32. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/engine/reflect.py +0 -0
  33. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/examples/__init__.py +0 -0
  34. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/examples/demo.py +0 -0
  35. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/export/__init__.py +0 -0
  36. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/export/memory_md.py +0 -0
  37. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/graph/__init__.py +0 -0
  38. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/graph/build.py +0 -0
  39. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/graph/extract.py +0 -0
  40. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/ingest/__init__.py +0 -0
  41. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/ingest/loader.py +0 -0
  42. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/ingest/pipeline.py +0 -0
  43. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/jobs/__init__.py +0 -0
  44. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/jobs/cognitive.py +0 -0
  45. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/jobs/compact.py +0 -0
  46. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/jobs/consolidate.py +0 -0
  47. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/jobs/contradiction.py +0 -0
  48. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/jobs/evolution.py +0 -0
  49. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/jobs/graph.py +0 -0
  50. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/jobs/llm_compact_pass.py +0 -0
  51. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/jobs/llm_consolidate.py +0 -0
  52. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/jobs/scheduler.py +0 -0
  53. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/llm/__init__.py +0 -0
  54. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/llm/base.py +0 -0
  55. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/llm/openai_adapter.py +0 -0
  56. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/llm/providers.py +0 -0
  57. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/mcp/__init__.py +0 -0
  58. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/memory/__init__.py +0 -0
  59. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/memory/types.py +0 -0
  60. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/privacy/__init__.py +0 -0
  61. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/privacy/private.py +0 -0
  62. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/privacy/redact.py +0 -0
  63. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/py.typed +0 -0
  64. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/sdk.py +0 -0
  65. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/sdk_extensions.py +0 -0
  66. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/security/__init__.py +0 -0
  67. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/security/secrets.py +0 -0
  68. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/serve/__init__.py +0 -0
  69. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/serve/app.py +0 -0
  70. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/serve/handlers.py +0 -0
  71. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/serve/routes/_shared.py +0 -0
  72. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/serve/routes/admin.py +0 -0
  73. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/serve/routes/cognitive.py +0 -0
  74. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/serve/routes/export.py +0 -0
  75. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/serve/routes/graph.py +0 -0
  76. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/serve/routes/insights.py +0 -0
  77. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/serve/routes/memories.py +0 -0
  78. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/serve/routes/sessions.py +0 -0
  79. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/serve/routes/wiki.py +0 -0
  80. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/serve/static/__init__.py +0 -0
  81. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/serve/static/index.html +0 -0
  82. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/serve/watcher.py +0 -0
  83. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/storage/__init__.py +0 -0
  84. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/storage/retrieval.py +0 -0
  85. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/storage/snapshot.py +0 -0
  86. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/wiki/__init__.py +0 -0
  87. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/wiki/backfill.py +0 -0
  88. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/wiki/classifier.py +0 -0
  89. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/wiki/prompts.py +0 -0
  90. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory/wiki/scope.py +0 -0
  91. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory.egg-info/dependency_links.txt +0 -0
  92. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory.egg-info/entry_points.txt +0 -0
  93. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory.egg-info/requires.txt +0 -0
  94. {loop_memory-0.4.11 → loop_memory-0.4.12}/loop_memory.egg-info/top_level.txt +0 -0
  95. {loop_memory-0.4.11 → loop_memory-0.4.12}/setup.cfg +0 -0
  96. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_admin_ingest_route.py +0 -0
  97. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_agent_memory_api.py +0 -0
  98. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_agent_memory_sdk.py +0 -0
  99. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_auth_token_rotate.py +0 -0
  100. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_busy_timeout_2026_09_24.py +0 -0
  101. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_cache_cap_2026_09_23.py +0 -0
  102. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_cli_audit_supersede.py +0 -0
  103. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_cli_export_okf.py +0 -0
  104. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_cli_init.py +0 -0
  105. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_cli_memory_stats.py +0 -0
  106. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_cli_recall_as_of.py +0 -0
  107. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_cli_recall_paths.py +0 -0
  108. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_cli_recall_verbose.py +0 -0
  109. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_cli_rules.py +0 -0
  110. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_cli_snapshot.py +0 -0
  111. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_cli_v7.py +0 -0
  112. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_cli_version.py +0 -0
  113. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_contradictions.py +0 -0
  114. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_evolution.py +0 -0
  115. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_evolution_quality.py +0 -0
  116. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_expanduser.py +0 -0
  117. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_export_ask.py +0 -0
  118. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_export_okf.py +0 -0
  119. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_graph.py +0 -0
  120. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_healthz_readyz_2026_09_24.py +0 -0
  121. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_ingest.py +0 -0
  122. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_llm_consolidator.py +0 -0
  123. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_llm_fingerprint_not_persisted.py +0 -0
  124. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_llm_providers.py +0 -0
  125. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_llm_test_endpoint.py +0 -0
  126. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_loop.py +0 -0
  127. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_mcp.py +0 -0
  128. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_memories_pagination.py +0 -0
  129. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_memory_stats.py +0 -0
  130. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_openclaw_loader.py +0 -0
  131. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_package_version.py +0 -0
  132. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_path_safety_2026_09_23.py +0 -0
  133. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_recall_as_of.py +0 -0
  134. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_recall_paths.py +0 -0
  135. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_recall_provenance.py +0 -0
  136. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_reflection.py +0 -0
  137. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_repo_framing.py +0 -0
  138. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_routes_audit_2026_09_13.py +0 -0
  139. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_routes_audit_2026_09_20.py +0 -0
  140. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_score_api.py +0 -0
  141. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_scoring_v2.py +0 -0
  142. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_secrets.py +0 -0
  143. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_serve_app.py +0 -0
  144. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_serve_handlers.py +0 -0
  145. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_session_order.py +0 -0
  146. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_short_query.py +0 -0
  147. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_snapshot.py +0 -0
  148. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_store.py +0 -0
  149. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_subgraph_hops_2026_09_23.py +0 -0
  150. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_summarization.py +0 -0
  151. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_universal_memory.py +0 -0
  152. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_vector_store.py +0 -0
  153. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_watcher.py +0 -0
  154. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_wiki_classifier.py +0 -0
  155. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_wiki_export_escape.py +0 -0
  156. {loop_memory-0.4.11 → loop_memory-0.4.12}/tests/test_wiki_prompts.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: loop-memory
3
- Version: 0.4.11
3
+ Version: 0.4.12
4
4
  Summary: A general-purpose, local memory system for every AI agent you run. Loop Memory auto-captures conversations from Codex / Claude / Hermes / OpenClaw, scores them by importance × recency × usage × feedback, distils them into a curated wiki, and serves everything from a single web UI.
5
5
  Author: Loop Memory contributors <loop-memory@users.noreply.github.com>
6
6
  License-Expression: MIT
@@ -66,6 +66,8 @@ Dynamic: license-file
66
66
 
67
67
  ---
68
68
 
69
+ > **What's new in 0.4.12** — **OKF bundle import** + **DB-level audit enforcement** (audit 2026-09-27). The new `loop-memory import-okf <in_dir>` (and `POST /api/import/okf`) is the symmetric counterpart to `export-okf` (0.4.9) — bring an OKF v0.2 bundle back into Loop Memory as wiki pages, with idempotent upsert on `(scope, slug)`, optional `--dry-run` and `--skip-conflicts`. Source: `thecolourfoundation/rune` HN launch (MIT, 2026-09-25) + `okf-memory/okf-agent-memory` Issues #12-#15 + `Deja-Vu` (MIT, 2026-09-24) + Google OKF v0.2 spec (Apache-2.0, 2026-09-01). The new `MemoryStore._install_audit_triggers()` installs 12 SQLite triggers on `memories` / `wiki_pages` / `relations` / `consolidation_runs` so the `audit_log` table cannot be skipped — even a raw `sqlite3` writer that bypasses the Python wrapper still appends an audit row with `actor='db_trigger'`. New `MemoryStore.list_audit_log()` reads the log; `GET /api/stats` reports `audit_log` + `audit_triggers` counts. Source: `cogstate-eng/memory-eternal v0.4.3` `enforceAudit()` pattern (MIT, 2026-09-23). 31 new regression cases. [Full CHANGELOG →](./CHANGELOG.md#0412---2026-09-27)
70
+
69
71
  > **What's new in 0.4.11** — **operational probes** +
70
72
  **SQLite write-contention fix** (audit 2026-09-24). New
71
73
  ``GET /api/healthz`` (liveness) + ``GET /api/readyz``
@@ -22,6 +22,8 @@
22
22
 
23
23
  ---
24
24
 
25
+ > **What's new in 0.4.12** — **OKF bundle import** + **DB-level audit enforcement** (audit 2026-09-27). The new `loop-memory import-okf <in_dir>` (and `POST /api/import/okf`) is the symmetric counterpart to `export-okf` (0.4.9) — bring an OKF v0.2 bundle back into Loop Memory as wiki pages, with idempotent upsert on `(scope, slug)`, optional `--dry-run` and `--skip-conflicts`. Source: `thecolourfoundation/rune` HN launch (MIT, 2026-09-25) + `okf-memory/okf-agent-memory` Issues #12-#15 + `Deja-Vu` (MIT, 2026-09-24) + Google OKF v0.2 spec (Apache-2.0, 2026-09-01). The new `MemoryStore._install_audit_triggers()` installs 12 SQLite triggers on `memories` / `wiki_pages` / `relations` / `consolidation_runs` so the `audit_log` table cannot be skipped — even a raw `sqlite3` writer that bypasses the Python wrapper still appends an audit row with `actor='db_trigger'`. New `MemoryStore.list_audit_log()` reads the log; `GET /api/stats` reports `audit_log` + `audit_triggers` counts. Source: `cogstate-eng/memory-eternal v0.4.3` `enforceAudit()` pattern (MIT, 2026-09-23). 31 new regression cases. [Full CHANGELOG →](./CHANGELOG.md#0412---2026-09-27)
26
+
25
27
  > **What's new in 0.4.11** — **operational probes** +
26
28
  **SQLite write-contention fix** (audit 2026-09-24). New
27
29
  ``GET /api/healthz`` (liveness) + ``GET /api/readyz``
@@ -119,6 +119,23 @@ def _build_parser() -> argparse.ArgumentParser:
119
119
  eo.add_argument("--scope", default=None,
120
120
  help="Filter: 'global' or a single source token (e.g. codex)")
121
121
 
122
+ # Audit 2026-09-27: OKF v0.2 bundle import
123
+ # (thecolourfoundation/rune + okf-memory/okf-agent-memory Issues
124
+ # #12-#15 + Deja-Vu HN front-page). Symmetric counterpart to
125
+ # ``export-okf`` (0.4.9): bring an OKF bundle back into Loop
126
+ # Memory as wiki pages. Idempotent upsert on (scope, slug).
127
+ io = sub.add_parser(
128
+ "import-okf",
129
+ help="Import an OKF v0.2 bundle directory as wiki pages")
130
+ io.add_argument("in_dir",
131
+ help="Bundle directory containing index.md and pages/")
132
+ io.add_argument("--scope", default=None,
133
+ help="Scope tag for imported pages (default: bundle's index.md, then 'global')")
134
+ io.add_argument("--dry-run", action="store_true",
135
+ help="Parse every file but do not write")
136
+ io.add_argument("--skip-conflicts", action="store_true",
137
+ help="Don't overwrite an existing (scope, slug) row")
138
+
122
139
  return p
123
140
 
124
141
 
@@ -375,3 +392,32 @@ def run_export_okf(args) -> int:
375
392
  s = MemoryStore(ns.db)
376
393
  r = s.export_okf(ns.out_dir, scope_filter=ns.scope)
377
394
  return _emit(r)
395
+
396
+
397
+ def run_import_okf(args) -> int:
398
+ """``loop-memory import-okf <in_dir> [--scope S] [--dry-run] [--skip-conflicts]``
399
+
400
+ Audit 2026-09-27: OKF v0.2 bundle import
401
+ (thecolourfoundation/rune + okf-memory/okf-agent-memory Issues
402
+ #12-#15 + Deja-Vu HN front-page). Returns the summary dict
403
+ from ``MemoryStore.import_okf`` so the caller can confirm what
404
+ landed where. ``--dry-run`` parses every file but writes nothing;
405
+ ``--skip-conflicts`` turns INSERT-vs-existing conflicts into
406
+ a ``skipped`` counter rather than an UPDATE.
407
+ """
408
+ import argparse as _ap
409
+ p = _ap.ArgumentParser(prog="loop-memory import-okf")
410
+ p.add_argument("in_dir")
411
+ p.add_argument("--scope", default=None)
412
+ p.add_argument("--dry-run", action="store_true")
413
+ p.add_argument("--skip-conflicts", action="store_true")
414
+ p.add_argument("--db", default=os.environ.get("LOOP_MEMORY_DB", DEFAULT_DB))
415
+ ns = p.parse_args(args)
416
+ s = MemoryStore(ns.db)
417
+ r = s.import_okf(
418
+ ns.in_dir,
419
+ scope=ns.scope,
420
+ dry_run=ns.dry_run,
421
+ skip_conflicts=ns.skip_conflicts,
422
+ )
423
+ return _emit(r)
@@ -26,6 +26,7 @@ Usage:
26
26
  loop-memory export <out_dir> # write a MEMORY.md bundle (v7)
27
27
  loop-memory export-bundle <out_dir> # explicit v7 bundle alias
28
28
  loop-memory import <in_dir> # re-hydrate a bundle
29
+ loop-memory import-okf <in_dir> [--scope S] [--dry-run] [--skip-conflicts] # ingest an OKF v0.2 bundle as wiki pages (audit 2026-09-27)
29
30
  loop-memory fork [--branch-tag T] # snapshot every wiki page
30
31
  loop-memory graph-edge <src> <dst> [--kind K] [--weight W] # push a relation
31
32
  loop-memory subgraph <query> # print a small subgraph
@@ -128,6 +129,8 @@ COMMANDS = {
128
129
  # Audit 2026-09-20 — OKF v0.2 export (akitaonrails/ai-memory 2.0
129
130
  # + okf-agent-memory + Google OKF spec).
130
131
  "export-okf": cognitive_cmd.run_export_okf,
132
+ # Audit 2026-09-27: OKF v0.2 bundle import (rune + okf-agent-memory #12-#15 + Deja-Vu).
133
+ "import-okf": cognitive_cmd.run_import_okf,
131
134
  "rules": rules_cmd.run_rules,
132
135
  "version": _run_version,
133
136
  }
@@ -172,6 +175,7 @@ COMMAND_HELP: dict[str, str] = {
172
175
  "memory-stats": "loop-memory memory-stats <id> [--prefix] # per-memory lifetime stats (audit 2026-09-06, agentmemory v1.3.0).",
173
176
  "snapshot": "loop-memory snapshot <out.memory.sqlite> # write a portable SQLite snapshot (audit 2026-09-06, codexa-memory v0.2.0).",
174
177
  "export-okf": "loop-memory export-okf <out_dir> [--scope S] # write an OKF v0.2 bundle (audit 2026-09-20).",
178
+ "import-okf": "loop-memory import-okf <in_dir> [--scope S] [--dry-run] [--skip-conflicts] # ingest an OKF v0.2 bundle as wiki pages (audit 2026-09-27).",
175
179
  "restore": "loop-memory restore <in.memory.sqlite> # re-hydrate a portable SQLite snapshot.",
176
180
  # Audit 2026-09-13 — L0 outline recall (tigerless-labs/agent-memory v0.3.0).
177
181
  "recall-paths": "loop-memory recall-paths <query> [--limit N] # cheap L0 outline (id+abstract+score) instead of full text (audit 2026-09-13).",
@@ -485,6 +485,49 @@ def register(app: FastAPI, store: MemoryStore, scheduler: Optional[Any] = None,
485
485
  raise HTTPException(500, f"export-okf failed: {e}")
486
486
  return r
487
487
 
488
+ @app.post("/api/import/okf")
489
+ def import_okf(body: dict):
490
+ """Audit 2026-09-27: OKF v0.2 bundle import.
491
+
492
+ Body shape::
493
+
494
+ {
495
+ "in_dir": "/abs/path/to/bundle",
496
+ "scope": "global", # optional
497
+ "dry_run": false, # optional
498
+ "skip_conflicts": false # optional
499
+ }
500
+
501
+ Walks ``<in_dir>/index.md`` + ``<in_dir>/pages/*.md`` and
502
+ upserts each page as a wiki row keyed on ``(scope, slug)``.
503
+ ``in_dir`` is validated by ``_safe_resolve_path`` (live DB
504
+ + system dirs are still refused; per-user temp is OK).
505
+ Returns the same summary dict as the CLI handler.
506
+ """
507
+ from ._shared import _safe_resolve_path as _safe_path
508
+ in_dir = (body.get("in_dir") or "").strip()
509
+ if not in_dir:
510
+ raise HTTPException(400, "in_dir is required")
511
+ scope = body.get("scope")
512
+ if scope is not None:
513
+ scope = str(scope).strip() or None
514
+ dry_run = bool(body.get("dry_run", False))
515
+ skip_conflicts = bool(body.get("skip_conflicts", False))
516
+ try:
517
+ safe_dir = _safe_path(in_dir, kind="read", live_db_path=str(store.path))
518
+ except ValueError as e:
519
+ raise HTTPException(400, str(e))
520
+ try:
521
+ r = store.import_okf(
522
+ safe_dir,
523
+ scope=scope,
524
+ dry_run=dry_run,
525
+ skip_conflicts=skip_conflicts,
526
+ )
527
+ except Exception as e:
528
+ raise HTTPException(500, f"import-okf failed: {e}")
529
+ return r
530
+
488
531
  @app.get("/api/recall/outline")
489
532
  def recall_outline(query: str = "", limit: int = 12,
490
533
  include: str = "memories,wiki,entities",