clawmem 0.9.0 → 0.10.1
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.
- package/AGENTS.md +11 -4
- package/CLAUDE.md +11 -4
- package/README.md +37 -21
- package/SKILL.md +16 -6
- package/package.json +2 -2
- package/src/clawmem.ts +150 -23
- package/src/hermes/__init__.py +41 -2
- package/src/openclaw/compaction-threshold.ts +166 -0
- package/src/openclaw/engine.ts +520 -241
- package/src/openclaw/index.ts +151 -140
- package/src/openclaw/openclaw.plugin.json +4 -1
- package/src/openclaw/package.json +9 -0
- package/src/openclaw/session-state.ts +55 -0
- package/src/openclaw/transcript-resolver.ts +441 -0
package/AGENTS.md
CHANGED
|
@@ -208,7 +208,11 @@ When using ClawMem with OpenClaw, choose one of two deployment options:
|
|
|
208
208
|
|
|
209
209
|
**Active Memory coexistence:** ClawMem is fully compatible with OpenClaw's Active Memory plugin (v2026.4.10+). They search different backends (ClawMem vault vs dreaming/wiki) and inject into different prompt regions (user prompt vs system prompt). Both can run simultaneously — no configuration needed.
|
|
210
210
|
|
|
211
|
-
**
|
|
211
|
+
**memory-core dreaming sidecar coexistence (v2026.4.18+, #65411):** ClawMem and `memory-core` dreaming can also run side-by-side. When ClawMem owns the memory slot AND `plugins.entries.memory-core.config.dreaming.enabled = true`, OpenClaw loads `memory-core`'s dreaming engine alongside ClawMem (rest of `memory-core` stays unloaded). Dreaming continues writing to `memory/dreaming/{phase}/YYYY-MM-DD.md` (separate from ClawMem's vault). Default after `openclaw plugins enable clawmem` is `dreaming.enabled = false` (ClawMem-only). Set it `true` if you want to keep the dreaming output stream alongside ClawMem.
|
|
212
|
+
|
|
213
|
+
**OpenClaw v2026.4.11+ required for ClawMem v0.10.0+.** v2026.4.11 tightened plugin discovery (`readdirSync({ withFileTypes: true })` + `dirent.isDirectory()`) and added a plugin-directory ownership check. ClawMem v0.10.0+ ships the new discovery manifest (`src/openclaw/package.json` with `openclaw.extensions`) and defaults to recursive copy (not symlink) installs to clear both gates. Older notes: v2026.4.10 fixed #64192 (`plugins.slots.contextEngine` silently dropped during config normalization, relevant only for pre-v0.10.0 ClawMem that still used the `contextEngine` slot).
|
|
214
|
+
|
|
215
|
+
**ClawMem v0.10.0 uses the `memory` slot, not `contextEngine`.** `openclaw plugins enable clawmem` sets `plugins.slots.memory: "clawmem"` and disables competing memory plugins (`memory-core`, `memory-lancedb`) in one step. The older `openclaw config set plugins.slots.contextEngine clawmem` pattern does not apply to v0.10.0+.
|
|
212
216
|
|
|
213
217
|
### Option 1: ClawMem Exclusive (Recommended)
|
|
214
218
|
|
|
@@ -735,6 +739,9 @@ clawmem focus clear --session-id abc123
|
|
|
735
739
|
- Consolidation worker (`CLAWMEM_ENABLE_CONSOLIDATION=true`) backfills unenriched docs with A-MEM notes + links. Only runs if the MCP process stays alive long enough to tick (every 5min).
|
|
736
740
|
- Beads integration: `syncBeadsIssues()` queries `bd` CLI (Dolt backend, v0.58.0+) for live issue data, creates markdown docs in `beads` collection, maps all dependency edge types into `memory_relations`, and triggers A-MEM enrichment for new docs. Watcher auto-triggers on `.beads/` directory changes; `beads_sync` MCP tool for manual sync. Requires `bd` binary on PATH or at `~/go/bin/bd`.
|
|
737
741
|
- HTTP REST API: `clawmem serve [--port 7438]` — optional REST server on localhost. Search, retrieval, lifecycle, and graph traversal. `POST /retrieve` mirrors `memory_retrieve` with auto-routing (keyword/semantic/causal/timeline/hybrid). `POST /search` provides direct mode selection. Bearer token auth via `CLAWMEM_API_TOKEN` env var (disabled if unset).
|
|
738
|
-
- OpenClaw
|
|
739
|
-
-
|
|
740
|
-
-
|
|
742
|
+
- OpenClaw memory plugin: `clawmem setup openclaw` — registers ClawMem as a native OpenClaw memory plugin (`kind: memory`, v0.10.0+). Lifecycle events on the plugin-hook bus: `before_prompt_build` is the **load-bearing** path — it runs prompt-aware retrieval (context-surfacing) AND the pre-emptive `precompact-extract` synchronously when token usage approaches the compaction threshold, so state is captured BEFORE the LLM call that could trigger compaction; `agent_end` runs decision-extractor + handoff-generator + feedback-loop in parallel (fire-and-forget at OpenClaw); `before_compaction` is **defense-in-depth fallback only** — fire-and-forget, races the compactor, exists for the rare case where the `before_prompt_build` proximity heuristic missed a sudden token jump; `session_start` registers the session and caches first-turn bootstrap context. Shares the same vault as Claude Code hooks (dual-mode). SQLite busy_timeout=5000ms for concurrent access safety.
|
|
743
|
+
- **§14.3 pure-memory migration (v0.10.0):** v0.10.0 drops the `ClawMemContextEngine` class entirely. Previous versions registered as `kind: context-engine` and implemented `assemble()`/`bootstrap()`/`afterTurn()`/`compact()` on a class. v0.10.0 registers as `kind: memory` and wires every lifecycle surface through plugin hooks on the event bus. Retrieval pipeline, composite scoring, vault format, and the 5 registered agent tools are unchanged — this is a packaging and registration change, not a behavioral one.
|
|
744
|
+
- **v2026.4.11 packaging fix (v0.10.0):** `src/openclaw/package.json` declares `openclaw.extensions: ["./index.ts"]` (required by v2026.4.11's discovery path), and `cmdSetupOpenClaw` defaults to `cpSync(..., { recursive: true, dereference: true })` because v2026.4.11's discoverer uses `readdirSync({ withFileTypes: true })` where symlink `isDirectory() === false`. A `--link` opt-in flag preserves the old symlink behavior for dev workflows with a warning.
|
|
745
|
+
- **v2026.4.18 synchronous-`register()` constraint:** OpenClaw v2026.4.18 (`fix(plugins): enforce synchronous registration`) throws `"plugin register must be synchronous"` if the plugin's `register()` function returns a Promise. ClawMem's `register(api)` in `src/openclaw/index.ts` is intentionally synchronous — all `await` work lives inside per-event handlers, never in registration itself. Companion change: register failures now atomically roll back side effects (globals, hook registrations, tool registrations), so any future throw inside `register()` will leave OpenClaw in a clean state. Keep the function synchronous and throw-free; do not add `async` or top-level `await`.
|
|
746
|
+
- **Precompact correctness contract (v0.10.0):** The load-bearing precompact path is `before_prompt_build`, NOT `before_compaction`. `before_prompt_build` is awaited synchronously before the LLM call that could trigger compaction, so it cannot race the compactor. `before_compaction` is fire-and-forget at OpenClaw's call site and exists only as a safety net for the rare case the proximity heuristic in `before_prompt_build` missed a sudden token-count jump. Do not describe `before_compaction` as the primary surface — the guarantee comes from `before_prompt_build`. v0.3.0 did the pre-emptive extraction from `ContextEngine.compact()` via `delegateCompactionToRuntime()`; v0.10.0 moves it into `before_prompt_build` where it can be awaited before the triggering LLM call. User-visible behavior is equivalent or better: state capture now happens strictly before compaction, not in a race with it.
|
|
747
|
+
- Hermes Agent MemoryProvider plugin: `src/hermes/` — Python plugin implementing Hermes's `MemoryProvider` ABC. **Preferred install:** copy into `$HERMES_HOME/plugins/clawmem/` (typically `~/.hermes/plugins/clawmem/`) — Hermes #10529 (v2026.4.13+) added user-plugin discovery, so this path survives `git pull` of hermes-agent. **Bundled-style install:** `hermes-agent/plugins/memory/clawmem/` still works (bundled-first precedence on name collisions). Uses shell-out for lifecycle hooks (session-bootstrap, context-surfacing, extraction) and REST API for tools (retrieve, get, session_log, timeline, similar). Plugin manages its own transcript JSONL for ClawMem hooks. Supports external (you run `clawmem serve`) and managed (plugin starts/stops serve) modes. **Agent-context isolation:** `initialize()` reads the `agent_context` kwarg Hermes passes ("primary"/"subagent"/"cron"/"flush"); for non-primary contexts the read-side hooks (session-bootstrap, context-surfacing) still run but the write-side surfaces (`sync_turn` transcript appends, `on_session_end` extraction, `on_pre_compress` precompact) early-return so cron system prompts and subagent intermediate state never reach the vault.
|
package/CLAUDE.md
CHANGED
|
@@ -208,7 +208,11 @@ When using ClawMem with OpenClaw, choose one of two deployment options:
|
|
|
208
208
|
|
|
209
209
|
**Active Memory coexistence:** ClawMem is fully compatible with OpenClaw's Active Memory plugin (v2026.4.10+). They search different backends (ClawMem vault vs dreaming/wiki) and inject into different prompt regions (user prompt vs system prompt). Both can run simultaneously — no configuration needed.
|
|
210
210
|
|
|
211
|
-
**
|
|
211
|
+
**memory-core dreaming sidecar coexistence (v2026.4.18+, #65411):** ClawMem and `memory-core` dreaming can also run side-by-side. When ClawMem owns the memory slot AND `plugins.entries.memory-core.config.dreaming.enabled = true`, OpenClaw loads `memory-core`'s dreaming engine alongside ClawMem (rest of `memory-core` stays unloaded). Dreaming continues writing to `memory/dreaming/{phase}/YYYY-MM-DD.md` (separate from ClawMem's vault). Default after `openclaw plugins enable clawmem` is `dreaming.enabled = false` (ClawMem-only). Set it `true` if you want to keep the dreaming output stream alongside ClawMem.
|
|
212
|
+
|
|
213
|
+
**OpenClaw v2026.4.11+ required for ClawMem v0.10.0+.** v2026.4.11 tightened plugin discovery (`readdirSync({ withFileTypes: true })` + `dirent.isDirectory()`) and added a plugin-directory ownership check. ClawMem v0.10.0+ ships the new discovery manifest (`src/openclaw/package.json` with `openclaw.extensions`) and defaults to recursive copy (not symlink) installs to clear both gates. Older notes: v2026.4.10 fixed #64192 (`plugins.slots.contextEngine` silently dropped during config normalization, relevant only for pre-v0.10.0 ClawMem that still used the `contextEngine` slot).
|
|
214
|
+
|
|
215
|
+
**ClawMem v0.10.0 uses the `memory` slot, not `contextEngine`.** `openclaw plugins enable clawmem` sets `plugins.slots.memory: "clawmem"` and disables competing memory plugins (`memory-core`, `memory-lancedb`) in one step. The older `openclaw config set plugins.slots.contextEngine clawmem` pattern does not apply to v0.10.0+.
|
|
212
216
|
|
|
213
217
|
### Option 1: ClawMem Exclusive (Recommended)
|
|
214
218
|
|
|
@@ -735,6 +739,9 @@ clawmem focus clear --session-id abc123
|
|
|
735
739
|
- Consolidation worker (`CLAWMEM_ENABLE_CONSOLIDATION=true`) backfills unenriched docs with A-MEM notes + links. Only runs if the MCP process stays alive long enough to tick (every 5min).
|
|
736
740
|
- Beads integration: `syncBeadsIssues()` queries `bd` CLI (Dolt backend, v0.58.0+) for live issue data, creates markdown docs in `beads` collection, maps all dependency edge types into `memory_relations`, and triggers A-MEM enrichment for new docs. Watcher auto-triggers on `.beads/` directory changes; `beads_sync` MCP tool for manual sync. Requires `bd` binary on PATH or at `~/go/bin/bd`.
|
|
737
741
|
- HTTP REST API: `clawmem serve [--port 7438]` — optional REST server on localhost. Search, retrieval, lifecycle, and graph traversal. `POST /retrieve` mirrors `memory_retrieve` with auto-routing (keyword/semantic/causal/timeline/hybrid). `POST /search` provides direct mode selection. Bearer token auth via `CLAWMEM_API_TOKEN` env var (disabled if unset).
|
|
738
|
-
- OpenClaw
|
|
739
|
-
-
|
|
740
|
-
-
|
|
742
|
+
- OpenClaw memory plugin: `clawmem setup openclaw` — registers ClawMem as a native OpenClaw memory plugin (`kind: memory`, v0.10.0+). Lifecycle events on the plugin-hook bus: `before_prompt_build` is the **load-bearing** path — it runs prompt-aware retrieval (context-surfacing) AND the pre-emptive `precompact-extract` synchronously when token usage approaches the compaction threshold, so state is captured BEFORE the LLM call that could trigger compaction; `agent_end` runs decision-extractor + handoff-generator + feedback-loop in parallel (fire-and-forget at OpenClaw); `before_compaction` is **defense-in-depth fallback only** — fire-and-forget, races the compactor, exists for the rare case where the `before_prompt_build` proximity heuristic missed a sudden token jump; `session_start` registers the session and caches first-turn bootstrap context. Shares the same vault as Claude Code hooks (dual-mode). SQLite busy_timeout=5000ms for concurrent access safety.
|
|
743
|
+
- **§14.3 pure-memory migration (v0.10.0):** v0.10.0 drops the `ClawMemContextEngine` class entirely. Previous versions registered as `kind: context-engine` and implemented `assemble()`/`bootstrap()`/`afterTurn()`/`compact()` on a class. v0.10.0 registers as `kind: memory` and wires every lifecycle surface through plugin hooks on the event bus. Retrieval pipeline, composite scoring, vault format, and the 5 registered agent tools are unchanged — this is a packaging and registration change, not a behavioral one.
|
|
744
|
+
- **v2026.4.11 packaging fix (v0.10.0):** `src/openclaw/package.json` declares `openclaw.extensions: ["./index.ts"]` (required by v2026.4.11's discovery path), and `cmdSetupOpenClaw` defaults to `cpSync(..., { recursive: true, dereference: true })` because v2026.4.11's discoverer uses `readdirSync({ withFileTypes: true })` where symlink `isDirectory() === false`. A `--link` opt-in flag preserves the old symlink behavior for dev workflows with a warning.
|
|
745
|
+
- **v2026.4.18 synchronous-`register()` constraint:** OpenClaw v2026.4.18 (`fix(plugins): enforce synchronous registration`) throws `"plugin register must be synchronous"` if the plugin's `register()` function returns a Promise. ClawMem's `register(api)` in `src/openclaw/index.ts` is intentionally synchronous — all `await` work lives inside per-event handlers, never in registration itself. Companion change: register failures now atomically roll back side effects (globals, hook registrations, tool registrations), so any future throw inside `register()` will leave OpenClaw in a clean state. Keep the function synchronous and throw-free; do not add `async` or top-level `await`.
|
|
746
|
+
- **Precompact correctness contract (v0.10.0):** The load-bearing precompact path is `before_prompt_build`, NOT `before_compaction`. `before_prompt_build` is awaited synchronously before the LLM call that could trigger compaction, so it cannot race the compactor. `before_compaction` is fire-and-forget at OpenClaw's call site and exists only as a safety net for the rare case the proximity heuristic in `before_prompt_build` missed a sudden token-count jump. Do not describe `before_compaction` as the primary surface — the guarantee comes from `before_prompt_build`. v0.3.0 did the pre-emptive extraction from `ContextEngine.compact()` via `delegateCompactionToRuntime()`; v0.10.0 moves it into `before_prompt_build` where it can be awaited before the triggering LLM call. User-visible behavior is equivalent or better: state capture now happens strictly before compaction, not in a race with it.
|
|
747
|
+
- Hermes Agent MemoryProvider plugin: `src/hermes/` — Python plugin implementing Hermes's `MemoryProvider` ABC. **Preferred install:** copy into `$HERMES_HOME/plugins/clawmem/` (typically `~/.hermes/plugins/clawmem/`) — Hermes #10529 (v2026.4.13+) added user-plugin discovery, so this path survives `git pull` of hermes-agent. **Bundled-style install:** `hermes-agent/plugins/memory/clawmem/` still works (bundled-first precedence on name collisions). Uses shell-out for lifecycle hooks (session-bootstrap, context-surfacing, extraction) and REST API for tools (retrieve, get, session_log, timeline, similar). Plugin manages its own transcript JSONL for ClawMem hooks. Supports external (you run `clawmem serve`) and managed (plugin starts/stops serve) modes. **Agent-context isolation:** `initialize()` reads the `agent_context` kwarg Hermes passes ("primary"/"subagent"/"cron"/"flush"); for non-primary contexts the read-side hooks (session-bootstrap, context-surfacing) still run but the write-side surfaces (`sync_turn` transcript appends, `on_session_end` extraction, `on_pre_compress` precompact) early-return so cron system prompts and subagent intermediate state never reach the vault.
|
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# ClawMem —
|
|
1
|
+
# ClawMem — On-device memory layer for Claude Code, OpenClaw, and Hermes agents
|
|
2
2
|
|
|
3
3
|
<p align="center">
|
|
4
4
|
<img src="docs/clawmem_hero.jpg" alt="ClawMem" width="100%">
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
ClawMem fuses recent research into a retrieval-augmented memory layer that agents actually use. The hybrid architecture combines [QMD](https://github.com/tobi/qmd)-derived multi-signal retrieval (BM25 + vector search + reciprocal rank fusion + query expansion + cross-encoder reranking), [SAME](https://github.com/sgx-labs/statelessagent)-inspired composite scoring (recency decay, confidence, content-type half-lives, co-activation reinforcement), [MAGMA](https://arxiv.org/abs/2501.13956)-style intent classification with multi-graph traversal (semantic, temporal, and causal beam search), and [A-MEM](https://arxiv.org/abs/2510.02178) self-evolving memory notes that enrich documents with keywords, tags, and causal links between entries. Pattern extraction from [Engram](https://github.com/Gentleman-Programming/engram) adds deduplication windows, frequency-based durability scoring, and temporal navigation.
|
|
10
10
|
|
|
11
|
-
Integrates via Claude Code hooks, an MCP server (works with any MCP-compatible client), a native OpenClaw
|
|
11
|
+
Integrates via Claude Code hooks, an MCP server (works with any MCP-compatible client), a native OpenClaw plugin, or a Hermes Agent `MemoryProvider` plugin. All paths write to the same local SQLite vault. A decision captured during a Claude Code session shows up immediately when an OpenClaw or Hermes agent picks up the same project.
|
|
12
12
|
|
|
13
13
|
TypeScript on Bun. MIT License.
|
|
14
14
|
|
|
@@ -47,7 +47,7 @@ ClawMem turns your markdown notes, project docs, and research dumps into persist
|
|
|
47
47
|
- **Syncs project issues** from Beads issue trackers into searchable memory
|
|
48
48
|
- **Runs a quiet-window heavy maintenance lane** — a second consolidation worker, off by default behind `CLAWMEM_HEAVY_LANE=true`, that runs on a longer interval only inside a configurable hour window. Gated by `context_usage` query-rate so it never competes for CPU/GPU with interactive sessions, scoped exclusively via DB-backed `worker_leases`, stale-first by default with an optional surprisal selector, and journals every attempt in `maintenance_runs` for operator visibility (v0.8.0)
|
|
49
49
|
|
|
50
|
-
Runs fully local with no API keys and no cloud services. Integrates via Claude Code hooks and MCP tools, as
|
|
50
|
+
Runs fully local with no API keys and no cloud services. Integrates via Claude Code hooks and MCP tools, as a native OpenClaw plugin, or as a Hermes Agent `MemoryProvider` plugin. All modes share the same vault for cross-runtime memory. Works with any MCP-compatible client.
|
|
51
51
|
|
|
52
52
|
Full version history is in [RELEASE_NOTES.md](RELEASE_NOTES.md). Upgrade instructions for existing vaults are in [docs/guides/upgrading.md](docs/guides/upgrading.md).
|
|
53
53
|
|
|
@@ -83,8 +83,8 @@ Full version history is in [RELEASE_NOTES.md](RELEASE_NOTES.md). Upgrade instruc
|
|
|
83
83
|
**Optional integrations:**
|
|
84
84
|
|
|
85
85
|
- [Claude Code](https://docs.anthropic.com/en/docs/claude-code) — for hooks + MCP integration
|
|
86
|
-
- [OpenClaw](https://github.com/openclaw/openclaw) — for
|
|
87
|
-
- [Hermes Agent](https://github.com/NousResearch/hermes-agent) — for MemoryProvider plugin integration
|
|
86
|
+
- [OpenClaw](https://github.com/openclaw/openclaw) — for native plugin integration
|
|
87
|
+
- [Hermes Agent](https://github.com/NousResearch/hermes-agent) — for `MemoryProvider` plugin integration
|
|
88
88
|
- [bd CLI](https://github.com/dolthub/dolt) v0.58.0+ — for Beads issue tracker sync (only if using Beads)
|
|
89
89
|
|
|
90
90
|
### Install from npm (recommended)
|
|
@@ -185,29 +185,31 @@ clawmem setup mcp # Register MCP server in ~/.claude.json (31 tools)
|
|
|
185
185
|
|
|
186
186
|
#### OpenClaw
|
|
187
187
|
|
|
188
|
-
ClawMem registers as a native
|
|
188
|
+
ClawMem registers as a native OpenClaw memory plugin (`kind: memory`, v0.10.0+). Same 90/10 automatic retrieval, delivered through OpenClaw's plugin-hook bus instead of Claude Code hooks.
|
|
189
189
|
|
|
190
190
|
```bash
|
|
191
|
-
clawmem setup openclaw #
|
|
191
|
+
clawmem setup openclaw # Installs plugin into ~/.openclaw/extensions/clawmem (copy, not symlink)
|
|
192
192
|
```
|
|
193
193
|
|
|
194
194
|
**What the plugin provides:**
|
|
195
|
-
- **`before_prompt_build` hook** - prompt-aware retrieval (context-surfacing + session-bootstrap)
|
|
196
|
-
- **`
|
|
197
|
-
- **`
|
|
195
|
+
- **`before_prompt_build` hook (load-bearing)** - prompt-aware retrieval (context-surfacing + session-bootstrap) AND the pre-emptive `precompact-extract` run when token usage approaches the compaction threshold. This is the authoritative path for precompact state capture because it runs synchronously before the LLM call that would trigger compaction, so it cannot race the compactor.
|
|
196
|
+
- **`agent_end` hook** - decision extraction, handoff generation, feedback loop (parallel, fire-and-forget at the OpenClaw call site)
|
|
197
|
+
- **`before_compaction` hook (defense-in-depth fallback)** - fires `precompact-extract` again for the rare case where `before_prompt_build`'s proximity heuristic missed a sudden token-count jump. Fire-and-forget at OpenClaw's call site, so it races the compactor and offers no correctness guarantee on its own — the `before_prompt_build` path is what actually holds the invariant.
|
|
198
|
+
- **`session_start` hook** - session registration + cached first-turn bootstrap context
|
|
198
199
|
- **5 agent tools** - `clawmem_search`, `clawmem_get`, `clawmem_session_log`, `clawmem_timeline`, `clawmem_similar`
|
|
199
|
-
- **Session lifecycle hooks** - `session_start`, `session_end`, `before_reset` safety net
|
|
200
200
|
|
|
201
201
|
Disable OpenClaw's native memory search to avoid duplicate injection:
|
|
202
202
|
```bash
|
|
203
203
|
openclaw config set agents.defaults.memorySearch.extraPaths "[]"
|
|
204
204
|
```
|
|
205
205
|
|
|
206
|
-
ClawMem coexists cleanly with OpenClaw's [Active Memory](https://docs.openclaw.ai/concepts/active-memory) plugin (v2026.4.10+) —
|
|
206
|
+
ClawMem coexists cleanly with OpenClaw's [Active Memory](https://docs.openclaw.ai/concepts/active-memory) plugin (v2026.4.10+) and, on OpenClaw v2026.4.18+ (#65411), with the `memory-core` dreaming sidecar — both run alongside ClawMem instead of being mutually exclusive. They search different backends and inject into different prompt regions, so they do not conflict. See the [OpenClaw plugin guide — Active Memory coexistence](docs/guides/openclaw-plugin.md#coexistence-with-openclaw-active-memory) and the [memory-core dreaming sidecar section](docs/guides/openclaw-plugin.md#coexistence-with-memory-core-dreaming-sidecar) for the two patterns.
|
|
207
207
|
|
|
208
|
-
|
|
208
|
+
**Pair ClawMem (memory) with a context-engine plugin (v0.10.0+).** OpenClaw and Hermes maintainers have converged on a two-surface plugin model: one slot for memory plugins (cross-session, retrieval-first) and a separate slot for context-engine plugins (in-session, compression/compaction-first). Under that model ClawMem is a memory layer — it has always been one in Hermes via the `MemoryProvider` ABC, and v0.10.0 moves the OpenClaw integration to the same semantic slot. You can now run ClawMem in the `memory` slot alongside an LCM-style compression plugin (for example, `lossless-claw`) in the `context-engine` slot. The two plugins do not overlap: one persists across sessions, the other reshapes the live window. See the [OpenClaw plugin guide — memory vs context engine](docs/guides/openclaw-plugin.md#memory-vs-context-engine--the-dual-plugin-surface) for the full rationale.
|
|
209
209
|
|
|
210
|
-
**
|
|
210
|
+
> **OpenClaw v2026.4.11+ recommended (required for ClawMem v0.10.0+).** v2026.4.11 introduced a new plugin discovery contract that requires each plugin directory to ship a `package.json` with `openclaw.extensions` declared, and that rejects symlinked plugin directories. ClawMem v0.10.0 includes both fixes. Older ClawMem versions (< v0.10.0) on OpenClaw v2026.4.11+ will fail to discover silently — upgrade ClawMem, then re-run `clawmem setup openclaw`. See [docs/guides/upgrading.md](docs/guides/upgrading.md#v090--v0100).
|
|
211
|
+
|
|
212
|
+
**Alternative:** OpenClaw agents can also use ClawMem's MCP server directly (`clawmem setup mcp`), with or without hooks. This gives full access to all 31 MCP tools but bypasses OpenClaw's plugin lifecycle, so you lose token budget awareness, native compaction orchestration, and the `agent_end` message pipeline. The native OpenClaw plugin is recommended for new setups; MCP is available as an additional or standalone integration.
|
|
211
213
|
|
|
212
214
|
#### Hermes Agent
|
|
213
215
|
|
|
@@ -216,11 +218,16 @@ ClawMem integrates as a native MemoryProvider plugin — Hermes's pluggable inte
|
|
|
216
218
|
**Install:**
|
|
217
219
|
|
|
218
220
|
```bash
|
|
219
|
-
#
|
|
221
|
+
# Preferred — user-plugin path (Hermes #10529, v2026.4.13+).
|
|
222
|
+
# Survives `git pull` of hermes-agent and avoids dual-registration with bundled providers.
|
|
223
|
+
cp -r /path/to/ClawMem/src/hermes ${HERMES_HOME:-~/.hermes}/plugins/clawmem
|
|
224
|
+
|
|
225
|
+
# Or, the bundled-style path (always supported, takes precedence on name collisions).
|
|
226
|
+
# Recommended only when you actively work in the hermes-agent source tree.
|
|
220
227
|
cp -r /path/to/ClawMem/src/hermes /path/to/hermes-agent/plugins/memory/clawmem
|
|
221
228
|
|
|
222
|
-
#
|
|
223
|
-
ln -s /path/to/ClawMem/src/hermes
|
|
229
|
+
# Symlink alternative for in-place development (either path).
|
|
230
|
+
ln -s /path/to/ClawMem/src/hermes ${HERMES_HOME:-~/.hermes}/plugins/clawmem
|
|
224
231
|
```
|
|
225
232
|
|
|
226
233
|
**Configure** in your Hermes profile's `.env` or environment:
|
|
@@ -1088,9 +1095,14 @@ clawmem install-service --enable
|
|
|
1088
1095
|
#### OpenClaw-specific
|
|
1089
1096
|
|
|
1090
1097
|
```bash
|
|
1091
|
-
# Install the
|
|
1098
|
+
# Install the OpenClaw plugin (v0.10.0+: recursively copies into ~/.openclaw/extensions/clawmem)
|
|
1092
1099
|
clawmem setup openclaw
|
|
1093
|
-
# Then follow the printed next steps:
|
|
1100
|
+
# Then follow the printed next steps:
|
|
1101
|
+
# 1. openclaw plugins enable clawmem (switches memory slot + disables memory-core)
|
|
1102
|
+
# 2. openclaw gateway restart
|
|
1103
|
+
# 3. Configure GPU endpoints if needed (see setup openclaw output)
|
|
1104
|
+
# Multi-user installs also need: sudo chown -R <gateway-user>:<gateway-group> ~/.openclaw/extensions/clawmem
|
|
1105
|
+
# Requires OpenClaw v2026.4.11+.
|
|
1094
1106
|
```
|
|
1095
1107
|
|
|
1096
1108
|
Index your content directories with `clawmem bootstrap` as above. The OpenClaw plugin shares the same vault as Claude Code hooks.
|
|
@@ -1098,8 +1110,12 @@ Index your content directories with `clawmem bootstrap` as above. The OpenClaw p
|
|
|
1098
1110
|
#### Hermes-specific
|
|
1099
1111
|
|
|
1100
1112
|
```bash
|
|
1101
|
-
# Install the memory provider plugin
|
|
1102
|
-
|
|
1113
|
+
# Install the memory provider plugin.
|
|
1114
|
+
# Preferred: $HERMES_HOME/plugins/clawmem/ (user-plugin path, Hermes #10529, v2026.4.13+).
|
|
1115
|
+
ln -s $(npm root -g)/clawmem/src/hermes ${HERMES_HOME:-~/.hermes}/plugins/clawmem
|
|
1116
|
+
|
|
1117
|
+
# Bundled-style path is also supported (takes precedence on name collisions):
|
|
1118
|
+
# ln -s $(npm root -g)/clawmem/src/hermes /path/to/hermes-agent/plugins/memory/clawmem
|
|
1103
1119
|
|
|
1104
1120
|
# Start the REST API (required for Hermes tool calls)
|
|
1105
1121
|
clawmem serve --port 7438 &
|
package/SKILL.md
CHANGED
|
@@ -605,9 +605,13 @@ Phase 3 deductive synthesis applies the same `contradicts` link for any draft th
|
|
|
605
605
|
|
|
606
606
|
## OpenClaw Integration
|
|
607
607
|
|
|
608
|
-
**Active Memory coexistence:** ClawMem is fully compatible with OpenClaw's Active Memory plugin (v2026.4.10+). They search different backends and inject into different prompt regions
|
|
608
|
+
**Active Memory coexistence:** ClawMem is fully compatible with OpenClaw's Active Memory plugin (v2026.4.10+). They search different backends and inject into different prompt regions, both can run simultaneously. The deployment options below control native memory search (`memorySearch.extraPaths`), not Active Memory.
|
|
609
609
|
|
|
610
|
-
**
|
|
610
|
+
**memory-core dreaming sidecar coexistence (v2026.4.18+, #65411):** When ClawMem owns the memory slot AND `plugins.entries.memory-core.config.dreaming.enabled = true`, OpenClaw loads `memory-core`'s dreaming engine alongside ClawMem (rest of `memory-core` stays unloaded). Default after `openclaw plugins enable clawmem` is `dreaming.enabled = false` (ClawMem-only). Set it `true` to keep the dreaming output stream (`memory/dreaming/{phase}/YYYY-MM-DD.md`) alongside ClawMem.
|
|
611
|
+
|
|
612
|
+
**OpenClaw v2026.4.11+ required for ClawMem v0.10.0+.** v2026.4.11 tightened plugin discovery (requires `package.json` with `openclaw.extensions`, rejects symlinked plugin directories). ClawMem v0.10.0 ships the new discovery manifest and defaults `clawmem setup openclaw` to recursive copy (not symlink). v2026.4.10 earlier fixed the #64192 config-normalization bug that dropped the `contextEngine` slot, which is now moot on v0.10.0+ because v0.10.0 uses the `memory` slot instead.
|
|
613
|
+
|
|
614
|
+
**ClawMem v0.10.0 plugin kind:** `memory` (not `context-engine`). Enable with `openclaw plugins enable clawmem`, which also disables `memory-core` / `memory-lancedb` in one step.
|
|
611
615
|
|
|
612
616
|
### Option 1: ClawMem Exclusive (Recommended)
|
|
613
617
|
|
|
@@ -629,9 +633,15 @@ openclaw config set agents.defaults.memorySearch.extraPaths '["~/documents", "~/
|
|
|
629
633
|
|
|
630
634
|
**Tradeoffs:** Redundant recall but 10-15% context window waste from duplicate facts.
|
|
631
635
|
|
|
632
|
-
###
|
|
636
|
+
### Multi-user install gotcha (v2026.4.11+)
|
|
637
|
+
|
|
638
|
+
If the gateway runs as a dedicated system user (e.g. `openclaw`) different from the user who runs `clawmem setup openclaw` (e.g. `sciros`), the copied plugin dir is rejected with `suspicious ownership (uid=X, expected uid=Y or root)`. Fix: `sudo chown -R <gateway-user>:<gateway-group> ~/.openclaw/extensions/clawmem`. Single-user installs are not affected.
|
|
639
|
+
|
|
640
|
+
Also: if the gateway user cannot traverse `~/<installer>/.openclaw/` (directory mode 700), the gateway fails to start with `Missing config. Run openclaw setup or set gateway.mode=local`. Fix: `sudo chmod 750 ~/<installer>/.openclaw` and ensure the gateway user is in the owning group.
|
|
641
|
+
|
|
642
|
+
### Precompact state capture — where it runs
|
|
633
643
|
|
|
634
|
-
`
|
|
644
|
+
The load-bearing surface for `precompact-extract` is `before_prompt_build`, not `before_compaction`. `before_prompt_build` awaits the extraction synchronously when token usage approaches the compaction threshold, so state capture completes before the LLM call that could trigger compaction on this turn. `before_compaction` is a defense-in-depth fallback only — fire-and-forget at OpenClaw's call site, races the compactor, exists for the rare case the proximity heuristic in `before_prompt_build` missed a sudden token jump. v0.3.0 did the pre-emptive extraction from `ContextEngine.compact()` via `delegateCompactionToRuntime()`; v0.10.0 moves it into `before_prompt_build` where it has a real pre-LLM hook to await on. ClawMem does not implement compaction itself — if you want compression in the same OpenClaw runtime, install a context-engine plugin (e.g. `lossless-claw`) into the context-engine slot, which v0.10.0 no longer occupies.
|
|
635
645
|
|
|
636
646
|
---
|
|
637
647
|
|
|
@@ -786,8 +796,8 @@ clawmem focus clear --session-id abc123
|
|
|
786
796
|
- Consolidation worker (`CLAWMEM_ENABLE_CONSOLIDATION=true`) backfills unenriched docs and runs Phase 2 merge / Phase 3 deductive synthesis. **v0.8.2:** hosted by either `clawmem watch` (long-lived, canonical) or `clawmem mcp` (per-session fallback); every tick acquires a `light-consolidation` `worker_leases` row before doing work, so dual-hosting against the same vault is safe.
|
|
787
797
|
- Beads integration: `syncBeadsIssues()` queries `bd` CLI (Dolt backend, v0.58.0+), creates markdown docs, maps dependency edges into `memory_relations`. Watcher auto-triggers on `.beads/` changes; `beads_sync` MCP for manual sync.
|
|
788
798
|
- HTTP REST API: `clawmem serve [--port 7438]` — optional REST server on localhost. Search, retrieval, lifecycle, and graph traversal. `POST /retrieve` mirrors `memory_retrieve` with auto-routing (keyword/semantic/causal/timeline/hybrid). `POST /search` provides direct mode selection. Bearer token auth via `CLAWMEM_API_TOKEN` env var (disabled if unset).
|
|
789
|
-
- OpenClaw
|
|
790
|
-
- Hermes Agent MemoryProvider plugin: `src/hermes/` — Python plugin for Hermes's memory system. Shell-out hooks for lifecycle (prefetch, extraction, precompact), REST API for tools. Plugin-managed transcript JSONL bridges Hermes turn pairs to ClawMem file format. Shares vault with Claude Code and OpenClaw.
|
|
799
|
+
- OpenClaw memory plugin (v0.10.0+): `clawmem setup openclaw` — registers as native OpenClaw memory plugin (`kind: memory`). Dual-mode: shares vault with Claude Code hooks. Hook wiring on the plugin-hook bus: `before_prompt_build` is the **load-bearing** path — it runs prompt-aware retrieval AND the pre-emptive `precompact-extract` synchronously when token usage approaches the compaction threshold, so state is captured before the LLM call that could trigger compaction. `agent_end` runs decision-extractor + handoff-generator + feedback-loop in parallel (fire-and-forget at OpenClaw's call site). `before_compaction` is **defense-in-depth fallback only** — fire-and-forget, races the compactor, exists for the rare case where the proximity heuristic in `before_prompt_build` missed a sudden token jump. `session_start` registers the session + caches first-turn bootstrap context. The §14.3 migration removed the `ClawMemContextEngine` class and moved the plugin from the `context-engine` slot to the `memory` slot. Requires OpenClaw v2026.4.11+ (earlier versions do not support the new discovery contract).
|
|
800
|
+
- Hermes Agent MemoryProvider plugin: `src/hermes/` — Python plugin for Hermes's memory system. Shell-out hooks for lifecycle (prefetch, extraction, precompact), REST API for tools. Plugin-managed transcript JSONL bridges Hermes turn pairs to ClawMem file format. Shares vault with Claude Code and OpenClaw. **Preferred install path:** `$HERMES_HOME/plugins/clawmem/` (Hermes #10529 user-plugin discovery, v2026.4.13+) — survives `git pull` of hermes-agent. The bundled `hermes-agent/plugins/memory/clawmem/` path still works. **Agent-context isolation:** read-side hooks always run; write-side surfaces (`sync_turn`, `on_session_end`, `on_pre_compress`) early-return when `agent_context != "primary"` so cron/subagent state never reaches the vault.
|
|
791
801
|
|
|
792
802
|
## Tool Selection (one-liner)
|
|
793
803
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clawmem",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "On-device
|
|
3
|
+
"version": "0.10.1",
|
|
4
|
+
"description": "On-device memory layer for AI agents. Claude Code, OpenClaw, and Hermes. Hooks + MCP server + hybrid RAG search.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"clawmem": "./bin/clawmem"
|
package/src/clawmem.ts
CHANGED
|
@@ -1304,8 +1304,28 @@ function cmdPath() {
|
|
|
1304
1304
|
console.log(getDefaultDbPath());
|
|
1305
1305
|
}
|
|
1306
1306
|
|
|
1307
|
+
/**
|
|
1308
|
+
* Read a single OpenClaw config key via `openclaw config get <key>`. Returns
|
|
1309
|
+
* the trimmed string value, or undefined when the key is unset / the CLI is
|
|
1310
|
+
* unavailable / the key is missing. Callers should treat undefined as
|
|
1311
|
+
* "no opinion" rather than "definitely unset".
|
|
1312
|
+
*/
|
|
1313
|
+
function readOpenClawConfigValue(key: string): string | undefined {
|
|
1314
|
+
try {
|
|
1315
|
+
const r = Bun.spawnSync(["openclaw", "config", "get", key], { stdout: "pipe", stderr: "pipe" });
|
|
1316
|
+
if (r.exitCode !== 0) return undefined;
|
|
1317
|
+
const out = new TextDecoder().decode(r.stdout).trim();
|
|
1318
|
+
if (!out) return undefined;
|
|
1319
|
+
// `openclaw config get` may print JSON ("clawmem"\n) or raw (clawmem). Strip quotes.
|
|
1320
|
+
return out.replace(/^"(.*)"$/, "$1");
|
|
1321
|
+
} catch {
|
|
1322
|
+
return undefined;
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1307
1326
|
async function cmdSetupOpenClaw(args: string[]) {
|
|
1308
1327
|
const remove = args.includes("--remove");
|
|
1328
|
+
const linkMode = args.includes("--link");
|
|
1309
1329
|
const pluginDir = pathResolve(import.meta.dir, "openclaw");
|
|
1310
1330
|
const extensionsDir = pathResolve(process.env.HOME || "~", ".openclaw", "extensions");
|
|
1311
1331
|
const linkPath = pathResolve(extensionsDir, "clawmem");
|
|
@@ -1339,10 +1359,21 @@ async function cmdSetupOpenClaw(args: string[]) {
|
|
|
1339
1359
|
}
|
|
1340
1360
|
|
|
1341
1361
|
if (hasOpenClawCli) {
|
|
1342
|
-
|
|
1343
|
-
|
|
1362
|
+
// Reset the memory slot if ClawMem owned it (post-§14.3-migration installs).
|
|
1363
|
+
const memSlot = readOpenClawConfigValue("plugins.slots.memory");
|
|
1364
|
+
if (memSlot === "clawmem") {
|
|
1365
|
+
Bun.spawnSync(["openclaw", "config", "unset", "plugins.slots.memory"], { stdout: "inherit", stderr: "inherit" });
|
|
1366
|
+
console.log(`${c.green}Cleared memory slot (was clawmem)${c.reset}`);
|
|
1367
|
+
}
|
|
1368
|
+
// Reset the legacy context-engine slot if any pre-§14.3-migration install
|
|
1369
|
+
// left it pointing at clawmem.
|
|
1370
|
+
const ceSlot = readOpenClawConfigValue("plugins.slots.contextEngine");
|
|
1371
|
+
if (ceSlot === "clawmem") {
|
|
1372
|
+
Bun.spawnSync(["openclaw", "config", "set", "plugins.slots.contextEngine", "legacy"], { stdout: "inherit", stderr: "inherit" });
|
|
1373
|
+
console.log(`${c.green}Reset context engine slot to legacy (was clawmem)${c.reset}`);
|
|
1374
|
+
}
|
|
1344
1375
|
} else if (removed) {
|
|
1345
|
-
console.log(`${c.dim}openclaw CLI not found — manually
|
|
1376
|
+
console.log(`${c.dim}openclaw CLI not found — manually clear: openclaw config unset plugins.slots.memory && openclaw config set plugins.slots.contextEngine legacy${c.reset}`);
|
|
1346
1377
|
}
|
|
1347
1378
|
return;
|
|
1348
1379
|
}
|
|
@@ -1354,42 +1385,86 @@ async function cmdSetupOpenClaw(args: string[]) {
|
|
|
1354
1385
|
if (!existsSync(pathResolve(pluginDir, "openclaw.plugin.json"))) {
|
|
1355
1386
|
die(`Plugin manifest not found at ${pluginDir}/openclaw.plugin.json`);
|
|
1356
1387
|
}
|
|
1388
|
+
if (!existsSync(pathResolve(pluginDir, "package.json"))) {
|
|
1389
|
+
die(`Plugin package.json not found at ${pluginDir}/package.json — required for OpenClaw v2026.4.11+ discovery`);
|
|
1390
|
+
}
|
|
1357
1391
|
|
|
1358
1392
|
// Create extensions directory
|
|
1359
1393
|
if (!existsSync(extensionsDir)) {
|
|
1360
1394
|
mkdirSync(extensionsDir, { recursive: true });
|
|
1361
1395
|
}
|
|
1362
1396
|
|
|
1363
|
-
// Remove stale symlink
|
|
1397
|
+
// Remove any stale install (symlink or directory) before re-installing.
|
|
1398
|
+
// OpenClaw v2026.4.11+ discovery (discoverInDirectory in ids-*.js) uses
|
|
1399
|
+
// readdirSync({ withFileTypes: true }) where symlinks report
|
|
1400
|
+
// isDirectory() === false and get silently skipped, so copy mode is the
|
|
1401
|
+
// default. The --link flag keeps symlink behavior for older OpenClaw
|
|
1402
|
+
// versions or local development workflows where editing the live source
|
|
1403
|
+
// should take effect without re-running setup.
|
|
1364
1404
|
try {
|
|
1365
1405
|
const { lstatSync, unlinkSync, rmSync } = await import("fs");
|
|
1366
1406
|
const stat = lstatSync(linkPath);
|
|
1367
1407
|
if (stat.isSymbolicLink()) {
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
if (target === pluginDir) {
|
|
1371
|
-
console.log(`${c.dim}Symlink already correct at ${linkPath}${c.reset}`);
|
|
1372
|
-
} else {
|
|
1373
|
-
unlinkSync(linkPath);
|
|
1374
|
-
console.log(`${c.dim}Replaced stale symlink (was → ${target})${c.reset}`);
|
|
1375
|
-
}
|
|
1408
|
+
unlinkSync(linkPath);
|
|
1409
|
+
console.log(`${c.dim}Replaced stale symlink at ${linkPath}${c.reset}`);
|
|
1376
1410
|
} else if (stat.isDirectory()) {
|
|
1377
1411
|
rmSync(linkPath, { recursive: true });
|
|
1378
1412
|
console.log(`${c.dim}Replaced existing directory at ${linkPath}${c.reset}`);
|
|
1379
1413
|
} else {
|
|
1380
|
-
// Regular file or other non-symlink, non-directory — conflict
|
|
1381
1414
|
die(`${linkPath} exists but is not a symlink or directory. Remove it manually and re-run setup.`);
|
|
1382
1415
|
}
|
|
1383
1416
|
} catch (e: any) {
|
|
1384
1417
|
if (e.code !== "ENOENT") throw e;
|
|
1385
1418
|
}
|
|
1386
1419
|
|
|
1387
|
-
|
|
1388
|
-
if (!existsSync(linkPath)) {
|
|
1420
|
+
if (linkMode) {
|
|
1389
1421
|
const { symlinkSync } = await import("fs");
|
|
1390
1422
|
symlinkSync(pluginDir, linkPath);
|
|
1423
|
+
console.log(`${c.green}Installed plugin: ${linkPath} → ${pluginDir} (symlink)${c.reset}`);
|
|
1424
|
+
console.log(`${c.yellow} Warning: symlink mode. OpenClaw v2026.4.11+ discovery skips${c.reset}`);
|
|
1425
|
+
console.log(`${c.yellow} symlinks silently. Re-run without --link on current releases.${c.reset}`);
|
|
1426
|
+
} else {
|
|
1427
|
+
const { cpSync } = await import("fs");
|
|
1428
|
+
cpSync(pluginDir, linkPath, { recursive: true, dereference: true });
|
|
1429
|
+
console.log(`${c.green}Installed plugin: ${linkPath} (copied from ${pluginDir})${c.reset}`);
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1432
|
+
// ----- §14.3 upgrade migration -----
|
|
1433
|
+
// ClawMem v0.10.0 changed `kind: "context-engine"` to `kind: "memory"`.
|
|
1434
|
+
// Existing installs with `plugins.slots.contextEngine = "clawmem"` will hit
|
|
1435
|
+
// a hard runtime error after upgrading because OpenClaw's
|
|
1436
|
+
// `resolveContextEngine()` throws on unknown engine ids. Detect and rewrite
|
|
1437
|
+
// the stale config to "legacy" so OpenClaw's built-in LegacyContextEngine
|
|
1438
|
+
// takes over compaction. Also detect any pre-existing `plugins.slots.memory`
|
|
1439
|
+
// assignment so we don't clobber a user's choice during upgrade.
|
|
1440
|
+
let migrationApplied = false;
|
|
1441
|
+
if (hasOpenClawCli) {
|
|
1442
|
+
const staleContextEngine = readOpenClawConfigValue("plugins.slots.contextEngine");
|
|
1443
|
+
if (staleContextEngine === "clawmem") {
|
|
1444
|
+
console.log();
|
|
1445
|
+
console.log(`${c.bold}${c.cyan}Upgrade migration detected:${c.reset}`);
|
|
1446
|
+
console.log(` Found legacy ClawMem context-engine slot config from v0.9.x or earlier.`);
|
|
1447
|
+
console.log(` Rewriting plugins.slots.contextEngine: clawmem → legacy`);
|
|
1448
|
+
console.log(` ${c.dim}(ClawMem now registers as a memory plugin. OpenClaw's built-in${c.reset}`);
|
|
1449
|
+
console.log(` ${c.dim} LegacyContextEngine will handle compaction unless you install a${c.reset}`);
|
|
1450
|
+
console.log(` ${c.dim} third-party context-engine plugin like hermes-lcm.)${c.reset}`);
|
|
1451
|
+
const migrate = Bun.spawnSync(
|
|
1452
|
+
["openclaw", "config", "set", "plugins.slots.contextEngine", "legacy"],
|
|
1453
|
+
{ stdout: "inherit", stderr: "inherit" },
|
|
1454
|
+
);
|
|
1455
|
+
if (migrate.exitCode === 0) {
|
|
1456
|
+
migrationApplied = true;
|
|
1457
|
+
} else {
|
|
1458
|
+
console.log(`${c.yellow} Warning: failed to rewrite stale config — please run manually:${c.reset}`);
|
|
1459
|
+
console.log(` ${c.cyan}openclaw config set plugins.slots.contextEngine legacy${c.reset}`);
|
|
1460
|
+
}
|
|
1461
|
+
}
|
|
1462
|
+
} else {
|
|
1463
|
+
console.log();
|
|
1464
|
+
console.log(`${c.dim}Upgrade migration skipped — openclaw CLI not on PATH. If upgrading${c.reset}`);
|
|
1465
|
+
console.log(`${c.dim}from v0.9.x or earlier, manually run:${c.reset}`);
|
|
1466
|
+
console.log(` ${c.cyan}openclaw config set plugins.slots.contextEngine legacy${c.reset}`);
|
|
1391
1467
|
}
|
|
1392
|
-
console.log(`${c.green}Installed plugin: ${linkPath} → ${pluginDir}${c.reset}`);
|
|
1393
1468
|
|
|
1394
1469
|
// Version warning
|
|
1395
1470
|
console.log();
|
|
@@ -1397,17 +1472,21 @@ async function cmdSetupOpenClaw(args: string[]) {
|
|
|
1397
1472
|
console.log(`have a bug where plugins.slots.contextEngine is silently dropped`);
|
|
1398
1473
|
console.log(`during config normalization (openclaw/openclaw#64192).`);
|
|
1399
1474
|
|
|
1400
|
-
// Remaining steps
|
|
1401
|
-
//
|
|
1402
|
-
//
|
|
1475
|
+
// Remaining steps. CLI discovery finds the plugin immediately because the
|
|
1476
|
+
// plugin dir now ships a package.json with openclaw.extensions declared, so
|
|
1477
|
+
// `openclaw plugins enable clawmem` can run before any gateway restart.
|
|
1478
|
+
// The enable command switches the exclusive memory slot to clawmem and
|
|
1479
|
+
// disables memory-core/memory-lancedb automatically. Then the gateway
|
|
1480
|
+
// restart applies the new slot assignment.
|
|
1403
1481
|
console.log();
|
|
1404
1482
|
console.log(`${c.bold}Next steps:${c.reset}`);
|
|
1405
1483
|
console.log();
|
|
1406
|
-
console.log(` 1.
|
|
1407
|
-
console.log(` ${c.cyan}openclaw
|
|
1484
|
+
console.log(` 1. Enable ClawMem as the active memory plugin:`);
|
|
1485
|
+
console.log(` ${c.cyan}openclaw plugins enable clawmem${c.reset}`);
|
|
1486
|
+
console.log(` ${c.dim}(Switches plugins.slots.memory to clawmem and disables memory-core if active.)${c.reset}`);
|
|
1408
1487
|
console.log();
|
|
1409
|
-
console.log(` 2.
|
|
1410
|
-
console.log(` ${c.cyan}openclaw
|
|
1488
|
+
console.log(` 2. Restart the gateway to apply:`);
|
|
1489
|
+
console.log(` ${c.cyan}openclaw gateway restart${c.reset}`);
|
|
1411
1490
|
console.log();
|
|
1412
1491
|
console.log(` 3. Configure GPU endpoints (if not using defaults):`);
|
|
1413
1492
|
console.log(` ${c.cyan}openclaw config set plugins.entries.clawmem.config.gpuEmbed http://YOUR_GPU:8088${c.reset}`);
|
|
@@ -1417,7 +1496,24 @@ async function cmdSetupOpenClaw(args: string[]) {
|
|
|
1417
1496
|
console.log(` 4. Start the REST API (for agent tools):`);
|
|
1418
1497
|
console.log(` ${c.cyan}clawmem serve &${c.reset}`);
|
|
1419
1498
|
console.log();
|
|
1499
|
+
console.log(`${c.bold}Important: keep dreaming disabled${c.reset}`);
|
|
1500
|
+
console.log(` ClawMem runs its own consolidation workers (CLAWMEM_ENABLE_CONSOLIDATION`);
|
|
1501
|
+
console.log(` light lane and CLAWMEM_HEAVY_LANE heavy lane). Keep ${c.cyan}dreaming.enabled = false${c.reset}`);
|
|
1502
|
+
console.log(` in OpenClaw's memory config to avoid auto-loading the bundled memory-core`);
|
|
1503
|
+
console.log(` dreaming engine alongside ClawMem (#65411 coexistence rule).`);
|
|
1504
|
+
console.log();
|
|
1505
|
+
console.log(`${c.bold}Compaction:${c.reset} OpenClaw's built-in LegacyContextEngine handles compaction`);
|
|
1506
|
+
console.log(`by default. Install a third-party context-engine plugin (hermes-lcm, etc.)`);
|
|
1507
|
+
console.log(`if you want a different compaction strategy. ClawMem injects pre-emptive`);
|
|
1508
|
+
console.log(`precompact state via ${c.cyan}before_prompt_build${c.reset} when token usage approaches the`);
|
|
1509
|
+
console.log(`compaction threshold.`);
|
|
1510
|
+
console.log();
|
|
1420
1511
|
console.log(`${c.dim}ClawMem will work alongside Claude Code hooks — both modes share the same vault.${c.reset}`);
|
|
1512
|
+
|
|
1513
|
+
if (migrationApplied) {
|
|
1514
|
+
console.log();
|
|
1515
|
+
console.log(`${c.green}✓ Upgrade migration applied — restart OpenClaw to pick up the new plugin kind.${c.reset}`);
|
|
1516
|
+
}
|
|
1421
1517
|
}
|
|
1422
1518
|
|
|
1423
1519
|
function findClawmemBinary(): string {
|
|
@@ -1735,6 +1831,37 @@ async function cmdDoctor() {
|
|
|
1735
1831
|
// Skip
|
|
1736
1832
|
}
|
|
1737
1833
|
|
|
1834
|
+
// 8. OpenClaw plugin slot config (§14.3 upgrade migration check)
|
|
1835
|
+
try {
|
|
1836
|
+
const stale = readOpenClawConfigValue("plugins.slots.contextEngine");
|
|
1837
|
+
if (stale === "clawmem") {
|
|
1838
|
+
console.log(
|
|
1839
|
+
`${c.red}✗${c.reset} OpenClaw config: stale ${c.cyan}plugins.slots.contextEngine = "clawmem"${c.reset}`,
|
|
1840
|
+
);
|
|
1841
|
+
console.log(
|
|
1842
|
+
` ${c.dim}ClawMem v0.10.0 is now a memory plugin. Run ${c.cyan}clawmem setup openclaw${c.dim} to migrate,${c.reset}`,
|
|
1843
|
+
);
|
|
1844
|
+
console.log(
|
|
1845
|
+
` ${c.dim}or manually: ${c.cyan}openclaw config set plugins.slots.contextEngine legacy${c.reset}`,
|
|
1846
|
+
);
|
|
1847
|
+
issues++;
|
|
1848
|
+
} else if (stale && stale !== "legacy") {
|
|
1849
|
+
console.log(
|
|
1850
|
+
`${c.green}✓${c.reset} OpenClaw context-engine slot: ${c.cyan}${stale}${c.reset} (third-party LCM)`,
|
|
1851
|
+
);
|
|
1852
|
+
}
|
|
1853
|
+
const memSlot = readOpenClawConfigValue("plugins.slots.memory");
|
|
1854
|
+
if (memSlot === "clawmem") {
|
|
1855
|
+
console.log(`${c.green}✓${c.reset} OpenClaw memory slot: ${c.cyan}clawmem${c.reset}`);
|
|
1856
|
+
} else if (memSlot) {
|
|
1857
|
+
console.log(
|
|
1858
|
+
`${c.dim}-${c.reset} OpenClaw memory slot: ${c.cyan}${memSlot}${c.reset} (ClawMem hooks will not fire under this agent)`,
|
|
1859
|
+
);
|
|
1860
|
+
}
|
|
1861
|
+
} catch {
|
|
1862
|
+
// openclaw CLI unavailable — skip silently
|
|
1863
|
+
}
|
|
1864
|
+
|
|
1738
1865
|
console.log();
|
|
1739
1866
|
if (issues > 0) {
|
|
1740
1867
|
console.log(`${c.yellow}${issues} issue(s) found.${c.reset}`);
|