clawmem 0.14.0 → 0.15.0
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 +165 -716
- package/CLAUDE.md +4 -786
- package/README.md +20 -191
- package/SKILL.md +157 -711
- package/docs/clawmem-architecture.excalidraw +2415 -0
- package/docs/clawmem-architecture.png +0 -0
- package/docs/clawmem_hero.jpg +0 -0
- package/docs/concepts/architecture.md +413 -0
- package/docs/concepts/composite-scoring.md +133 -0
- package/docs/concepts/hooks-vs-mcp.md +156 -0
- package/docs/concepts/multi-vault.md +71 -0
- package/docs/contributing.md +101 -0
- package/docs/guides/cloud-embedding.md +134 -0
- package/docs/guides/hermes-plugin.md +187 -0
- package/docs/guides/inference-services.md +144 -0
- package/docs/guides/multi-vault-config.md +84 -0
- package/docs/guides/openclaw-plugin.md +306 -0
- package/docs/guides/setup-hooks.md +146 -0
- package/docs/guides/setup-mcp.md +76 -0
- package/docs/guides/systemd-services.md +332 -0
- package/docs/guides/upgrading.md +566 -0
- package/docs/internals/entity-resolution.md +135 -0
- package/docs/internals/graph-traversal.md +85 -0
- package/docs/internals/intent-search-pipeline.md +103 -0
- package/docs/internals/query-pipeline.md +100 -0
- package/docs/introduction.md +104 -0
- package/docs/quickstart.md +158 -0
- package/docs/reference/cli.md +195 -0
- package/docs/reference/configuration.md +101 -0
- package/docs/reference/mcp-tools.md +336 -0
- package/docs/reference/rest-api.md +204 -0
- package/docs/troubleshooting.md +330 -0
- package/package.json +2 -1
- package/src/memory.ts +2 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# Hermes Agent MemoryProvider plugin
|
|
2
|
+
|
|
3
|
+
ClawMem integrates with Hermes Agent as a native MemoryProvider plugin, giving Hermes agents the same persistent memory available to Claude Code and OpenClaw. All three runtimes share a single vault, so decisions captured in one are available in the others.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
Hermes scans two directories for memory provider plugins (since Hermes #10529, in v2026.4.13+):
|
|
8
|
+
|
|
9
|
+
1. **User plugins** at `$HERMES_HOME/plugins/<name>/` — typically `~/.hermes/plugins/<name>/`. **Preferred.** Survives `git pull` of hermes-agent and avoids the dual-registration trap that previously caused duplicate tool names with strict providers.
|
|
10
|
+
2. **Bundled plugins** at `hermes-agent/plugins/memory/<name>/` — always supported. Bundled-first precedence on name collisions.
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
# Preferred — user-plugin path
|
|
14
|
+
cp -r /path/to/ClawMem/src/hermes ${HERMES_HOME:-~/.hermes}/plugins/clawmem
|
|
15
|
+
|
|
16
|
+
# Or symlink for development (either path)
|
|
17
|
+
ln -s /path/to/ClawMem/src/hermes ${HERMES_HOME:-~/.hermes}/plugins/clawmem
|
|
18
|
+
|
|
19
|
+
# Bundled-style — only when working in the hermes-agent source tree
|
|
20
|
+
cp -r /path/to/ClawMem/src/hermes /path/to/hermes-agent/plugins/memory/clawmem
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Discovery is heuristic — Hermes looks for `register_memory_provider` or `MemoryProvider` substrings in `__init__.py`. Both are present in `src/hermes/__init__.py`, so the plugin is discovered correctly under either path.
|
|
24
|
+
|
|
25
|
+
Activate via `memory.provider: clawmem` in `~/.hermes/config.yaml` (or run `hermes memory setup` and pick `clawmem`). Memory providers are an exclusive category — exactly one is active at a time, selected via `memory.provider`, completely separate from the general plugin loader.
|
|
26
|
+
|
|
27
|
+
> **Do NOT add `clawmem` to `plugins.enabled` in `config.yaml`.** That list is the general-plugin opt-in roster (Hermes #11xxx onwards made all general plugins opt-in by default). Memory providers have their own activation channel via `memory.provider` and the general loader explicitly skips bundled `plugins/memory/` and treats user-installed memory providers as separate from the standalone-plugin gate. Adding `clawmem` to `plugins.enabled` would make the general loader try to import it as a `kind: standalone` plugin and call `register(ctx)` against the general `PluginContext` — which doesn't expose `register_memory_provider`, so the import errors and the warning gets logged. Harmless but noisy.
|
|
28
|
+
|
|
29
|
+
Verify discovery:
|
|
30
|
+
```bash
|
|
31
|
+
hermes memory list # Should show "clawmem" as available
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Architecture
|
|
35
|
+
|
|
36
|
+
The plugin uses shell-out for lifecycle hooks and REST API for interactive tools:
|
|
37
|
+
|
|
38
|
+
| Component | Transport | Role |
|
|
39
|
+
|-----------|-----------|------|
|
|
40
|
+
| `initialize()` | Shell-out | Create transcript, run `session-bootstrap`, cache bootstrap context |
|
|
41
|
+
| `prefetch()` / `queue_prefetch()` | Shell-out | Prompt-aware retrieval via `context-surfacing` hook (automatic every turn) |
|
|
42
|
+
| `sync_turn()` | Local file I/O | Append user+assistant to plugin-managed transcript JSONL |
|
|
43
|
+
| `on_session_end()` | Shell-out | `decision-extractor`, `handoff-generator`, `feedback-loop` in parallel |
|
|
44
|
+
| `on_pre_compress()` | Shell-out | `precompact-extract` for state preservation |
|
|
45
|
+
| `system_prompt_block()` | In-process | Static provider info and tool names |
|
|
46
|
+
| Agent tools (5) | REST API | `clawmem_retrieve`, `clawmem_get`, `clawmem_session_log`, `clawmem_timeline`, `clawmem_similar` |
|
|
47
|
+
|
|
48
|
+
### Why shell-out for hooks?
|
|
49
|
+
|
|
50
|
+
ClawMem's lifecycle hooks (context-surfacing, decision-extractor, etc.) are Bun/TypeScript programs that read a transcript JSONL file and interact with the SQLite vault directly. The Python plugin shells out to the `clawmem` binary to invoke them, avoiding a cross-language library dependency. This is the same pattern used by the OpenClaw plugin.
|
|
51
|
+
|
|
52
|
+
### Why REST for tools?
|
|
53
|
+
|
|
54
|
+
Interactive tool calls need structured JSON responses and benefit from the REST server's connection pooling. The `clawmem serve` process stays warm, so tool calls complete in milliseconds.
|
|
55
|
+
|
|
56
|
+
### Plugin-managed transcript
|
|
57
|
+
|
|
58
|
+
Hermes passes turn data via `sync_turn(user_content, assistant_content)`, but ClawMem hooks expect a `.jsonl` transcript file. The plugin bridges this by maintaining its own transcript at `$HERMES_HOME/clawmem-transcripts/<session_id>.jsonl`, appending each turn in Claude Code transcript format (`{"type":"message","message":{"role":"...","content":"..."}}`).
|
|
59
|
+
|
|
60
|
+
## Configuration
|
|
61
|
+
|
|
62
|
+
Set in your Hermes profile's `.env` or shell environment:
|
|
63
|
+
|
|
64
|
+
| Variable | Default | Description |
|
|
65
|
+
|----------|---------|-------------|
|
|
66
|
+
| `CLAWMEM_BIN` | auto-detect on PATH | Path to `clawmem` binary |
|
|
67
|
+
| `CLAWMEM_SERVE_PORT` | `7438` | REST API port |
|
|
68
|
+
| `CLAWMEM_SERVE_MODE` | `external` | `external` (you run `clawmem serve`) or `managed` (plugin starts/stops it) |
|
|
69
|
+
| `CLAWMEM_PROFILE` | `balanced` | Retrieval profile: `speed` (BM25 only), `balanced` (hybrid), `deep` (full pipeline) |
|
|
70
|
+
| `CLAWMEM_EMBED_URL` | — | GPU embedding server URL (e.g., `http://localhost:8088`) |
|
|
71
|
+
| `CLAWMEM_LLM_URL` | — | GPU LLM server URL (e.g., `http://localhost:8089`) |
|
|
72
|
+
| `CLAWMEM_LLM_MODEL` | `qwen3` | Model name sent to the GPU/cloud LLM endpoint (e.g., `qwen3`, `gpt-5.4-mini`) |
|
|
73
|
+
| `CLAWMEM_LLM_REASONING_EFFORT` | — | Optional top-level `reasoning_effort` field for Chat Completions endpoints that support it (for example OpenAI reasoning models). Leave unset for llama-server/vLLM unless explicitly supported. |
|
|
74
|
+
| `CLAWMEM_LLM_NO_THINK` | `true` | Append `/no_think` to remote prompts; set to `false` for standard OpenAI models and other endpoints that reject or treat the Qwen-style suffix as literal prompt text |
|
|
75
|
+
| `CLAWMEM_RERANK_URL` | — | GPU reranker server URL (e.g., `http://localhost:8090`) |
|
|
76
|
+
| `CLAWMEM_API_TOKEN` | — | Bearer token for REST API auth (optional, must match `clawmem serve` config) |
|
|
77
|
+
|
|
78
|
+
Or configure interactively:
|
|
79
|
+
```bash
|
|
80
|
+
hermes memory setup # Walks through provider configuration
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Server modes
|
|
84
|
+
|
|
85
|
+
### External (recommended for production)
|
|
86
|
+
|
|
87
|
+
You manage `clawmem serve` yourself, either as a systemd service or a background process:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
clawmem serve --port 7438 &
|
|
91
|
+
# or via systemd — see docs/guides/systemd-services.md
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
The plugin connects to the existing server. If the server is unreachable, tools fail gracefully but hooks still work (shell-out transport).
|
|
95
|
+
|
|
96
|
+
### Managed
|
|
97
|
+
|
|
98
|
+
The plugin starts `clawmem serve` during `initialize()` and stops it on `shutdown()`. Includes a readiness probe (5s health check loop) and early-exit detection.
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
export CLAWMEM_SERVE_MODE=managed
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Suitable for development. Not recommended for production — the process doesn't survive plugin crashes or Hermes restarts.
|
|
105
|
+
|
|
106
|
+
## Agent-context isolation
|
|
107
|
+
|
|
108
|
+
Hermes's `run_agent.py` passes an `agent_context` kwarg to every `MemoryProvider.initialize()` call with one of four values: `"primary"`, `"subagent"`, `"cron"`, or `"flush"`. The `MemoryProvider` ABC docstring is explicit about why this matters: *"Providers should skip writes for non-primary contexts (cron system prompts would corrupt user representations)."*
|
|
109
|
+
|
|
110
|
+
The plugin honours this contract by gating only the **write-side** surfaces — read-side hooks always run so non-primary agents still benefit from retrieval:
|
|
111
|
+
|
|
112
|
+
| Surface | Direction | `agent_context != "primary"` behaviour |
|
|
113
|
+
|---|---|---|
|
|
114
|
+
| `session-bootstrap` (in `initialize`) | Read | Runs — context still surfaced |
|
|
115
|
+
| `prefetch()` / `queue_prefetch()` (`context-surfacing`) | Read | Runs — context still surfaced |
|
|
116
|
+
| `system_prompt_block()` | Read | Runs — provider info still injected |
|
|
117
|
+
| Agent tools (REST) | Read | Runs — agents can still call `clawmem_retrieve` etc. |
|
|
118
|
+
| `sync_turn()` (transcript append) | Write | **Suppressed** |
|
|
119
|
+
| `on_session_end()` (extraction) | Write | **Suppressed** |
|
|
120
|
+
| `on_pre_compress()` (precompact) | Write | **Suppressed** |
|
|
121
|
+
|
|
122
|
+
Net effect: subagents, cron jobs, and flush passes get the benefit of vault recall without contaminating the vault with intermediate state or system-prompt reasoning. The `initialize()` log line records the active context for operator visibility:
|
|
123
|
+
|
|
124
|
+
```
|
|
125
|
+
clawmem: agent_context=cron — reads enabled, writes suppressed
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Hermes built-in memory coexistence
|
|
129
|
+
|
|
130
|
+
Hermes always runs its built-in memory provider (MEMORY.md / USER.md) alongside the external provider. ClawMem is additive — it does not replace or disable built-in memory. Both inject into the context independently.
|
|
131
|
+
|
|
132
|
+
This means some duplication is possible (built-in memory captures a fact, ClawMem extracts the same fact from the transcript). In practice the overlap is minimal because:
|
|
133
|
+
- Built-in memory captures explicit `add_to_memory` tool calls
|
|
134
|
+
- ClawMem captures implicit decisions, handoffs, and patterns from conversation flow
|
|
135
|
+
- Different storage formats (markdown files vs SQLite vault) serve different retrieval strategies
|
|
136
|
+
|
|
137
|
+
`on_memory_write()` is intentionally a no-op in v1 to avoid amplifying duplication.
|
|
138
|
+
|
|
139
|
+
## Shared vault across frameworks
|
|
140
|
+
|
|
141
|
+
Claude Code, OpenClaw, and Hermes all access the same SQLite vault file (`~/.cache/clawmem/index.sqlite` by default). A decision captured in a Claude Code session is visible to Hermes agents, and vice versa.
|
|
142
|
+
|
|
143
|
+
SQLite WAL mode + `busy_timeout=5000ms` handles concurrent access. The plugin-managed transcript is stored separately under `$HERMES_HOME/clawmem-transcripts/` and does not affect the shared vault.
|
|
144
|
+
|
|
145
|
+
## What needs to be running
|
|
146
|
+
|
|
147
|
+
| Service | Purpose | Managed by |
|
|
148
|
+
|---------|---------|------------|
|
|
149
|
+
| `clawmem serve` | REST API for agent tools | External (systemd) or managed (plugin) |
|
|
150
|
+
| `clawmem-watcher` | Auto-index on file changes | [systemd](systemd-services.md#watcher-service) |
|
|
151
|
+
| `clawmem-embed.timer` | Daily embedding sweep | [systemd](systemd-services.md#embed-timer) |
|
|
152
|
+
| GPU servers (optional) | Embedding, LLM, reranker | [systemd](systemd-services.md#gpu-service-units) or in-process fallback |
|
|
153
|
+
|
|
154
|
+
## Verify
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
# Plugin discovered
|
|
158
|
+
hermes memory list | grep clawmem
|
|
159
|
+
|
|
160
|
+
# REST API responding
|
|
161
|
+
curl http://localhost:7438/health
|
|
162
|
+
|
|
163
|
+
# Hooks working
|
|
164
|
+
clawmem status
|
|
165
|
+
|
|
166
|
+
# Watcher active
|
|
167
|
+
systemctl --user status clawmem-watcher.service
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## Lifecycle mapping reference
|
|
171
|
+
|
|
172
|
+
| Hermes MemoryProvider | ClawMem equivalent | Notes |
|
|
173
|
+
|---|---|---|
|
|
174
|
+
| `is_available()` | PATH check for `clawmem` binary | No network calls |
|
|
175
|
+
| `initialize(session_id, **kwargs)` | `session-bootstrap` hook | Creates transcript, caches bootstrap context. Reads `agent_context` and `hermes_home` from kwargs. Other kwargs Hermes passes (`platform`, `agent_identity`, `agent_workspace`, `parent_session_id`, `user_id`, `gateway_session_key`, `session_title`) are absorbed via `**kwargs` and currently unused. |
|
|
176
|
+
| `system_prompt_block()` | Static text | Provider active, tool names |
|
|
177
|
+
| `prefetch(query)` | `context-surfacing` hook output | Returns cached result from background thread |
|
|
178
|
+
| `queue_prefetch(query)` | `context-surfacing` hook | Background thread, generation-safe |
|
|
179
|
+
| `sync_turn(user, assistant)` | Transcript JSONL append | Bridges Hermes turn pairs to ClawMem file format. Suppressed when `agent_context != "primary"`. |
|
|
180
|
+
| `on_turn_start()` | — | Not overridden — base no-op |
|
|
181
|
+
| `on_session_end(messages)` | `decision-extractor` + `handoff-generator` + `feedback-loop` | Parallel, 30s timeout each. Suppressed when `agent_context != "primary"`. |
|
|
182
|
+
| `on_pre_compress(messages)` | `precompact-extract` | Side effect only (Hermes ignores return). Suppressed when `agent_context != "primary"`. |
|
|
183
|
+
| `on_memory_write()` | No-op | Avoids duplication with built-in memory (filesystem watcher already indexes MEMORY.md / USER.md if they live under a configured collection). |
|
|
184
|
+
| `on_delegation()` | No-op | Subagent observation handled at the parent's primary context already; nothing useful to add here. |
|
|
185
|
+
| `get_tool_schemas()` | 5 REST-backed tools | retrieve, get, session_log, timeline, similar |
|
|
186
|
+
| `handle_tool_call()` | REST API dispatch | Bearer auth when `CLAWMEM_API_TOKEN` is set |
|
|
187
|
+
| `shutdown()` | Thread cleanup + managed serve stop | Joins prefetch thread, terminates managed process |
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# Inference services — choosing and running your stack
|
|
2
|
+
|
|
3
|
+
ClawMem uses three inference services: **embedding**, **LLM** (query expansion / intent classification / A-MEM enrichment), and **reranker** (cross-encoder). In the **default** stack all three run as `llama-server` (llama.cpp) instances, each with an in-process `node-llama-cpp` fallback that auto-downloads on first use — so ClawMem works with no manual setup and no dedicated GPU. The `bin/clawmem` wrapper points the three endpoint vars at `localhost:8088` (embedding), `localhost:8089` (LLM), `localhost:8090` (reranker) by default.
|
|
4
|
+
|
|
5
|
+
> **Always run ClawMem via the `bin/clawmem` wrapper.** It exports the endpoint defaults. Invoking `bun run src/clawmem.ts` directly skips them and silently falls back to in-process CPU inference (slow). For remote GPU, add the same vars to your systemd units — see [systemd-services.md](systemd-services.md).
|
|
6
|
+
|
|
7
|
+
## Choosing your inference stack
|
|
8
|
+
|
|
9
|
+
Three stacks, picked by hardware, license, and quality needs. This is the decision; the rest of this guide is how to run each.
|
|
10
|
+
|
|
11
|
+
| Stack | Models | VRAM | License | Retrieval quality / context | Pick when |
|
|
12
|
+
|---|---|---|---|---|---|
|
|
13
|
+
| **QMD native** (default) | EmbeddingGemma-300M (768d) + qmd-query-expansion-1.7B + qwen3-reranker-0.6B | ~4 GB total, or **in-process** (Metal/Vulkan/CPU) | **Permissive — commercial OK** | Good · 2K embed context | Any GPU **or no GPU**; **commercial use**; zero-config start (auto-downloads) |
|
|
14
|
+
| **z / SOTA** | zembed-1 (2560d, zELO-distilled from zerank-2) + qmd-query-expansion-1.7B + zerank-2 seq-cls **sidecar** (bf16) | ~16 GB (4.4 + 2.2 + 9) | **CC-BY-NC-4.0 — non-commercial only** | Best (zerank-2 NDCG@10 ahead of Cohere rerank-3.5) · 32K embed context | 16 GB+ GPU **and** non-commercial; want top recall |
|
|
15
|
+
| **Cloud embedding** | Jina v5-text-small (1024d, rec.) / OpenAI / Voyage / Cohere — **embedding only** | none (embedding) | provider ToS | provider-dependent · up to 128K (Cohere) | No local GPU for embedding, or prefer managed. **LLM + reranker still run local/in-process.** |
|
|
16
|
+
|
|
17
|
+
**Decision axes:** VRAM budget · license (commercial vs non-commercial) · retrieval quality · context length. The default native stack is the right starting point for most users and the only stack with no licensing restriction; upgrade to the z-stack only with a 16 GB+ GPU and a non-commercial use case; use cloud embedding when you have no local GPU to spare for embeddings.
|
|
18
|
+
|
|
19
|
+
## Landmines (read before serving)
|
|
20
|
+
|
|
21
|
+
- **The zerank-2 GGUF is deprecated and inert.** llama.cpp's converter drops zerank's CrossEncoder/LogitScore head, so under `--reranking` it returns HTTP 200 with near-zero, non-discriminating scores — the final ordering silently collapses to RRF. Serve the SOTA reranker via the **seq-cls sidecar** (`extras/rerankers/zerank-2-seq/`), never as a GGUF. Run `clawmem rerank-health` to confirm a reranker actually discriminates (liveness ≠ correctness).
|
|
22
|
+
- **`-ub` must equal `-b`** for embedding/reranking models (non-causal attention) or `llama-server` asserts (`non-causal attention requires n_ubatch >= n_tokens`). The zerank-2 sidecar is transformers-served and exempt; the qwen3-reranker GGUF does not need it. See [llama.cpp#12836](https://github.com/ggml-org/llama.cpp/issues/12836).
|
|
23
|
+
- **Changing embedding dimensions requires a full re-embed:** `clawmem embed --force` (idempotent, safe to interrupt/resume).
|
|
24
|
+
- **Set `CLAWMEM_NO_LOCAL_MODELS=true`** for remote-only / dedicated-server setups to fail fast on an unreachable endpoint instead of silently auto-downloading multi-GB GGUFs and running CPU inference.
|
|
25
|
+
|
|
26
|
+
## Default stack — QMD native (any GPU or in-process)
|
|
27
|
+
|
|
28
|
+
Total ~4 GB VRAM, or runs in-process via `node-llama-cpp` (Metal on Apple Silicon, Vulkan where available, CPU as last resort — fast with GPU acceleration, significantly slower CPU-only). All three auto-download on first use if no server is running.
|
|
29
|
+
|
|
30
|
+
| Service | Port | Model | VRAM | Purpose |
|
|
31
|
+
|---|---|---|---|---|
|
|
32
|
+
| Embedding | 8088 | [EmbeddingGemma-300M-Q8_0](https://huggingface.co/ggml-org/embeddinggemma-300M-GGUF) (314 MB, 768d, 2K ctx) | ~400 MB | Vector search, indexing, context-surfacing |
|
|
33
|
+
| LLM | 8089 | [qmd-query-expansion-1.7B-q4_k_m](https://huggingface.co/tobil/qmd-query-expansion-1.7B-gguf) (~1.1 GB) | ~2.2 GB | Intent classification, query expansion, A-MEM |
|
|
34
|
+
| Reranker | 8090 | [qwen3-reranker-0.6B-Q8_0](https://huggingface.co/ggml-org/Qwen3-Reranker-0.6B-Q8_0-GGUF) (~600 MB) | ~1.3 GB | Cross-encoder reranking |
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
# Embedding (--embeddings flag required)
|
|
38
|
+
llama-server -m embeddinggemma-300M-Q8_0.gguf \
|
|
39
|
+
--embeddings --port 8088 --host 0.0.0.0 -ngl 99 -c 2048 --batch-size 2048
|
|
40
|
+
|
|
41
|
+
# LLM (QMD finetuned model)
|
|
42
|
+
llama-server -m qmd-query-expansion-1.7B-q4_k_m.gguf \
|
|
43
|
+
--port 8089 --host 0.0.0.0 -ngl 99 -c 4096 --batch-size 512
|
|
44
|
+
|
|
45
|
+
# Reranker
|
|
46
|
+
llama-server -m Qwen3-Reranker-0.6B-Q8_0.gguf \
|
|
47
|
+
--reranking --port 8090 --host 0.0.0.0 -ngl 99 -c 2048 --batch-size 512
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
On CPU, omit `-ngl 99`. If a server is unreachable (ECONNREFUSED/ETIMEDOUT), ClawMem sets a 60-second cooldown and falls back to in-process inference; HTTP 4xx/5xx and user-cancelled requests do not trigger cooldown.
|
|
51
|
+
|
|
52
|
+
## SOTA stack — z models (16 GB+ GPU, CC-BY-NC-4.0, non-commercial only)
|
|
53
|
+
|
|
54
|
+
ZeroEntropy's distillation-paired stack — best retrieval quality, total ~16 GB VRAM. zembed-1 is distilled from zerank-2 via [zELO](https://docs.zeroentropy.dev), so the pair is mutually optimal.
|
|
55
|
+
|
|
56
|
+
| Service | Port | Model | VRAM | Purpose |
|
|
57
|
+
|---|---|---|---|---|
|
|
58
|
+
| Embedding | 8088 | [zembed-1-Q4_K_M](https://huggingface.co/Abhiray/zembed-1-Q4_K_M-GGUF) (2.4 GB, 2560d, 32K ctx) | ~4.4 GB | SOTA embedding |
|
|
59
|
+
| LLM | 8089 | qmd-query-expansion-1.7B-q4_k_m | ~2.2 GB | (same as default) |
|
|
60
|
+
| Reranker | 8090 | [zerank-2 seq-cls sidecar](../../extras/rerankers/zerank-2-seq/) (transformers, bf16) | ~9 GB | SOTA reranker — **not** a GGUF |
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
# Embedding (zembed-1) — -ub MUST equal -b for non-causal attention
|
|
64
|
+
llama-server -m zembed-1-Q4_K_M.gguf \
|
|
65
|
+
--embeddings --port 8088 --host 0.0.0.0 -ngl 99 -c 8192 -b 2048 -ub 2048
|
|
66
|
+
|
|
67
|
+
# Reranker (zerank-2) — seq-cls SIDECAR (transformers, bf16), NOT a llama-server GGUF:
|
|
68
|
+
cd extras/rerankers/zerank-2-seq
|
|
69
|
+
docker compose build
|
|
70
|
+
HF_TOKEN=hf_xxx docker compose run --rm convert # download + convert + verify (all gates must pass)
|
|
71
|
+
docker compose up -d reranker # serves /v1/rerank on :8090
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Embedding (detail)
|
|
75
|
+
|
|
76
|
+
ClawMem calls the OpenAI-compatible `/v1/embeddings` endpoint for all embedding operations — works with local `llama-server` and cloud providers alike.
|
|
77
|
+
|
|
78
|
+
- **GPU with VRAM to spare:** zembed-1 (Option above) — SOTA, multilingual out of the box.
|
|
79
|
+
- **No GPU / limited VRAM:** EmbeddingGemma-300M-Q8_0 (Option above). For a lightweight multilingual alternative use [granite-embedding-278m-multilingual-Q6_K](https://huggingface.co/bartowski/granite-embedding-278m-multilingual-GGUF) (314 MB; set `CLAWMEM_EMBED_MAX_CHARS=1100` for its 512-token context).
|
|
80
|
+
- **Cloud:** any OpenAI-compatible `/v1/embeddings` provider — Jina (recommended `jina-embeddings-v5-text-small`, 1024d), OpenAI, Voyage, Cohere. Full provider matrix, batch/TPM behavior, and per-provider params are in [cloud-embedding.md](cloud-embedding.md).
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
# Verify an embedding endpoint is reachable
|
|
84
|
+
curl $CLAWMEM_EMBED_URL/v1/embeddings \
|
|
85
|
+
-H "Content-Type: application/json" \
|
|
86
|
+
-H "Authorization: Bearer $CLAWMEM_EMBED_API_KEY" \
|
|
87
|
+
-d "{\"input\":\"test\",\"model\":\"$CLAWMEM_EMBED_MODEL\"}"
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## LLM server
|
|
91
|
+
|
|
92
|
+
Intent classification, query expansion, and A-MEM extraction use [qmd-query-expansion-1.7B](https://huggingface.co/tobil/qmd-query-expansion-1.7B-gguf) — a Qwen3-1.7B finetuned by QMD for generating search-expansion terms (hyde, lexical, vector variants). ~1.1 GB at q4_k_m, served on port 8089. If `CLAWMEM_LLM_URL` is unset, `node-llama-cpp` auto-downloads it.
|
|
93
|
+
|
|
94
|
+
- **Performance (RTX 3090):** intent classification ~27 ms; query expansion ~333 tok/s; VRAM ~2.2–2.8 GB.
|
|
95
|
+
- **Qwen3 `/no_think`:** Qwen3 emits thinking tokens by default; ClawMem appends `/no_think` to all prompts automatically for structured output.
|
|
96
|
+
- **Dual-path intent:** a heuristic regex classifier handles strong why/when/who signals instantly (0.8+ confidence); the LLM refines only ambiguous queries below that threshold.
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
llama-server -m qmd-query-expansion-1.7B-q4_k_m.gguf \
|
|
100
|
+
--port 8089 --host 0.0.0.0 -ngl 99 -c 4096 --batch-size 512
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
For better entity-extraction quality during `reindex --enrich`, point `CLAWMEM_LLM_URL` at a 7B+ model or cloud API (see [../internals/entity-resolution.md](../internals/entity-resolution.md)).
|
|
104
|
+
|
|
105
|
+
## Reranker server
|
|
106
|
+
|
|
107
|
+
Cross-encoder reranking for the `query` (4000-char context, deep) and `intent_search` (200-char context, fast) pipelines on port 8090, via the `/v1/rerank` endpoint.
|
|
108
|
+
|
|
109
|
+
- **GPU with VRAM to spare:** the zerank-2 seq-cls sidecar (recipe above). **CC-BY-NC-4.0.**
|
|
110
|
+
- **CPU / limited VRAM:** qwen3-reranker-0.6B-Q8_0 (~600 MB, ~1.3 GB VRAM), the QMD native reranker — auto-downloaded if no server is running.
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
llama-server -m Qwen3-Reranker-0.6B-Q8_0.gguf \
|
|
114
|
+
--reranking --port 8090 --host 0.0.0.0 -ngl 99 -c 2048 --batch-size 512
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
See the landmines above: the zerank-2 **GGUF is inert** (use the sidecar), and verify discrimination with `clawmem rerank-health`.
|
|
118
|
+
|
|
119
|
+
## Remote GPU
|
|
120
|
+
|
|
121
|
+
If the GPU lives on a separate machine, point the env vars at it and disable local fallback:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
export CLAWMEM_EMBED_URL=http://gpu-host:8088
|
|
125
|
+
export CLAWMEM_LLM_URL=http://gpu-host:8089
|
|
126
|
+
export CLAWMEM_LLM_MODEL=qwen3
|
|
127
|
+
export CLAWMEM_RERANK_URL=http://gpu-host:8090
|
|
128
|
+
export CLAWMEM_NO_LOCAL_MODELS=true # fail fast instead of auto-downloading multi-GB GGUFs
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Verify endpoints
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
curl http://host:8088/v1/embeddings -d '{"input":"test","model":"embedding"}' -H 'Content-Type: application/json'
|
|
135
|
+
curl http://host:8089/v1/models
|
|
136
|
+
curl http://host:8090/v1/models
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## See also
|
|
140
|
+
|
|
141
|
+
- **Cloud embedding** — provider matrix, batch embedding, TPM-aware pacing, per-provider params → [cloud-embedding.md](cloud-embedding.md)
|
|
142
|
+
- **All environment variables** (endpoints, profiles, consolidation, merge gates) → [../reference/configuration.md](../reference/configuration.md)
|
|
143
|
+
- **Keeping servers up** (systemd units, GPU env in services) → [systemd-services.md](systemd-services.md)
|
|
144
|
+
- **Reranker health** — the degenerate-reranker failure mode and `clawmem rerank-health` → [../troubleshooting.md](../troubleshooting.md)
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Multi-vault configuration
|
|
2
|
+
|
|
3
|
+
Step-by-step guide for setting up multiple independent ClawMem vaults to isolate AI agent memory by project or team.
|
|
4
|
+
|
|
5
|
+
## 1. Define vaults
|
|
6
|
+
|
|
7
|
+
Edit `~/.config/clawmem/config.yaml`:
|
|
8
|
+
|
|
9
|
+
```yaml
|
|
10
|
+
vaults:
|
|
11
|
+
work: ~/.cache/clawmem/work.sqlite
|
|
12
|
+
personal: ~/.cache/clawmem/personal.sqlite
|
|
13
|
+
research: ~/data/research-vault.sqlite
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Or use the environment variable:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
export CLAWMEM_VAULTS='{"work":"~/.cache/clawmem/work.sqlite","personal":"~/.cache/clawmem/personal.sqlite"}'
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Paths support `~` expansion. Environment variables override config file values.
|
|
23
|
+
|
|
24
|
+
## 2. Populate vaults
|
|
25
|
+
|
|
26
|
+
Use `vault_sync` via MCP or CLI:
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
vault_sync(vault="work", content_root="~/projects/work-notes")
|
|
30
|
+
vault_sync(vault="personal", content_root="~/notes/personal")
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Or add collections to a vault manually:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
INDEX_PATH=~/.cache/clawmem/work.sqlite ./bin/clawmem collection add ~/projects/work-notes --name work-notes
|
|
37
|
+
INDEX_PATH=~/.cache/clawmem/work.sqlite ./bin/clawmem update --embed
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## 3. Embed vault content
|
|
41
|
+
|
|
42
|
+
Each vault needs its own embedding pass:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
INDEX_PATH=~/.cache/clawmem/work.sqlite ./bin/clawmem embed
|
|
46
|
+
INDEX_PATH=~/.cache/clawmem/personal.sqlite ./bin/clawmem embed
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## 4. Query vaults
|
|
50
|
+
|
|
51
|
+
All MCP tools accept `vault`:
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
# Search work vault
|
|
55
|
+
query("API authentication flow", vault="work", compact=true)
|
|
56
|
+
|
|
57
|
+
# Check personal vault lifecycle
|
|
58
|
+
lifecycle_status(vault="personal")
|
|
59
|
+
|
|
60
|
+
# Pin something in research vault
|
|
61
|
+
memory_pin("important finding", vault="research")
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## 5. List configured vaults
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
list_vaults()
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
Configured vaults (2):
|
|
74
|
+
work: /home/user/.cache/clawmem/work.sqlite
|
|
75
|
+
personal: /home/user/.cache/clawmem/personal.sqlite
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Notes
|
|
79
|
+
|
|
80
|
+
- The default (unnamed) vault at `~/.cache/clawmem/index.sqlite` always exists and is used when `vault` is omitted
|
|
81
|
+
- Hooks always operate on the default vault
|
|
82
|
+
- Named vault stores are cached in memory and reused across tool calls
|
|
83
|
+
- Each vault is fully independent — separate documents, embeddings, graphs, and sessions
|
|
84
|
+
- `vault_sync` validates paths against a deny-list (rejects `/etc/`, `.ssh`, `.env`, `credentials`, etc.)
|