memu-cli 0.2.0__tar.gz → 0.3.0__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 (195) hide show
  1. {memu_cli-0.2.0 → memu_cli-0.3.0}/.github/workflows/publish-memu-cli.yml +11 -16
  2. {memu_cli-0.2.0 → memu_cli-0.3.0}/.github/workflows/release-please.yml +3 -7
  3. {memu_cli-0.2.0 → memu_cli-0.3.0}/PKG-INFO +24 -13
  4. {memu_cli-0.2.0 → memu_cli-0.3.0}/README.md +22 -11
  5. memu_cli-0.3.0/SKILL.md +78 -0
  6. {memu_cli-0.2.0 → memu_cli-0.3.0}/docs/adr/0009-codex-packaging-cli-and-config.md +1 -1
  7. memu_cli-0.3.0/docs/adr/0010-multi-host-adapters.md +167 -0
  8. memu_cli-0.3.0/docs/adr/0011-generic-host-adapter.md +85 -0
  9. {memu_cli-0.2.0 → memu_cli-0.3.0}/docs/adr/README.md +2 -0
  10. {memu_cli-0.2.0 → memu_cli-0.3.0}/npm/README.md +2 -2
  11. {memu_cli-0.2.0 → memu_cli-0.3.0}/npm/bin/memu.js +1 -2
  12. {memu_cli-0.2.0 → memu_cli-0.3.0}/npm/package.json +1 -1
  13. {memu_cli-0.2.0 → memu_cli-0.3.0}/pyproject.toml +11 -3
  14. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/hosts/base.py +8 -0
  15. memu_cli-0.3.0/src/memu/hosts/claude_code/BRIDGING_TASK.md +85 -0
  16. memu_cli-0.3.0/src/memu/hosts/claude_code/INSTALL.md +153 -0
  17. memu_cli-0.3.0/src/memu/hosts/claude_code/__init__.py +11 -0
  18. memu_cli-0.3.0/src/memu/hosts/claude_code/cli.py +47 -0
  19. memu_cli-0.3.0/src/memu/hosts/claude_code/sessions.py +72 -0
  20. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/hosts/codex/INSTALL.md +1 -1
  21. memu_cli-0.3.0/src/memu/hosts/codex/cli.py +68 -0
  22. memu_cli-0.3.0/src/memu/hosts/cursor/BRIDGING_TASK.md +80 -0
  23. memu_cli-0.3.0/src/memu/hosts/cursor/INSTALL.md +126 -0
  24. memu_cli-0.3.0/src/memu/hosts/cursor/__init__.py +11 -0
  25. memu_cli-0.3.0/src/memu/hosts/cursor/cli.py +48 -0
  26. memu_cli-0.3.0/src/memu/hosts/cursor/sessions.py +74 -0
  27. memu_cli-0.3.0/src/memu/hosts/generic/BRIDGING_TASK.md +107 -0
  28. memu_cli-0.3.0/src/memu/hosts/generic/INSTALL.md +151 -0
  29. memu_cli-0.3.0/src/memu/hosts/generic/__init__.py +12 -0
  30. memu_cli-0.3.0/src/memu/hosts/generic/cli.py +85 -0
  31. memu_cli-0.3.0/src/memu/hosts/generic/detect.py +207 -0
  32. memu_cli-0.3.0/src/memu/hosts/generic/sessions.py +141 -0
  33. memu_cli-0.3.0/src/memu/hosts/hermes/BRIDGING_TASK.md +83 -0
  34. memu_cli-0.3.0/src/memu/hosts/hermes/INSTALL.md +128 -0
  35. memu_cli-0.3.0/src/memu/hosts/hermes/__init__.py +12 -0
  36. memu_cli-0.3.0/src/memu/hosts/hermes/cli.py +49 -0
  37. memu_cli-0.3.0/src/memu/hosts/hermes/sessions.py +126 -0
  38. memu_cli-0.3.0/src/memu/hosts/host_cli.py +221 -0
  39. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/hosts/instruction.py +48 -29
  40. memu_cli-0.3.0/src/memu/hosts/openclaw/BRIDGING_TASK.md +108 -0
  41. memu_cli-0.3.0/src/memu/hosts/openclaw/INSTALL.md +129 -0
  42. memu_cli-0.3.0/src/memu/hosts/openclaw/__init__.py +11 -0
  43. memu_cli-0.3.0/src/memu/hosts/openclaw/cli.py +47 -0
  44. memu_cli-0.3.0/src/memu/hosts/openclaw/sessions.py +77 -0
  45. memu_cli-0.3.0/tests/test_host_generic.py +144 -0
  46. {memu_cli-0.2.0 → memu_cli-0.3.0}/tests/test_host_instruction.py +32 -16
  47. memu_cli-0.3.0/tests/test_host_sessions.py +205 -0
  48. {memu_cli-0.2.0 → memu_cli-0.3.0}/uv.lock +1 -1
  49. memu_cli-0.2.0/src/memu/hosts/codex/cli.py +0 -167
  50. {memu_cli-0.2.0 → memu_cli-0.3.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  51. {memu_cli-0.2.0 → memu_cli-0.3.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  52. {memu_cli-0.2.0 → memu_cli-0.3.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  53. {memu_cli-0.2.0 → memu_cli-0.3.0}/.github/ISSUE_TEMPLATE/hackathon_task.yml +0 -0
  54. {memu_cli-0.2.0 → memu_cli-0.3.0}/.github/ISSUE_TEMPLATE/improvement_suggestion.yml +0 -0
  55. {memu_cli-0.2.0 → memu_cli-0.3.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  56. {memu_cli-0.2.0 → memu_cli-0.3.0}/.github/workflows/build.yml +0 -0
  57. {memu_cli-0.2.0 → memu_cli-0.3.0}/.github/workflows/pr-title.yml +0 -0
  58. {memu_cli-0.2.0 → memu_cli-0.3.0}/.gitignore +0 -0
  59. {memu_cli-0.2.0 → memu_cli-0.3.0}/.pre-commit-config.yaml +0 -0
  60. {memu_cli-0.2.0 → memu_cli-0.3.0}/.python-version +0 -0
  61. {memu_cli-0.2.0 → memu_cli-0.3.0}/AGENTS.md +0 -0
  62. {memu_cli-0.2.0 → memu_cli-0.3.0}/CHANGELOG.md +0 -0
  63. {memu_cli-0.2.0 → memu_cli-0.3.0}/CONTRIBUTING.md +0 -0
  64. {memu_cli-0.2.0 → memu_cli-0.3.0}/Cargo.lock +0 -0
  65. {memu_cli-0.2.0 → memu_cli-0.3.0}/Cargo.toml +0 -0
  66. {memu_cli-0.2.0 → memu_cli-0.3.0}/LICENSE.txt +0 -0
  67. {memu_cli-0.2.0 → memu_cli-0.3.0}/MANIFEST.in +0 -0
  68. {memu_cli-0.2.0 → memu_cli-0.3.0}/Makefile +0 -0
  69. {memu_cli-0.2.0 → memu_cli-0.3.0}/assets/banner.png +0 -0
  70. {memu_cli-0.2.0 → memu_cli-0.3.0}/assets/benchmark.png +0 -0
  71. {memu_cli-0.2.0 → memu_cli-0.3.0}/assets/memUbot.png +0 -0
  72. {memu_cli-0.2.0 → memu_cli-0.3.0}/assets/memorize.png +0 -0
  73. {memu_cli-0.2.0 → memu_cli-0.3.0}/assets/partners/Clawdchat.png +0 -0
  74. {memu_cli-0.2.0 → memu_cli-0.3.0}/assets/partners/LazyLLM.png +0 -0
  75. {memu_cli-0.2.0 → memu_cli-0.3.0}/assets/partners/buddie.png +0 -0
  76. {memu_cli-0.2.0 → memu_cli-0.3.0}/assets/partners/bytebase.png +0 -0
  77. {memu_cli-0.2.0 → memu_cli-0.3.0}/assets/partners/jazz.png +0 -0
  78. {memu_cli-0.2.0 → memu_cli-0.3.0}/assets/partners/openagents.png +0 -0
  79. {memu_cli-0.2.0 → memu_cli-0.3.0}/assets/partners/xroute.png +0 -0
  80. {memu_cli-0.2.0 → memu_cli-0.3.0}/assets/qrcode.png +0 -0
  81. {memu_cli-0.2.0 → memu_cli-0.3.0}/assets/retrieve.png +0 -0
  82. {memu_cli-0.2.0 → memu_cli-0.3.0}/assets/star.gif +0 -0
  83. {memu_cli-0.2.0 → memu_cli-0.3.0}/assets/structure-v2.png +0 -0
  84. {memu_cli-0.2.0 → memu_cli-0.3.0}/assets/structure.png +0 -0
  85. {memu_cli-0.2.0 → memu_cli-0.3.0}/assets/usecase/ai_companion-0000.jpg +0 -0
  86. {memu_cli-0.2.0 → memu_cli-0.3.0}/assets/usecase/ai_creation-0000.jpg +0 -0
  87. {memu_cli-0.2.0 → memu_cli-0.3.0}/assets/usecase/ai_edu-0000.jpg +0 -0
  88. {memu_cli-0.2.0 → memu_cli-0.3.0}/assets/usecase/ai_ip-0000.png +0 -0
  89. {memu_cli-0.2.0 → memu_cli-0.3.0}/assets/usecase/ai_robot-0000.jpg +0 -0
  90. {memu_cli-0.2.0 → memu_cli-0.3.0}/assets/usecase/ai_role_play-0000.jpg +0 -0
  91. {memu_cli-0.2.0 → memu_cli-0.3.0}/assets/usecase/ai_therapy-0000.jpg +0 -0
  92. {memu_cli-0.2.0 → memu_cli-0.3.0}/docs/adr/0001-workflow-pipeline-architecture.md +0 -0
  93. {memu_cli-0.2.0 → memu_cli-0.3.0}/docs/adr/0002-pluggable-storage-and-vector-strategy.md +0 -0
  94. {memu_cli-0.2.0 → memu_cli-0.3.0}/docs/adr/0003-user-scope-in-data-model.md +0 -0
  95. {memu_cli-0.2.0 → memu_cli-0.3.0}/docs/adr/0004-workspace-memorize-and-memory-file-system.md +0 -0
  96. {memu_cli-0.2.0 → memu_cli-0.3.0}/docs/adr/0005-dedicated-embedding-package.md +0 -0
  97. {memu_cli-0.2.0 → memu_cli-0.3.0}/docs/adr/0006-from-memory-item-category-to-tracked-workspace-memorization.md +0 -0
  98. {memu_cli-0.2.0 → memu_cli-0.3.0}/docs/adr/0007-three-independent-memory-lines-wiki-graph.md +0 -0
  99. {memu_cli-0.2.0 → memu_cli-0.3.0}/docs/adr/0008-two-integration-surfaces-hooks-and-api.md +0 -0
  100. {memu_cli-0.2.0 → memu_cli-0.3.0}/docs/sqlite.md +0 -0
  101. {memu_cli-0.2.0 → memu_cli-0.3.0}/scripts/db.py +0 -0
  102. {memu_cli-0.2.0 → memu_cli-0.3.0}/setup.cfg +0 -0
  103. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/lib.rs +0 -0
  104. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/__init__.py +0 -0
  105. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/__main__.py +0 -0
  106. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/_core.pyi +0 -0
  107. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/app/__init__.py +0 -0
  108. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/app/agentic.py +0 -0
  109. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/app/client_pool.py +0 -0
  110. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/app/service.py +0 -0
  111. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/app/settings.py +0 -0
  112. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/cli.py +0 -0
  113. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/__init__.py +0 -0
  114. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/factory.py +0 -0
  115. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/inmemory/__init__.py +0 -0
  116. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/inmemory/models.py +0 -0
  117. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/inmemory/repo.py +0 -0
  118. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/inmemory/repositories/__init__.py +0 -0
  119. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/inmemory/repositories/filter.py +0 -0
  120. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/inmemory/repositories/recall_file_repo.py +0 -0
  121. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/inmemory/repositories/recall_file_resource_repo.py +0 -0
  122. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/inmemory/repositories/recall_file_segment_repo.py +0 -0
  123. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/inmemory/repositories/resource_repo.py +0 -0
  124. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/inmemory/state.py +0 -0
  125. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/inmemory/vector.py +0 -0
  126. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/interfaces.py +0 -0
  127. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/models.py +0 -0
  128. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/postgres/__init__.py +0 -0
  129. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/postgres/migration.py +0 -0
  130. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/postgres/migrations/__init__.py +0 -0
  131. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/postgres/migrations/env.py +0 -0
  132. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/postgres/migrations/script.py.mako +0 -0
  133. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/postgres/migrations/versions/20260703_0001_initial_schema.py +0 -0
  134. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/postgres/models.py +0 -0
  135. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/postgres/postgres.py +0 -0
  136. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/postgres/repositories/__init__.py +0 -0
  137. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/postgres/repositories/base.py +0 -0
  138. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/postgres/repositories/recall_file_repo.py +0 -0
  139. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/postgres/repositories/recall_file_resource_repo.py +0 -0
  140. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/postgres/repositories/recall_file_segment_repo.py +0 -0
  141. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/postgres/repositories/resource_repo.py +0 -0
  142. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/postgres/schema.py +0 -0
  143. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/postgres/session.py +0 -0
  144. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/repositories/__init__.py +0 -0
  145. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/repositories/recall_file.py +0 -0
  146. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/repositories/recall_file_resource.py +0 -0
  147. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/repositories/recall_file_segment.py +0 -0
  148. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/repositories/resource.py +0 -0
  149. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/sqlite/__init__.py +0 -0
  150. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/sqlite/models.py +0 -0
  151. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/sqlite/repositories/__init__.py +0 -0
  152. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/sqlite/repositories/base.py +0 -0
  153. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/sqlite/repositories/recall_file_repo.py +0 -0
  154. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/sqlite/repositories/recall_file_resource_repo.py +0 -0
  155. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/sqlite/repositories/recall_file_segment_repo.py +0 -0
  156. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/sqlite/repositories/resource_repo.py +0 -0
  157. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/sqlite/schema.py +0 -0
  158. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/sqlite/session.py +0 -0
  159. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/sqlite/sqlite.py +0 -0
  160. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/state.py +0 -0
  161. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/embedding/__init__.py +0 -0
  162. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/embedding/backends/__init__.py +0 -0
  163. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/embedding/backends/base.py +0 -0
  164. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/embedding/backends/doubao.py +0 -0
  165. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/embedding/backends/jina.py +0 -0
  166. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/embedding/backends/openai.py +0 -0
  167. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/embedding/backends/openrouter.py +0 -0
  168. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/embedding/backends/voyage.py +0 -0
  169. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/embedding/base.py +0 -0
  170. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/embedding/defaults.py +0 -0
  171. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/embedding/gateway.py +0 -0
  172. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/embedding/http_client.py +0 -0
  173. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/embedding/openai_sdk.py +0 -0
  174. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/env.py +0 -0
  175. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/hosts/__init__.py +0 -0
  176. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/hosts/bridging/__init__.py +0 -0
  177. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/hosts/bridging/instructions.py +0 -0
  178. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/hosts/bridging/layout.py +0 -0
  179. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/hosts/bridging/manifest.py +0 -0
  180. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/hosts/bridging/pipeline.py +0 -0
  181. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/hosts/bridging/recall_files.py +0 -0
  182. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/hosts/bridging/resources.py +0 -0
  183. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/hosts/bridging/transcripts.py +0 -0
  184. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/hosts/codex/BRIDGING_TASK.md +0 -0
  185. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/hosts/codex/__init__.py +0 -0
  186. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/hosts/codex/sessions.py +0 -0
  187. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/hosts/retrieval.py +0 -0
  188. {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/vector.py +0 -0
  189. {memu_cli-0.2.0 → memu_cli-0.3.0}/tests/__init__.py +0 -0
  190. {memu_cli-0.2.0 → memu_cli-0.3.0}/tests/rust_entry_test.py +0 -0
  191. {memu_cli-0.2.0 → memu_cli-0.3.0}/tests/test_agentic.py +0 -0
  192. {memu_cli-0.2.0 → memu_cli-0.3.0}/tests/test_cli.py +0 -0
  193. {memu_cli-0.2.0 → memu_cli-0.3.0}/tests/test_embedding.py +0 -0
  194. {memu_cli-0.2.0 → memu_cli-0.3.0}/tests/test_postgres_migration_config.py +0 -0
  195. {memu_cli-0.2.0 → memu_cli-0.3.0}/tests/test_vector.py +0 -0
@@ -1,10 +1,9 @@
1
- # Publishes the engine snapshot to PyPI under the distribution name `memu-cli`.
1
+ # Publishes the engine to PyPI as `memu-cli` — the one and only distribution.
2
2
  #
3
- # `memu-cli` is the CLI release channel: it ships the same `memu` module and
4
- # entry points as `memu-py`, but versions independently of the release-please
5
- # train so the npm launcher and docs can point at a stable install target.
6
- # The rename happens at build time only — pyproject.toml in the repo always
7
- # says `memu-py`.
3
+ # `memu-cli` versions independently of the release-please train (which still
4
+ # cuts GitHub releases and the changelog), so the npm launcher and docs can
5
+ # point at a stable install target; the version is set at build time from the
6
+ # workflow input.
8
7
  #
9
8
  # First-time setup: add a trusted publisher on PyPI for project `memu-cli`
10
9
  # (workflow: publish-memu-cli.yml, environment: pypi).
@@ -13,7 +12,7 @@ on:
13
12
  workflow_dispatch:
14
13
  inputs:
15
14
  version:
16
- description: "memu-cli version to publish (independent of memu-py, e.g. 0.1.1)"
15
+ description: "memu-cli version to publish (e.g. 0.2.1)"
17
16
  required: true
18
17
  type: string
19
18
 
@@ -57,14 +56,12 @@ jobs:
57
56
 
58
57
  # No $ anchors: Windows runners check out with CRLF line endings,
59
58
  # where a trailing \r sits between the closing quote and the newline.
60
- - name: Rename distribution to memu-cli
59
+ - name: Set memu-cli version
61
60
  shell: bash
62
61
  run: |
63
- perl -pi -e 's/^name = "memu-py"/name = "memu-cli"/' pyproject.toml
64
62
  perl -pi -e 's/^version = "[^"]*"/version = "${{ inputs.version }}"/ if $. < 10' pyproject.toml
65
- perl -pi -e 's/^description = "[^"]*"/description = "CLI distribution channel for memU (same engine as memu-py). Personal memory as files."/' pyproject.toml
66
- grep -q '^name = "memu-cli"' pyproject.toml || { echo "::error::rename to memu-cli did not apply"; exit 1; }
67
- grep -E '^(name|version|description) = ' pyproject.toml | head -3
63
+ grep -q '^name = "memu-cli"' pyproject.toml || { echo "::error::pyproject is not memu-cli"; exit 1; }
64
+ grep -E '^(name|version) = ' pyproject.toml | head -2
68
65
 
69
66
  - name: Install uv
70
67
  uses: astral-sh/setup-uv@v7
@@ -108,13 +105,11 @@ jobs:
108
105
  steps:
109
106
  - uses: actions/checkout@v6
110
107
 
111
- - name: Rename distribution to memu-cli
108
+ - name: Set memu-cli version
112
109
  shell: bash
113
110
  run: |
114
- perl -pi -e 's/^name = "memu-py"/name = "memu-cli"/' pyproject.toml
115
111
  perl -pi -e 's/^version = "[^"]*"/version = "${{ inputs.version }}"/ if $. < 10' pyproject.toml
116
- perl -pi -e 's/^description = "[^"]*"/description = "CLI distribution channel for memU (same engine as memu-py). Personal memory as files."/' pyproject.toml
117
- grep -q '^name = "memu-cli"' pyproject.toml || { echo "::error::rename to memu-cli did not apply"; exit 1; }
112
+ grep -q '^name = "memu-cli"' pyproject.toml || { echo "::error::pyproject is not memu-cli"; exit 1; }
118
113
 
119
114
  - name: Install uv
120
115
  uses: astral-sh/setup-uv@v7
@@ -120,6 +120,9 @@ jobs:
120
120
  path: dist/*.tar.gz
121
121
  if-no-files-found: error
122
122
 
123
+ # Release artifacts go to the GitHub release only. PyPI publishing happens
124
+ # exclusively through publish-memu-cli.yml (the `memu-cli` distribution,
125
+ # versioned independently of this release train).
123
126
  publish:
124
127
  name: publish release artifacts
125
128
  runs-on: ubuntu-latest
@@ -128,9 +131,7 @@ jobs:
128
131
  - build-wheels
129
132
  - build-sdist
130
133
  if: ${{ needs.release-please.outputs.releases_created == 'true' && needs.release-please.outputs.tag_name != '' }}
131
- environment: pypi
132
134
  permissions:
133
- id-token: write
134
135
  contents: write
135
136
  steps:
136
137
  - name: Download wheel artifacts
@@ -153,8 +154,3 @@ jobs:
153
154
  file: dist/*
154
155
  tag: ${{ needs.release-please.outputs.tag_name }}
155
156
  file_glob: true
156
-
157
- - name: Publish to PyPI
158
- uses: pypa/gh-action-pypi-publish@release/v1
159
- with:
160
- packages-dir: dist/
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: memu-cli
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: Operating System :: OS Independent
@@ -17,7 +17,7 @@ Requires-Dist: pgvector>=0.3.4 ; extra == 'postgres'
17
17
  Requires-Dist: sqlalchemy[postgresql-psycopgbinary]>=2.0.36 ; extra == 'postgres'
18
18
  Provides-Extra: postgres
19
19
  License-File: LICENSE.txt
20
- Summary: CLI distribution channel for memU (same engine as memu-py). Personal memory as files.
20
+ Summary: Personal memory as files fast retrieval, higher accuracy, lower cost.
21
21
  Keywords: agent,agentic,agent-harness,harness,loop-engineering,context-engineering,context-window,memory,personal-information,workspace,retrieval,llm
22
22
  Author-email: MemU Team <contact@nevamind.ai>
23
23
  Requires-Python: >=3.13
@@ -50,6 +50,12 @@ Project-URL: Homepage, https://github.com/NevaMind-AI/MemU
50
50
 
51
51
  memU is a 500-line memory system for AI agents. Agents write what's worth keeping as Markdown; memU stores it, embeds it, and retrieves ranked context in a single call — embeddings are the only model calls it makes. The entire memory logic lives in [`agentic.py`](src/memu/app/agentic.py) + [`service.py`](src/memu/app/service.py); everything else is pluggable storage and embedding transport.
52
52
 
53
+ **Installation is agent-driven.** The guides are written for the agent, not for you. One message is the whole setup — tell your agent:
54
+
55
+ > Read https://raw.githubusercontent.com/NevaMind-AI/MemU/main/SKILL.md and follow it to install memU.
56
+
57
+ It works for Codex, Claude Code, Cursor, OpenClaw, Hermes — and any other agent, via detection. Details in [Host adapters](#host-adapters-memory-for-desktop-coding-agents).
58
+
53
59
  ## Quick start
54
60
 
55
61
  ```python
@@ -123,26 +129,31 @@ Segments are reconciled on every commit: lines that disappeared are deleted, onl
123
129
 
124
130
  There is no intention routing, sufficiency checking, or summarization — one embedding call in, ranked context out.
125
131
 
126
- ## Host adapter: memory for desktop coding agents
132
+ ## Host adapters: memory for desktop coding agents
127
133
 
128
- `memu-codex` runs memU as a sidecar to Codex-style agents (ADR 0008/0009). It binds two seams:
134
+ memU runs as a sidecar to a desktop agent (ADR 0008/0009/0010), one binary per host. Each binds two seams:
129
135
 
130
136
  - **record** — a scheduled bridging task slices new session logs into self-contained job files; the agent itself distills them into memory/skill Markdown; `commit` submits whatever the agent left on disk back through `commit_results`.
131
- - **inject** — a standing instruction in the host's global instruction file (`~/.codex/AGENTS.md`) tells the agent to run `memu-codex retrieve` (→ `progressive_retrieve`) before answering.
137
+ - **inject** — a standing instruction in the host's instruction file tells the agent to run `<binary> retrieve` (→ `progressive_retrieve`) before answering.
132
138
 
133
- **Installation is agent-driven.** The install guide is written for the agent, not for you — install the package, then hand the guide to your agent and let it do the rest (configure the store, register the scheduled bridging task, patch the instruction file each step ends with a verify gate):
139
+ | Host | Binary | Session log it mines | Instruction file it patches |
140
+ | --- | --- | --- | --- |
141
+ | Codex | `memu-codex` | `~/.codex/sessions/**/*.jsonl` | `~/.codex/AGENTS.md` |
142
+ | Claude Code | `memu-claude-code` | `~/.claude/projects/<project>/<session>.jsonl` | `~/.claude/CLAUDE.md` |
143
+ | Cursor (Agent/CLI) | `memu-cursor` | `~/.cursor/projects/<project>/agent-transcripts/**.jsonl` | `./AGENTS.md` (per project) |
144
+ | OpenClaw | `memu-openclaw` | `~/.openclaw/agents/<agentId>/sessions/*.jsonl` | `~/.openclaw/workspace/AGENTS.md` |
145
+ | Hermes Agent | `memu-hermes` | `~/.hermes/state.db` (SQLite, read-only) | `~/.hermes/SOUL.md` |
146
+ | **any other agent** | `memu-agent` | found by `memu-agent detect` (JSONL dialect sniffed) | found by `detect` (AGENTS.md / CLAUDE.md / SOUL.md / …) |
134
147
 
135
- ```bash
136
- pip install memu-cli # puts memu + memu-codex on PATH
137
- ```
148
+ For agents without a dedicated binary, `memu-agent detect` probes the machine and reports per agent whether **memorization** works (a recognizable session log exists) and whether **retrieval** works (an instruction file exists to patch) — then the same verbs run against what it found.
138
149
 
139
- Then tell your agent:
150
+ All hosts share one store and one embedding space via `~/.memu/config.env` — what one host's sessions taught memU, another host retrieves.
140
151
 
141
- > Run `memu-codex docs install`, read the guide it prints, and follow it to install memU.
152
+ Installation is the one-message setup at the top of this README. [SKILL.md](SKILL.md) is the routing skill it hands your agent: install the package, identify which host you are (falling back to `memu-agent detect` for anything without a dedicated adapter), print that host's packaged install guide (`<binary> docs install`), and follow it configure the store, register the scheduled bridging task, patch the instruction file, each step behind a verify gate — then report which seams (memorization / retrieval) are now active.
142
153
 
143
- Afterwards `memu-codex doctor` proves the whole loop resolves: config, store, and a live retrieval.
154
+ Afterwards `<binary> doctor` proves the whole loop resolves: config, store, and a live retrieval.
144
155
 
145
- Adding another host means implementing one `TranscriptSource` (where its session logs live, how its records are shaped) plus a thin CLI — the pipeline and instruction text are shared.
156
+ Adding another host means implementing one `TranscriptSource` (where its session logs live, how its records are shaped) plus a `HostSpec`-sized CLI — the pipeline, verbs, and instruction text are shared (ADR 0010).
146
157
 
147
158
  ## Installation
148
159
 
@@ -22,6 +22,12 @@
22
22
 
23
23
  memU is a 500-line memory system for AI agents. Agents write what's worth keeping as Markdown; memU stores it, embeds it, and retrieves ranked context in a single call — embeddings are the only model calls it makes. The entire memory logic lives in [`agentic.py`](src/memu/app/agentic.py) + [`service.py`](src/memu/app/service.py); everything else is pluggable storage and embedding transport.
24
24
 
25
+ **Installation is agent-driven.** The guides are written for the agent, not for you. One message is the whole setup — tell your agent:
26
+
27
+ > Read https://raw.githubusercontent.com/NevaMind-AI/MemU/main/SKILL.md and follow it to install memU.
28
+
29
+ It works for Codex, Claude Code, Cursor, OpenClaw, Hermes — and any other agent, via detection. Details in [Host adapters](#host-adapters-memory-for-desktop-coding-agents).
30
+
25
31
  ## Quick start
26
32
 
27
33
  ```python
@@ -95,26 +101,31 @@ Segments are reconciled on every commit: lines that disappeared are deleted, onl
95
101
 
96
102
  There is no intention routing, sufficiency checking, or summarization — one embedding call in, ranked context out.
97
103
 
98
- ## Host adapter: memory for desktop coding agents
104
+ ## Host adapters: memory for desktop coding agents
99
105
 
100
- `memu-codex` runs memU as a sidecar to Codex-style agents (ADR 0008/0009). It binds two seams:
106
+ memU runs as a sidecar to a desktop agent (ADR 0008/0009/0010), one binary per host. Each binds two seams:
101
107
 
102
108
  - **record** — a scheduled bridging task slices new session logs into self-contained job files; the agent itself distills them into memory/skill Markdown; `commit` submits whatever the agent left on disk back through `commit_results`.
103
- - **inject** — a standing instruction in the host's global instruction file (`~/.codex/AGENTS.md`) tells the agent to run `memu-codex retrieve` (→ `progressive_retrieve`) before answering.
109
+ - **inject** — a standing instruction in the host's instruction file tells the agent to run `<binary> retrieve` (→ `progressive_retrieve`) before answering.
104
110
 
105
- **Installation is agent-driven.** The install guide is written for the agent, not for you — install the package, then hand the guide to your agent and let it do the rest (configure the store, register the scheduled bridging task, patch the instruction file each step ends with a verify gate):
111
+ | Host | Binary | Session log it mines | Instruction file it patches |
112
+ | --- | --- | --- | --- |
113
+ | Codex | `memu-codex` | `~/.codex/sessions/**/*.jsonl` | `~/.codex/AGENTS.md` |
114
+ | Claude Code | `memu-claude-code` | `~/.claude/projects/<project>/<session>.jsonl` | `~/.claude/CLAUDE.md` |
115
+ | Cursor (Agent/CLI) | `memu-cursor` | `~/.cursor/projects/<project>/agent-transcripts/**.jsonl` | `./AGENTS.md` (per project) |
116
+ | OpenClaw | `memu-openclaw` | `~/.openclaw/agents/<agentId>/sessions/*.jsonl` | `~/.openclaw/workspace/AGENTS.md` |
117
+ | Hermes Agent | `memu-hermes` | `~/.hermes/state.db` (SQLite, read-only) | `~/.hermes/SOUL.md` |
118
+ | **any other agent** | `memu-agent` | found by `memu-agent detect` (JSONL dialect sniffed) | found by `detect` (AGENTS.md / CLAUDE.md / SOUL.md / …) |
106
119
 
107
- ```bash
108
- pip install memu-cli # puts memu + memu-codex on PATH
109
- ```
120
+ For agents without a dedicated binary, `memu-agent detect` probes the machine and reports per agent whether **memorization** works (a recognizable session log exists) and whether **retrieval** works (an instruction file exists to patch) — then the same verbs run against what it found.
110
121
 
111
- Then tell your agent:
122
+ All hosts share one store and one embedding space via `~/.memu/config.env` — what one host's sessions taught memU, another host retrieves.
112
123
 
113
- > Run `memu-codex docs install`, read the guide it prints, and follow it to install memU.
124
+ Installation is the one-message setup at the top of this README. [SKILL.md](SKILL.md) is the routing skill it hands your agent: install the package, identify which host you are (falling back to `memu-agent detect` for anything without a dedicated adapter), print that host's packaged install guide (`<binary> docs install`), and follow it configure the store, register the scheduled bridging task, patch the instruction file, each step behind a verify gate — then report which seams (memorization / retrieval) are now active.
114
125
 
115
- Afterwards `memu-codex doctor` proves the whole loop resolves: config, store, and a live retrieval.
126
+ Afterwards `<binary> doctor` proves the whole loop resolves: config, store, and a live retrieval.
116
127
 
117
- Adding another host means implementing one `TranscriptSource` (where its session logs live, how its records are shaped) plus a thin CLI — the pipeline and instruction text are shared.
128
+ Adding another host means implementing one `TranscriptSource` (where its session logs live, how its records are shaped) plus a `HostSpec`-sized CLI — the pipeline, verbs, and instruction text are shared (ADR 0010).
118
129
 
119
130
  ## Installation
120
131
 
@@ -0,0 +1,78 @@
1
+ ---
2
+ name: install-memu
3
+ description: Install memU for whatever agent you are — identify your host, print its packaged install guide, and follow it to wire both seams (record and inject). Use when the user asks to install, set up, or integrate memU.
4
+ ---
5
+
6
+ # Install memU
7
+
8
+ > **Audience: the agent.** A user has pointed you at this file ("read SKILL.md
9
+ > and follow it to install memU"). This skill does not contain the install
10
+ > steps — it routes you to the right guide, which ships inside the memU package
11
+ > and is always in sync with the installed code. Do not install from memory or
12
+ > from blog posts; print the guide and follow it to the letter.
13
+
14
+ memU integrates with a host agent through two seams: **record** (a scheduled
15
+ bridging task mines your session log into durable memory) and **inject** (a
16
+ standing instruction in your instruction file makes you retrieve before
17
+ answering). Each supported host has its own adapter binary carrying its own
18
+ install guide. Your job here is three steps: install the package, pick your
19
+ binary, print and follow its guide.
20
+
21
+ ## Step 1 — install the package
22
+
23
+ ```
24
+ pip install memu-cli
25
+ ```
26
+
27
+ This puts `memu` and every host-adapter binary on `PATH`. If `pip` is not the
28
+ right tool for this machine (managed Python, uv-only), use the equivalent —
29
+ what matters is that the binaries below resolve from a bare, non-interactive
30
+ shell.
31
+
32
+ ## Step 2 — pick your host binary
33
+
34
+ Identify **which agent you are** (not which agents are installed — the one
35
+ executing this skill):
36
+
37
+ | You are | Your binary |
38
+ | --- | --- |
39
+ | Codex | `memu-codex` |
40
+ | Claude Code | `memu-claude-code` |
41
+ | Cursor (Agent/CLI) | `memu-cursor` |
42
+ | OpenClaw | `memu-openclaw` |
43
+ | Hermes Agent | `memu-hermes` |
44
+ | anything else | `memu-agent` |
45
+
46
+ Unsure, or not in the table? You are `memu-agent`. Run:
47
+
48
+ ```
49
+ memu-agent detect
50
+ ```
51
+
52
+ It probes this machine and reports, per agent, whether **memorization** works
53
+ (a recognizable session log exists) and whether **retrieval** works (an
54
+ instruction file exists to patch) — and it will redirect you to a dedicated
55
+ binary if your host turns out to have one.
56
+
57
+ ## Step 3 — print your guide and follow it
58
+
59
+ ```
60
+ <your-binary> docs install
61
+ ```
62
+
63
+ Read what it prints, top to bottom, and follow it exactly. Every guide has the
64
+ same shape — configure the store once in `~/.memu/config.env`, register the
65
+ scheduled bridging task (record), patch your instruction file (inject) — and
66
+ every part ends with a **verify gate**; do not proceed past a failing one.
67
+
68
+ Two rules that hold for every host:
69
+
70
+ - **One store.** If `~/.memu/config.env` already exists (another agent on this
71
+ machine is already integrated), reuse it as is. A second store would split
72
+ the embedding space and both installs would silently retrieve nothing from
73
+ each other.
74
+ - **Report the outcome.** When done, tell the user which seams are now active —
75
+ memorization, retrieval, or both — and where (the session log being mined,
76
+ the instruction file patched). For `memu-agent`, the detect report decides
77
+ this; a retrieval-only integration is a valid outcome to report, not a
78
+ failure to hide.
@@ -48,7 +48,7 @@ silently returns nothing.
48
48
 
49
49
  ### 1. Distribute via pip; do not ship a parallel npm package
50
50
 
51
- memU is installed as a Python package (`pip install memu-py`), exposing two console entrypoints:
51
+ memU is installed as a Python package (`pip install memu-cli`), exposing two console entrypoints:
52
52
  `memu` (the library's own surface) and `memu-codex` (the host adapter — see Decision 2). No npm
53
53
  package is built for this integration.
54
54
 
@@ -0,0 +1,167 @@
1
+ ADR 0010: Multi-Host Adapters — Claude Code, Cursor, OpenClaw, and Hermes
2
+
3
+ - Status: Accepted
4
+ - Date: 2026-07-16
5
+ - Builds on: ADR 0008 (two integration surfaces), ADR 0009 (packaging, CLI seam, one config
6
+ loader)
7
+ - Scope: adding four host adapters beyond Codex, and the two pieces of shared structure that
8
+ shipping a second host forced: a common CLI builder, and per-host working trees. It does
9
+ **not** revisit the pipeline, the seams, or the config decisions of 0008/0009.
10
+
11
+ ## Context
12
+
13
+ ADR 0009 closed with a claim and an IOU. The claim: "a second host is a `TranscriptSource`
14
+ and a CLI, not a forked pipeline." The IOU: the working directories (`~/.memu/jobs`,
15
+ `~/.memu/sessions`, the touched-file log) are shared and wiped per run — "two hosts' bridging
16
+ tasks running at the same time would race. Fine while Codex is the only host; must be settled
17
+ before the second one ships."
18
+
19
+ Four hosts now ship at once: **Claude Code**, **Cursor**, **OpenClaw**, and **Hermes Agent**.
20
+ Each was located empirically (inspecting a live machine and, for OpenClaw and Hermes, the
21
+ hosts' own source) rather than from documentation alone:
22
+
23
+ | Host | Session log | Container | Record shape |
24
+ | --- | --- | --- | --- |
25
+ | Codex | `~/.codex/sessions/**/*.jsonl` | JSONL per session | `{timestamp, payload: {type, role, …}}`; `type: message` (user/assistant) vs `function_call`/`function_call_output` |
26
+ | Claude Code | `~/.claude/projects/<escaped-cwd>/<session-uuid>.jsonl` (subagent transcripts in per-session subdirs) | JSONL per session | `{type: user\|assistant, timestamp, message: {role, content}}`, one content block per record: `text` / `tool_use` / `tool_result` / `thinking`; plus non-message noise types (`queue-operation`, `attachment`, `system`, `pr-link`, `last-prompt`) and `isMeta` user records |
27
+ | Cursor (Agent/CLI) | `~/.cursor/projects/<escaped-cwd>/agent-transcripts/<id>/<id>.jsonl` | JSONL per session | `{role, message: {content: [blocks]}}`; `text` and `tool_use` blocks, often in one record; **no timestamps**. The IDE's Composer chats live in the editor's `state.vscdb` SQLite and are out of scope |
28
+ | OpenClaw | `~/.openclaw/agents/<agentId>/sessions/<sessionId>.jsonl` (`-topic-<threadId>` suffix for topic sessions; `sessions.json` index alongside; root moves with `OPENCLAW_STATE_DIR`) | JSONL per session | parent-linked entry tree: `{type: session\|message\|compaction\|custom…, id, parentId, timestamp, message: {role, content}}`; roles `user`/`assistant`/`toolResult` |
29
+ | Hermes Agent | `~/.hermes/state.db` (moves with `HERMES_HOME`; `~/.hermes/sessions/saved/` holds only manual snapshots) | **SQLite**, WAL mode | `sessions` + `messages` tables; OpenAI-shaped rows: `role` (`system`/`user`/`assistant`/`tool`), `content`, `tool_calls`, `tool_call_id`, epoch-seconds `timestamp` |
30
+
31
+ And the inject seam's landing file per host:
32
+
33
+ | Host | Instruction file | Why |
34
+ | --- | --- | --- |
35
+ | Codex | `~/.codex/AGENTS.md` | global, loaded every session (ADR 0009) |
36
+ | Claude Code | `~/.claude/CLAUDE.md` | the global memory file, loaded in every project |
37
+ | Cursor | `./AGENTS.md` (per project) | Cursor's CLI honors no global instruction *file*; User Rules are IDE settings out of a CLI's reach |
38
+ | OpenClaw | `~/.openclaw/workspace/AGENTS.md` | the workspace file loaded at the start of every session |
39
+ | Hermes | `~/.hermes/SOUL.md` | the one file loaded from `HERMES_HOME` regardless of cwd; project files (`.hermes.md`, `AGENTS.md`) would miss sessions started elsewhere |
40
+
41
+ Two of the four break assumptions Codex allowed:
42
+
43
+ - **Hermes's log is not files.** The `TranscriptSource` defaults (rglob, line reads, string
44
+ timestamps) assume JSONL-on-disk. 0009's seam anticipated this ("a host with a different
45
+ container overrides `discover`, `read_records`, `timestamp`"), but no host had exercised it.
46
+ - **Claude Code's roles lie.** A tool result is logged as a *user*-typed record. Any
47
+ classification keyed on role alone would put tool output in the conversation transcript the
48
+ memory job reads.
49
+
50
+ ## Decision
51
+
52
+ ### 1. The host CLI is built from a declaration, not copied
53
+
54
+ Five binaries share one verb set — `retrieve`, `install-instruction`, `prepare`, `commit`,
55
+ `verify-resources`, `doctor`, `docs` — because the behavior behind every verb is host-agnostic.
56
+ So the parser and handlers move to `memu.hosts.host_cli`, built from a `HostSpec`: the host id,
57
+ the session-log default, the instruction-file default, and the docs package. A host's `cli.py`
58
+ is now the spec plus `main`, ~40 lines; `memu-codex` is rebuilt on the same spec with byte-
59
+ identical behavior.
60
+
61
+ The standing-instruction text (ADR 0009's managed block) is likewise parameterized on the host
62
+ binary rather than hardcoding `memu-codex`; each host's block names its own `retrieve`, and the
63
+ per-binary begin-marker means two hosts pointed at one file manage two independent blocks.
64
+ Codex's rendered block is unchanged, so already-installed markers still match and upgrade in
65
+ place.
66
+
67
+ What stays per host is exactly what 0009 predicted — a `TranscriptSource` — plus the two paths
68
+ (session log, instruction file) and the packaged guides. Cursor's `discover` is narrowed to
69
+ `*/agent-transcripts/**/*.jsonl` (the project dirs also hold canvases and terminal logs);
70
+ Hermes overrides the container seam wholesale: sessions are *virtual paths* keyed by session
71
+ id, `read_records` serializes message rows to JSON lines ordered by insertion id, and
72
+ `discover` orders by last activity so the manifest's early-stop stays sound. The database is
73
+ opened **read-only** — the bridging task must never contend for Hermes's WAL write lock. The
74
+ line-count cursor carries over untouched: message rows are append-only per session, so "lines
75
+ seen" is "rows seen."
76
+
77
+ ### 2. Working trees are per host; the store stays shared
78
+
79
+ 0009's open issue is settled by removing the sharing, not by locking: every host's `Layout`
80
+ gets its own base directory, `~/.memu/hosts/<host>/`, holding its jobs, sliced sessions,
81
+ mirrors, manifests, and touched-file log. Concurrent bridging runs of different hosts touch
82
+ disjoint trees. **Codex keeps `~/.memu`**: its job-file paths are baked into users' already-
83
+ scheduled task prompts (the exact fragility 0009's `PATH`-command decision was protecting
84
+ against — the prompt references `~/.memu/jobs/*.txt` literally), and breaking every existing
85
+ install to make five directories symmetrical is a bad trade. The asymmetry is recorded in
86
+ `HostSpec.base_dir` with a comment saying why.
87
+
88
+ What is *not* per host: `~/.memu/config.env` and the store behind `MEMU_DB`. That is the
89
+ point of the whole exercise — a session mined from Claude Code tonight is retrievable from
90
+ Cursor tomorrow. The install guides instruct an agent that finds an existing `config.env` to
91
+ reuse it as is, because a second host writing a second store/provider would silently split the
92
+ embedding space (0009's core invariant).
93
+
94
+ ### 3. Classification is by record shape, not role
95
+
96
+ Each host's `classify` encodes its log's actual semantics, pinned by tests with hand-written
97
+ records in the host's real shape:
98
+
99
+ - **Claude Code**: block type decides — `text` (or a raw-string user message) is conversation;
100
+ `tool_use`/`tool_result` are tool records regardless of the wrapping role; `thinking` blocks,
101
+ `isMeta` user records, and all non-message types are dropped.
102
+ - **Cursor**: a record with prose is conversation even when it also carries the `tool_use`
103
+ blocks it narrates; only bare tool-block records go to the tool transcript. No timestamps
104
+ exist, so the manifest records `null` and the line count alone drives incrementality.
105
+ - **OpenClaw**: `type: message` with role user/assistant is conversation, role `toolResult` is
106
+ a tool record; session headers, compaction summaries, and extension entries are dropped.
107
+ Timestamps may be ISO strings or epoch millis; both normalize.
108
+ - **Hermes**: role `tool`, and assistant rows carrying only `tool_calls`, are tool records;
109
+ user/assistant rows with content are conversation; `system` rows are dropped. Epoch-seconds
110
+ timestamps normalize to ISO.
111
+
112
+ ## What this changes
113
+
114
+ - Four new console scripts — `memu-claude-code`, `memu-cursor`, `memu-openclaw`,
115
+ `memu-hermes` — each with packaged `INSTALL.md` / `BRIDGING_TASK.md` guides printable via
116
+ `<binary> docs`, alongside the unchanged `memu-codex`.
117
+ - `memu.hosts.host_cli` (new): `HostSpec` + the shared parser/handlers. `codex/cli.py`
118
+ shrinks to its spec; its public names (`build_parser`, `AGENTS_MD`, `HOST`,
119
+ `VERIFY_COMMAND`) survive.
120
+ - `memu.hosts.instruction`: `INSTRUCTION`/`BEGIN` constants become `instruction(binary)` /
121
+ `begin(binary)` templates; `install`/`patch`/`register` take the binary.
122
+ - `memu.hosts.base.TranscriptSource` gains `exists()` (default: root is a directory) so a
123
+ SQLite-backed host can gate `prepare` on its file instead.
124
+ - New host packages: `hosts/claude_code`, `hosts/cursor`, `hosts/openclaw`, `hosts/hermes` —
125
+ each a `sessions.py`, a spec-sized `cli.py`, and the two guides.
126
+
127
+ ## Consequences
128
+
129
+ Positive:
130
+
131
+ - The 0009 claim is now demonstrated: four hosts, zero pipeline forks, and the next host is a
132
+ `classify` method, two paths, and two markdown files.
133
+ - Concurrent bridging across hosts is safe by construction (disjoint trees), with no locking
134
+ protocol to get wrong.
135
+ - One instruction text and one CLI surface to improve; all five binaries pick up fixes at once.
136
+
137
+ Negative / costs:
138
+
139
+ - Codex's `~/.memu` vs everyone else's `~/.memu/hosts/<host>` is a visible asymmetry, carried
140
+ for compatibility. A future major release could migrate Codex in.
141
+ - The recall-file mirror is written once per host per run instead of once per machine —
142
+ redundant disk writes, accepted for isolation.
143
+ - Cursor's inject seam is per project (no global file), so its instruction install is a
144
+ per-project step the guides must (and do) call out.
145
+ - Host log formats are observed, not contracted. OpenClaw already has a SQLite session target
146
+ behind a flag; if it becomes the default, that host needs the Hermes treatment. The
147
+ per-host fixture tests localize such breaks.
148
+
149
+ ## Open issues (deferred)
150
+
151
+ - **Same-host concurrency.** Two bridging runs of the *same* host still race on that host's
152
+ tree; scheduled tasks make this unlikely, and per-run lock files remain available if it
153
+ bites.
154
+ - **IDE-container hosts.** Cursor's Composer history (`state.vscdb`) and any host whose log
155
+ lives inside an editor's private state would need the SQLite treatment plus a stability
156
+ story for schema drift; not attempted.
157
+ - **Session-dir env vars.** OpenClaw (`OPENCLAW_STATE_DIR`) and Hermes (`HERMES_HOME`) can
158
+ relocate their logs; the adapters take `--session-dir` rather than reading the host's env,
159
+ keeping the contract explicit. The guides say when to pass it.
160
+
161
+ ## Related ADRs
162
+
163
+ - Builds on `docs/adr/0008-two-integration-surfaces-hooks-and-api.md` — each new host binds
164
+ the same two seams.
165
+ - Builds on `docs/adr/0009-codex-packaging-cli-and-config.md` — settles its "concurrent
166
+ hosts" open issue via per-host working trees; keeps its distribution, CLI-command, and
167
+ config decisions unchanged.
@@ -0,0 +1,85 @@
1
+ ADR 0011: A Generic Host Adapter — Detect First, Then Bind What Works
2
+
3
+ - Status: Accepted
4
+ - Date: 2026-07-16
5
+ - Builds on: ADR 0008 (two seams), ADR 0010 (multi-host adapters, shared CLI builder)
6
+ - Scope: how memU integrates with agents that have **no dedicated adapter**. It does not
7
+ change the five dedicated hosts or the pipeline.
8
+
9
+ ## Context
10
+
11
+ ADR 0010 shipped five dedicated adapters and noted the recipe for a sixth: a `classify`
12
+ method, two paths, two markdown files. That recipe assumes someone writes the adapter. The
13
+ long tail of agents — new CLIs appear monthly — will mostly never get one, yet many of them
14
+ are integrable *today*, because the ecosystem has converged on a handful of session-log
15
+ dialects and a handful of instruction-file names.
16
+
17
+ Two observations make a generic adapter viable:
18
+
19
+ 1. **Session logs cluster into ~5 JSONL dialects.** Payload-wrapped (Codex lineage), typed
20
+ message trees (OpenClaw/pi lineage), typed block records (Claude Code lineage),
21
+ role+message blocks (Cursor lineage), and flat OpenAI-client chat rows. A sniffing
22
+ `classify` that tries these in order covers most JSONL-logging agents without any
23
+ per-agent code.
24
+ 2. **The two seams degrade independently.** An agent with a readable session log gets
25
+ *memorization* (the record seam) even if we cannot find its instruction file; an agent
26
+ with only an `AGENTS.md`/`CLAUDE.md`/`SOUL.md`-style file gets *retrieval* (the inject
27
+ seam) even if its sessions are unreadable (SQLite, editor state, or absent). Partial
28
+ integration is still integration — but only if the user is told which half they got.
29
+
30
+ ## Decision
31
+
32
+ One more binary, `memu-agent` (package `memu.hosts.generic`), with the shared verb surface
33
+ plus one new verb:
34
+
35
+ - **`detect` probes before anything binds.** With no argument it surveys `~` for agent
36
+ directories; with a path it probes that directory. For each candidate it answers the two
37
+ questions in order — *is there a session log whose records sniff as a known dialect?*
38
+ (memorization), and if not or additionally, *is there an instruction file to patch?*
39
+ (retrieval) — and prints an explicit per-agent verdict: memorization works / retrieval
40
+ works / both / neither, with the found paths and the exact next command. Directories of
41
+ the five dedicated hosts are redirected to their own binaries. Sessions in containers the
42
+ sniffer cannot read (SQLite and friends) are reported as such — the Hermes precedent, not
43
+ silence.
44
+ - **The transcript source sniffs per record.** `GenericTranscriptSource.classify` tries the
45
+ five dialects in order; a record matching none is `OTHER`. This is the same fail-closed
46
+ posture the dedicated adapters take with their hosts' metadata records: the mining jobs
47
+ see only what provably is conversation or tool traffic, so a half-recognized log degrades
48
+ to less input, never to garbage input.
49
+ - **Nothing is defaulted that detect must find.** `prepare --session-dir` is *required* (the
50
+ `HostSpec` marks no universal location), and `install-instruction` takes the `--path`
51
+ detect reported. The one machine-specific value the bridging prompt carries is that
52
+ session dir — a deliberate, documented exception to ADR 0009's "nothing machine-specific
53
+ in the prompt", because for an unknown agent there is no `PATH`-stable name to hide it
54
+ behind.
55
+ - **Several generic agents share one binary, not one working tree.** The default tree is
56
+ `~/.memu/hosts/agent/`; integrating a second unknown agent means passing
57
+ `--base-dir ~/.memu/hosts/<name>` in that agent's task, keeping ADR 0010's isolation
58
+ guarantee.
59
+
60
+ ## Consequences
61
+
62
+ Positive:
63
+
64
+ - Any agent logging a known JSONL dialect integrates with zero new code, and any agent with
65
+ a recognizable instruction file gets retrieval regardless.
66
+ - The user always learns *which* seams work and why — the detect report is the contract,
67
+ so a retrieval-only integration is a stated outcome rather than a silent half-failure.
68
+ - `detect` doubles as the scouting tool for new dedicated adapters: an unrecognized-dialect
69
+ or SQLite report is exactly the evidence a sixth adapter starts from.
70
+
71
+ Negative / costs:
72
+
73
+ - Sniffing is heuristic. A new dialect classifies as `OTHER` (missed memories, safe), and a
74
+ pathological log could mis-bucket records (wrong-track memories, bounded by the dialects'
75
+ mutual exclusivity). The dedicated adapters remain the correctness bar.
76
+ - `detect`'s survey reads directory listings across `~/.*` (capped per directory); it is
77
+ read-only but not free, and its skip-list of non-agent dirs needs occasional tending.
78
+ - The required `--session-dir` bakes one machine-specific path into the generic bridging
79
+ prompt — accepted, see above.
80
+
81
+ ## Related ADRs
82
+
83
+ - `docs/adr/0010-multi-host-adapters.md` — the shared CLI builder (`HostSpec`) this reuses,
84
+ extended here with `register_extra` (host-specific subcommands) and required-when-blank
85
+ `session_dir`.
@@ -9,3 +9,5 @@
9
9
  - [0007: Split Memorize/Retrieve into Three Independent Lines on a Layered Wiki-Graph Kernel](0007-three-independent-memory-lines-wiki-graph.md)
10
10
  - [0008: Trajectory as the Source — Zero-Code Hooks over a Programmatic API](0008-two-integration-surfaces-hooks-and-api.md)
11
11
  - [0009: Packaging the Codex Integration — pip, a CLI Seam, and One Config Loader](0009-codex-packaging-cli-and-config.md)
12
+ - [0010: Multi-Host Adapters — Claude Code, Cursor, OpenClaw, and Hermes](0010-multi-host-adapters.md)
13
+ - [0011: A Generic Host Adapter — Detect First, Then Bind What Works](0011-generic-host-adapter.md)
@@ -38,14 +38,14 @@ State persists in a local SQLite database (`./data/memu.sqlite3` by default), so
38
38
 
39
39
  ## How it works
40
40
 
41
- This npm package is a thin launcher (a few kB, no dependencies). The engine is the PyPI package [`memu-cli`](https://pypi.org/project/memu-cli/) — the CLI release channel of [`memu-py`](https://pypi.org/project/memu-py/), same module, versioned independently, with prebuilt wheels for Linux (x86_64/aarch64), macOS (Intel/Apple Silicon), and Windows. The shim finds a runner and delegates, in order:
41
+ This npm package is a thin launcher (a few kB, no dependencies). The engine is the PyPI package [`memu-cli`](https://pypi.org/project/memu-cli/) — the memU engine itself, with prebuilt wheels for Linux (x86_64/aarch64), macOS (Intel/Apple Silicon), and Windows. The shim finds a runner and delegates, in order:
42
42
 
43
43
  1. `$MEMU_PYTHON -m memu` — explicit interpreter override
44
44
  2. `uvx --from memu-cli memu` — no install needed, cached by uv (recommended)
45
45
  3. `pipx run --spec memu-cli memu` — no install needed, cached by pipx
46
46
  4. `python3 -m memu` — requires `pip install memu-cli`
47
47
 
48
- Using Python already? Skip npm entirely: `uvx --from memu-cli memu --help`, or `pip install memu-cli`. For the library API (`MemoryService`, Postgres backends), use [`memu-py`](https://pypi.org/project/memu-py/) but install only one of the two in a given environment; they ship the same `memu` module.
48
+ Using Python already? Skip npm entirely: `uvx --from memu-cli memu --help`, or `pip install memu-cli`. The same package carries the library API (`MemoryService`, Postgres backends) — one install covers CLI, host adapters, and library use.
49
49
 
50
50
  See the [main README](https://github.com/NevaMind-AI/MemU#readme) for the memory model, library API, and self-hosting options.
51
51
 
@@ -1,6 +1,5 @@
1
1
  #!/usr/bin/env node
2
- // memu-cli: thin launcher for the PyPI package `memu-cli` (the CLI release
3
- // channel of the memU engine; same module as memu-py, versioned independently).
2
+ // memu-cli: thin launcher for the PyPI package `memu-cli` (the memU engine).
4
3
  //
5
4
  // The memU engine is Python (>= 3.13). This shim finds a runner and delegates,
6
5
  // in order of preference:
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memu-cli",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "CLI for memU \u2014 personal memory as files. Thin launcher for the PyPI package memu-cli.",
5
5
  "bin": {
6
6
  "memu": "bin/memu.js"