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.
- {memu_cli-0.2.0 → memu_cli-0.3.0}/.github/workflows/publish-memu-cli.yml +11 -16
- {memu_cli-0.2.0 → memu_cli-0.3.0}/.github/workflows/release-please.yml +3 -7
- {memu_cli-0.2.0 → memu_cli-0.3.0}/PKG-INFO +24 -13
- {memu_cli-0.2.0 → memu_cli-0.3.0}/README.md +22 -11
- memu_cli-0.3.0/SKILL.md +78 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/docs/adr/0009-codex-packaging-cli-and-config.md +1 -1
- memu_cli-0.3.0/docs/adr/0010-multi-host-adapters.md +167 -0
- memu_cli-0.3.0/docs/adr/0011-generic-host-adapter.md +85 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/docs/adr/README.md +2 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/npm/README.md +2 -2
- {memu_cli-0.2.0 → memu_cli-0.3.0}/npm/bin/memu.js +1 -2
- {memu_cli-0.2.0 → memu_cli-0.3.0}/npm/package.json +1 -1
- {memu_cli-0.2.0 → memu_cli-0.3.0}/pyproject.toml +11 -3
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/hosts/base.py +8 -0
- memu_cli-0.3.0/src/memu/hosts/claude_code/BRIDGING_TASK.md +85 -0
- memu_cli-0.3.0/src/memu/hosts/claude_code/INSTALL.md +153 -0
- memu_cli-0.3.0/src/memu/hosts/claude_code/__init__.py +11 -0
- memu_cli-0.3.0/src/memu/hosts/claude_code/cli.py +47 -0
- memu_cli-0.3.0/src/memu/hosts/claude_code/sessions.py +72 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/hosts/codex/INSTALL.md +1 -1
- memu_cli-0.3.0/src/memu/hosts/codex/cli.py +68 -0
- memu_cli-0.3.0/src/memu/hosts/cursor/BRIDGING_TASK.md +80 -0
- memu_cli-0.3.0/src/memu/hosts/cursor/INSTALL.md +126 -0
- memu_cli-0.3.0/src/memu/hosts/cursor/__init__.py +11 -0
- memu_cli-0.3.0/src/memu/hosts/cursor/cli.py +48 -0
- memu_cli-0.3.0/src/memu/hosts/cursor/sessions.py +74 -0
- memu_cli-0.3.0/src/memu/hosts/generic/BRIDGING_TASK.md +107 -0
- memu_cli-0.3.0/src/memu/hosts/generic/INSTALL.md +151 -0
- memu_cli-0.3.0/src/memu/hosts/generic/__init__.py +12 -0
- memu_cli-0.3.0/src/memu/hosts/generic/cli.py +85 -0
- memu_cli-0.3.0/src/memu/hosts/generic/detect.py +207 -0
- memu_cli-0.3.0/src/memu/hosts/generic/sessions.py +141 -0
- memu_cli-0.3.0/src/memu/hosts/hermes/BRIDGING_TASK.md +83 -0
- memu_cli-0.3.0/src/memu/hosts/hermes/INSTALL.md +128 -0
- memu_cli-0.3.0/src/memu/hosts/hermes/__init__.py +12 -0
- memu_cli-0.3.0/src/memu/hosts/hermes/cli.py +49 -0
- memu_cli-0.3.0/src/memu/hosts/hermes/sessions.py +126 -0
- memu_cli-0.3.0/src/memu/hosts/host_cli.py +221 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/hosts/instruction.py +48 -29
- memu_cli-0.3.0/src/memu/hosts/openclaw/BRIDGING_TASK.md +108 -0
- memu_cli-0.3.0/src/memu/hosts/openclaw/INSTALL.md +129 -0
- memu_cli-0.3.0/src/memu/hosts/openclaw/__init__.py +11 -0
- memu_cli-0.3.0/src/memu/hosts/openclaw/cli.py +47 -0
- memu_cli-0.3.0/src/memu/hosts/openclaw/sessions.py +77 -0
- memu_cli-0.3.0/tests/test_host_generic.py +144 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/tests/test_host_instruction.py +32 -16
- memu_cli-0.3.0/tests/test_host_sessions.py +205 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/uv.lock +1 -1
- memu_cli-0.2.0/src/memu/hosts/codex/cli.py +0 -167
- {memu_cli-0.2.0 → memu_cli-0.3.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/.github/ISSUE_TEMPLATE/hackathon_task.yml +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/.github/ISSUE_TEMPLATE/improvement_suggestion.yml +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/.github/workflows/build.yml +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/.github/workflows/pr-title.yml +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/.gitignore +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/.pre-commit-config.yaml +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/.python-version +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/AGENTS.md +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/CHANGELOG.md +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/CONTRIBUTING.md +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/Cargo.lock +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/Cargo.toml +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/LICENSE.txt +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/MANIFEST.in +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/Makefile +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/assets/banner.png +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/assets/benchmark.png +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/assets/memUbot.png +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/assets/memorize.png +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/assets/partners/Clawdchat.png +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/assets/partners/LazyLLM.png +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/assets/partners/buddie.png +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/assets/partners/bytebase.png +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/assets/partners/jazz.png +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/assets/partners/openagents.png +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/assets/partners/xroute.png +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/assets/qrcode.png +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/assets/retrieve.png +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/assets/star.gif +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/assets/structure-v2.png +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/assets/structure.png +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/assets/usecase/ai_companion-0000.jpg +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/assets/usecase/ai_creation-0000.jpg +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/assets/usecase/ai_edu-0000.jpg +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/assets/usecase/ai_ip-0000.png +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/assets/usecase/ai_robot-0000.jpg +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/assets/usecase/ai_role_play-0000.jpg +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/assets/usecase/ai_therapy-0000.jpg +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/docs/adr/0001-workflow-pipeline-architecture.md +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/docs/adr/0002-pluggable-storage-and-vector-strategy.md +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/docs/adr/0003-user-scope-in-data-model.md +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/docs/adr/0004-workspace-memorize-and-memory-file-system.md +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/docs/adr/0005-dedicated-embedding-package.md +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/docs/adr/0006-from-memory-item-category-to-tracked-workspace-memorization.md +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/docs/adr/0007-three-independent-memory-lines-wiki-graph.md +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/docs/adr/0008-two-integration-surfaces-hooks-and-api.md +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/docs/sqlite.md +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/scripts/db.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/setup.cfg +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/lib.rs +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/__init__.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/__main__.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/_core.pyi +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/app/__init__.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/app/agentic.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/app/client_pool.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/app/service.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/app/settings.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/cli.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/__init__.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/factory.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/inmemory/__init__.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/inmemory/models.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/inmemory/repo.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/inmemory/repositories/__init__.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/inmemory/repositories/filter.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/inmemory/repositories/recall_file_repo.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/inmemory/repositories/recall_file_resource_repo.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/inmemory/repositories/recall_file_segment_repo.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/inmemory/repositories/resource_repo.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/inmemory/state.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/inmemory/vector.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/interfaces.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/models.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/postgres/__init__.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/postgres/migration.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/postgres/migrations/__init__.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/postgres/migrations/env.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/postgres/migrations/script.py.mako +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/postgres/migrations/versions/20260703_0001_initial_schema.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/postgres/models.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/postgres/postgres.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/postgres/repositories/__init__.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/postgres/repositories/base.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/postgres/repositories/recall_file_repo.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/postgres/repositories/recall_file_resource_repo.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/postgres/repositories/recall_file_segment_repo.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/postgres/repositories/resource_repo.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/postgres/schema.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/postgres/session.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/repositories/__init__.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/repositories/recall_file.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/repositories/recall_file_resource.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/repositories/recall_file_segment.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/repositories/resource.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/sqlite/__init__.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/sqlite/models.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/sqlite/repositories/__init__.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/sqlite/repositories/base.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/sqlite/repositories/recall_file_repo.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/sqlite/repositories/recall_file_resource_repo.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/sqlite/repositories/recall_file_segment_repo.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/sqlite/repositories/resource_repo.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/sqlite/schema.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/sqlite/session.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/sqlite/sqlite.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/database/state.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/embedding/__init__.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/embedding/backends/__init__.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/embedding/backends/base.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/embedding/backends/doubao.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/embedding/backends/jina.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/embedding/backends/openai.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/embedding/backends/openrouter.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/embedding/backends/voyage.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/embedding/base.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/embedding/defaults.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/embedding/gateway.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/embedding/http_client.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/embedding/openai_sdk.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/env.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/hosts/__init__.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/hosts/bridging/__init__.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/hosts/bridging/instructions.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/hosts/bridging/layout.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/hosts/bridging/manifest.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/hosts/bridging/pipeline.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/hosts/bridging/recall_files.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/hosts/bridging/resources.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/hosts/bridging/transcripts.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/hosts/codex/BRIDGING_TASK.md +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/hosts/codex/__init__.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/hosts/codex/sessions.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/hosts/retrieval.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/src/memu/vector.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/tests/__init__.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/tests/rust_entry_test.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/tests/test_agentic.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/tests/test_cli.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/tests/test_embedding.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/tests/test_postgres_migration_config.py +0 -0
- {memu_cli-0.2.0 → memu_cli-0.3.0}/tests/test_vector.py +0 -0
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
# Publishes the engine
|
|
1
|
+
# Publishes the engine to PyPI as `memu-cli` — the one and only distribution.
|
|
2
2
|
#
|
|
3
|
-
# `memu-cli`
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
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 (
|
|
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:
|
|
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
|
-
|
|
66
|
-
grep -
|
|
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:
|
|
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
|
-
|
|
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.
|
|
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:
|
|
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
|
|
132
|
+
## Host adapters: memory for desktop coding agents
|
|
127
133
|
|
|
128
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
104
|
+
## Host adapters: memory for desktop coding agents
|
|
99
105
|
|
|
100
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
memu_cli-0.3.0/SKILL.md
ADDED
|
@@ -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-
|
|
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
|
|
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`.
|
|
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
|
|
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:
|