clawmem 0.20.2 → 0.22.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 +6 -6
- package/README.md +6 -3
- package/SKILL.md +6 -6
- package/docs/concepts/architecture.md +1 -1
- package/docs/concepts/composite-scoring.md +6 -4
- package/docs/guides/inference-services.md +11 -2
- package/docs/guides/upgrading.md +33 -3
- package/docs/introduction.md +1 -1
- package/docs/quickstart.md +1 -1
- package/docs/reference/cli.md +5 -3
- package/docs/reference/configuration.md +1 -0
- package/docs/reference/mcp-tools.md +15 -2
- package/docs/troubleshooting.md +7 -4
- package/package.json +1 -1
- package/src/busy-retry.ts +34 -0
- package/src/canary.ts +364 -0
- package/src/clawmem.ts +271 -22
- package/src/config.ts +29 -1
- package/src/graph-traversal.ts +32 -4
- package/src/mcp.ts +207 -63
- package/src/memory.ts +1 -0
- package/src/scoring-regime.ts +79 -0
- package/src/store.ts +366 -32
package/AGENTS.md
CHANGED
|
@@ -59,7 +59,7 @@ clawmem doctor # full health check (clawmem status
|
|
|
59
59
|
| `feedback-loop` | Stop | tracks referenced notes → confidence boosts, co-activations, utility signals |
|
|
60
60
|
|
|
61
61
|
**Default behavior:** read injected `<vault-context>` first; if sufficient, answer immediately.
|
|
62
|
-
**Blind spots (by design):** hooks filter `_clawmem/` artifacts, enforce score thresholds, cap token budget — **absence in `<vault-context>` does NOT mean absence in memory.** If expected memory wasn't surfaced, escalate to Tier 3.
|
|
62
|
+
**Blind spots (by design):** hooks filter `_clawmem/` artifacts, enforce score thresholds, cap token budget — **absence in `<vault-context>` does NOT mean absence in memory.** If expected memory wasn't surfaced, escalate to Tier 3. Note the MCP retrieval tools themselves exclude `_clawmem` by default since v0.21.0 — pass `includeInternal: true` when system-internal memory (observations/handoffs/deductions) is the target.
|
|
63
63
|
**Profiles:** `speed` / `balanced` (default) / `deep` set the kept-score ratio (65% / 55% / 45%) + an activation floor; only `deep` adds query expansion + reranking to the hook path. → [docs/concepts/hooks-vs-mcp.md](docs/concepts/hooks-vs-mcp.md).
|
|
64
64
|
|
|
65
65
|
### Tier 3 — agent-initiated (one targeted MCP call)
|
|
@@ -105,7 +105,7 @@ All other retrieval is handled by Tier 2 hooks. **Do NOT call MCP tools speculat
|
|
|
105
105
|
| `kg_query` | Entity SPO triples with temporal validity. Entity facts, NOT causal "why". |
|
|
106
106
|
| `session_log` | "last time" / "yesterday" / "what did we do". Do NOT use `query` for cross-session. |
|
|
107
107
|
| `profile` | User profile (static facts + dynamic context). |
|
|
108
|
-
| `memory_pin` | +0.3 composite boost. PROACTIVELY for constraints, architecture decisions, corrections. |
|
|
108
|
+
| `memory_pin` | Lifecycle retention + priority among relevance-equivalent results (+0.3 composite boost on composite surfaces; exact-tie precedence on raw vector routes). PROACTIVELY for constraints, architecture decisions, corrections. |
|
|
109
109
|
| `memory_snooze` | PROACTIVELY when `<vault-context>` surfaces noise — snooze 30 days. |
|
|
110
110
|
| `memory_forget` | Deactivate a memory by closest match. Sparingly — prefer snooze. |
|
|
111
111
|
| `build_graphs` | Temporal backbone + semantic graph after bulk ingestion. NOT after every reindex. |
|
|
@@ -135,14 +135,14 @@ The pipeline autonomously generates lex/vec/hyde variants, fuses BM25 + vector v
|
|
|
135
135
|
|
|
136
136
|
## Composite scoring
|
|
137
137
|
|
|
138
|
-
Applied
|
|
138
|
+
Applied on the composite surfaces: hooks, `query`, `search`, and `memory_retrieve`'s keyword/hybrid/causal/complex modes. **v0.22.0: MCP `vsearch` and `memory_retrieve` semantic/discovery rank non-recency queries by RAW cosine instead** (`scoreBasis: "vector-cosine"`; metadata breaks exact ties only; `minScore` filters raw with no default); recency-intent queries keep composite everywhere.
|
|
139
139
|
|
|
140
140
|
```
|
|
141
141
|
compositeScore = (0.50·searchScore + 0.25·recencyScore + 0.25·confidenceScore) × qualityMultiplier × coActivationBoost
|
|
142
142
|
```
|
|
143
143
|
|
|
144
|
-
- `qualityMultiplier = 0.7 + 0.6·qualityScore` (0.7× … 1.3×); `coActivationBoost` up to +15%; length-normalized (floor 30%); frequency boost capped +10%; **pinned docs +0.3 additive
|
|
145
|
-
- **`query` tool (v0.13.0+):** non-recency queries use **0.70·search + 0.15·recency + 0.15·confidence**. `search
|
|
144
|
+
- `qualityMultiplier = 0.7 + 0.6·qualityScore` (0.7× … 1.3×); `coActivationBoost` up to +15%; length-normalized (floor 30%); frequency boost capped +10%; **pinned docs +0.3 additive on composite surfaces** (raw vector routes: pin = exact-tie precedence only).
|
|
145
|
+
- **`query` tool (v0.13.0+):** non-recency queries use **0.70·search + 0.15·recency + 0.15·confidence**. `search`, `memory_retrieve`'s composite modes, and context-surfacing keep the 0.50/0.25/0.25 default. (`vsearch` + `memory_retrieve` semantic/discovery use RAW cosine for non-recency queries as of v0.22.0 — no composite weights at all.)
|
|
146
146
|
- **Recency intent** ("latest"/"recent"/"last session") switches all to **0.10·search + 0.70·recency + 0.20·confidence**.
|
|
147
147
|
- **Half-lives:** decision/deductive/preference/hub/antipattern = ∞ · project 120d · research 90d · problem/milestone/note 60d · conversation/progress 45d · handoff 30d (extend up to 3× for frequently-accessed).
|
|
148
148
|
|
|
@@ -162,7 +162,7 @@ compositeScore = (0.50·searchScore + 0.25·recencyScore + 0.25·confidenceScore
|
|
|
162
162
|
|
|
163
163
|
## Memory lifecycle (pin / snooze / forget — manual tools)
|
|
164
164
|
|
|
165
|
-
- **`memory_pin`** (+0.3 boost,
|
|
165
|
+
- **`memory_pin`** (lifecycle retention + priority among relevance-equivalent results; +0.3 boost on composite surfaces, exact-tie precedence on raw vector routes) — PROACTIVELY when: user says "remember this"/"important"; an architecture/critical decision was just made; a user preference/constraint should persist. Do NOT pin routine/session-specific items.
|
|
166
166
|
- **`memory_snooze`** — PROACTIVELY when a memory keeps surfacing but isn't relevant now, user says "not now"/"later", or content is time-boxed.
|
|
167
167
|
- **`memory_forget`** — only when genuinely wrong or permanently obsolete. Prefer snooze for temporary suppression.
|
|
168
168
|
- **Contradiction auto-resolution:** when `decision-extractor` detects a new decision contradicting an old one, the old one's confidence is lowered automatically — no manual action needed.
|
package/README.md
CHANGED
|
@@ -531,6 +531,8 @@ clawmem status Quick index status
|
|
|
531
531
|
|
|
532
532
|
Registered by `clawmem setup mcp`. Available to any MCP-compatible client.
|
|
533
533
|
|
|
534
|
+
**Internal-collection visibility (v0.21.0):** the retrieval tools `search`, `vsearch`, `query`, `query_plan`, `memory_retrieve`, and `find_similar` exclude the system-internal `_clawmem` collection by default — pass `includeInternal: true` (or name `_clawmem` in an explicit `collection` filter where the tool has one) to include it. `find_similar` auto-includes internal neighbors when the reference document is itself internal; `intent_search`, `find_causal_links`, `kg_query`, `session_log`, and `timeline` are unfiltered by design. Full contract (including the `degraded` under-fill markers): [docs/reference/mcp-tools.md](docs/reference/mcp-tools.md).
|
|
535
|
+
|
|
534
536
|
| Tool | Description |
|
|
535
537
|
|---|---|
|
|
536
538
|
| `__IMPORTANT` | Workflow guide: prefer `memory_retrieve` → match query type to tool → `multi_get` for full content |
|
|
@@ -541,7 +543,7 @@ Registered by `clawmem setup mcp`. Available to any MCP-compatible client.
|
|
|
541
543
|
|---|---|
|
|
542
544
|
| `memory_retrieve` | **Preferred entry point.** Auto-classifies query and routes to optimal backend (query, intent_search, session_log, find_similar, or query_plan). Use instead of manually choosing a search tool. |
|
|
543
545
|
| `search` | BM25 keyword search — for exact terms, config names, error codes, filenames. Composite scoring + co-activation boost + compact mode. Collection filter supports comma-separated values. Prefer `memory_retrieve` for auto-routing. |
|
|
544
|
-
| `vsearch` | Vector semantic search — for conceptual/fuzzy matching when exact keywords are unknown.
|
|
546
|
+
| `vsearch` | Vector semantic search — for conceptual/fuzzy matching when exact keywords are unknown. **v0.22.0: non-recency queries rank by RAW cosine (`scoreBasis: "vector-cosine"`; metadata breaks exact ties only; `minScore` filters raw with no default)**; recency-intent queries keep composite. Collection filter supports comma-separated values. Prefer `memory_retrieve` for auto-routing. |
|
|
545
547
|
| `query` | Full hybrid pipeline (BM25 + vector + rerank) — general-purpose when query type is unclear. WRONG for "why" questions (use `intent_search`) or cross-session queries (use `session_log`). Prefer `memory_retrieve` for auto-routing. Intent hint, strong-signal bypass, chunk dedup, candidateLimit, MMR diversity, compact mode. |
|
|
546
548
|
| `get` | Retrieve single document by path or docid |
|
|
547
549
|
| `multi_get` | Retrieve multiple docs by glob or comma-separated list |
|
|
@@ -593,7 +595,7 @@ Registered by `clawmem setup mcp`. Available to any MCP-compatible client.
|
|
|
593
595
|
| Tool | Description |
|
|
594
596
|
|---|---|
|
|
595
597
|
| `memory_forget` | Search → deactivate closest match (with audit trail) |
|
|
596
|
-
| `memory_pin` | Pin a memory
|
|
598
|
+
| `memory_pin` | Pin a memory: lifecycle retention + priority among relevance-equivalent results (+0.3 composite boost on hook/`query`/`search` surfaces; exact-tie precedence on the raw vector routes). USE PROACTIVELY when: user states a persistent constraint, makes an architecture decision, or corrects a misconception. Don't wait for curator — pin critical decisions immediately. |
|
|
597
599
|
| `memory_snooze` | Temporarily hide a memory from context surfacing until a date. USE PROACTIVELY when `<vault-context>` repeatedly surfaces irrelevant content — snooze for 30 days instead of ignoring it. |
|
|
598
600
|
| `status` | Index health with content type distribution |
|
|
599
601
|
| `reindex` | Trigger vault re-scan |
|
|
@@ -693,7 +695,7 @@ Content types are inferred from frontmatter or file path patterns. Half-lives ex
|
|
|
693
695
|
|
|
694
696
|
**Frequency boost:** Documents with higher revision counts or duplicate counts get a durability signal: `freqSignal = (revisions - 1) × 2 + (duplicates - 1)`, `freqBoost = min(0.10, log1p(freqSignal) × 0.03)`. Revision count (content evolution) is weighted 2× vs duplicate count (ingest repetition). Capped at 10%.
|
|
695
697
|
|
|
696
|
-
**Pin boost:**
|
|
698
|
+
**Pin boost:** Pin = lifecycle retention + priority among relevance-equivalent results. On composite surfaces pinned documents get a +0.3 additive boost (capped at 1.0); on the raw vector routes (v0.22.0) pin breaks exact raw-score ties only. Use `memory_pin` to pin critical memories.
|
|
697
699
|
|
|
698
700
|
**Snooze:** Snoozed documents are filtered out of context surfacing until their snooze date. Use `memory_snooze` for temporary suppression.
|
|
699
701
|
|
|
@@ -789,6 +791,7 @@ Notes referenced by the agent during a session get boosted (`access_count++`). U
|
|
|
789
791
|
| `CLAWMEM_RERANK_URL` | `http://localhost:8090` | Reranker server URL. Without it, falls to `node-llama-cpp` (if allowed). |
|
|
790
792
|
| `CLAWMEM_RERANK_API_KEY` | (none) | Bearer token for an authenticated remote reranker endpoint. Independent of the embed and LLM keys. |
|
|
791
793
|
| `CLAWMEM_NO_LOCAL_MODELS` | `false` | Block `node-llama-cpp` from auto-downloading GGUF models. Set `true` for remote-only setups where you want fail-fast on unreachable endpoints. |
|
|
794
|
+
| `CLAWMEM_MCP_DIRECT_TUNED_WEIGHTS` | (superseded) | **No effect since v0.22.0** — the direct-pipeline eval this knob was gated on measured tuned weights at 1/19 hit@1; the direct vector routes rank by raw cosine instead. Still parsed for backward compatibility; setting it logs a once-per-process warning. |
|
|
792
795
|
| `CLAWMEM_MERGE_SCORE_NORMAL` | `0.93` | **v0.7.1.** Phase 2 consolidation merge-safety threshold when candidate and existing anchors align. Merges above this normalized 3-gram cosine score are allowed. |
|
|
793
796
|
| `CLAWMEM_MERGE_SCORE_STRICT` | `0.98` | **v0.7.1.** Strictest merge-safety threshold — fallback when anchor sets are ambiguous. |
|
|
794
797
|
| `CLAWMEM_MERGE_GUARD_DRY_RUN` | `false` | **v0.7.1.** When `true`, Phase 2 merge-safety rejections are logged but not enforced — use for calibration before enabling the gate. |
|
package/SKILL.md
CHANGED
|
@@ -35,7 +35,7 @@ Hooks handle ~90% of retrieval at zero agent effort.
|
|
|
35
35
|
|
|
36
36
|
**Default behavior:** read injected `<vault-context>` first; if sufficient, answer immediately.
|
|
37
37
|
|
|
38
|
-
**Hook blind spots (by design):** hooks filter `_clawmem/` artifacts, enforce score thresholds, and cap token budget — **absence in `<vault-context>` does NOT mean absence in memory.** If expected memory wasn't surfaced, escalate to Tier 3.
|
|
38
|
+
**Hook blind spots (by design):** hooks filter `_clawmem/` artifacts, enforce score thresholds, and cap token budget — **absence in `<vault-context>` does NOT mean absence in memory.** If expected memory wasn't surfaced, escalate to Tier 3. Note the MCP retrieval tools themselves exclude `_clawmem` by default since v0.21.0 — pass `includeInternal: true` when system-internal memory (observations/handoffs/deductions) is the target.
|
|
39
39
|
|
|
40
40
|
**Profiles:** `speed` / `balanced` (default) / `deep` set the kept-score ratio (65% / 55% / 45%) and an activation floor. Only `deep` adds query expansion + reranking to the hook path. Profile and the hook `timeout` are set in `~/.claude/settings.json` — see *Operational gotchas* for timeout tuning.
|
|
41
41
|
|
|
@@ -92,7 +92,7 @@ All other retrieval is handled by Tier 2 hooks. **Do NOT call MCP tools speculat
|
|
|
92
92
|
| `kg_query` | Entity SPO triples with temporal validity. Entity facts, NOT causal "why" (use `intent_search`). |
|
|
93
93
|
| `session_log` | "last time" / "yesterday" / "what did we do". Do NOT use `query` for cross-session. |
|
|
94
94
|
| `profile` | User profile (static facts + dynamic context). |
|
|
95
|
-
| `memory_pin` | +0.3 composite boost. Use PROACTIVELY for constraints, architecture decisions, corrections. |
|
|
95
|
+
| `memory_pin` | Lifecycle retention + priority among relevance-equivalent results (+0.3 composite boost on composite surfaces; exact-tie precedence on raw vector routes). Use PROACTIVELY for constraints, architecture decisions, corrections. |
|
|
96
96
|
| `memory_snooze` | Use PROACTIVELY when `<vault-context>` surfaces noise — snooze 30 days. |
|
|
97
97
|
| `memory_forget` | Deactivate a memory by closest match. Sparingly — prefer snooze. |
|
|
98
98
|
| `build_graphs` | Temporal backbone + semantic graph after bulk ingestion. NOT after every reindex. |
|
|
@@ -189,7 +189,7 @@ Query -> intent classification (WHY/WHEN/ENTITY/WHAT)
|
|
|
189
189
|
|
|
190
190
|
## Composite scoring (how ranking works)
|
|
191
191
|
|
|
192
|
-
Applied
|
|
192
|
+
Applied on the composite surfaces: hooks, `query`, `search`, and `memory_retrieve`'s keyword/hybrid/causal/complex modes. **v0.22.0: MCP `vsearch` and `memory_retrieve` semantic/discovery rank non-recency queries by RAW cosine instead** (`scoreBasis: "vector-cosine"`; metadata breaks exact ties only; `minScore` filters raw with no default); recency-intent queries keep composite everywhere.
|
|
193
193
|
|
|
194
194
|
```
|
|
195
195
|
compositeScore = (0.50·searchScore + 0.25·recencyScore + 0.25·confidenceScore) × qualityMultiplier × coActivationBoost
|
|
@@ -198,8 +198,8 @@ compositeScore = (0.50·searchScore + 0.25·recencyScore + 0.25·confidenceScore
|
|
|
198
198
|
- `qualityMultiplier = 0.7 + 0.6·qualityScore` (0.7× penalty … 1.3× boost).
|
|
199
199
|
- `coActivationBoost = 1 + min(coCount/10, 0.15)` (docs surfaced together get up to +15%).
|
|
200
200
|
- Length normalization penalizes verbose entries (floor 30%); frequency boost capped at +10%.
|
|
201
|
-
- **Pinned docs: +0.3 additive** (capped at 1.0).
|
|
202
|
-
- **`query` tool (v0.13.0+):** non-recency queries use retrieval-tuned **0.70·search + 0.15·recency + 0.15·confidence**. `search
|
|
201
|
+
- **Pinned docs: +0.3 additive on composite surfaces** (capped at 1.0); on the raw vector routes pin = exact-tie precedence only.
|
|
202
|
+
- **`query` tool (v0.13.0+):** non-recency queries use retrieval-tuned **0.70·search + 0.15·recency + 0.15·confidence**. `search`, `memory_retrieve`'s composite modes, and `context-surfacing` keep the 0.50/0.25/0.25 default. (`vsearch` + `memory_retrieve` semantic/discovery use RAW cosine for non-recency queries as of v0.22.0 — no composite weights at all.)
|
|
203
203
|
- **Recency intent** ("latest"/"recent"/"last session") switches all to **0.10·search + 0.70·recency + 0.20·confidence**.
|
|
204
204
|
|
|
205
205
|
**Content-type half-lives:** decision / deductive / preference / hub / antipattern = ∞ (never decay) · project 120d · research 90d · problem / milestone / note 60d · conversation / progress 45d · handoff 30d. Half-lives extend up to 3× for frequently-accessed memories. Attention decay: non-durable types (handoff, progress, conversation, note, project) lose 5% confidence/week without access; decision / deductive / preference / hub / research / antipattern are exempt.
|
|
@@ -210,7 +210,7 @@ compositeScore = (0.50·searchScore + 0.25·recencyScore + 0.25·confidenceScore
|
|
|
210
210
|
|
|
211
211
|
## Memory lifecycle (pin / snooze / forget — manual tools)
|
|
212
212
|
|
|
213
|
-
- **`memory_pin`** (+0.3 boost,
|
|
213
|
+
- **`memory_pin`** (lifecycle retention + priority among relevance-equivalent results; +0.3 boost on composite surfaces, exact-tie precedence on raw vector routes) — PROACTIVELY when: user says "remember this"/"important"; an architecture/critical decision was just made; a user preference/constraint should persist across sessions. Do NOT pin routine/session-specific items.
|
|
214
214
|
- **`memory_snooze`** — PROACTIVELY when a memory keeps surfacing but isn't relevant now, user says "not now"/"later", or content is time-boxed.
|
|
215
215
|
- **`memory_forget`** — only when genuinely wrong or permanently obsolete. Prefer snooze for temporary suppression.
|
|
216
216
|
- **Contradiction auto-resolution:** when `decision-extractor` detects a new decision contradicting an old one, the old one's confidence is lowered automatically — no manual action needed.
|
|
@@ -56,7 +56,7 @@ Each indexed file becomes a document with:
|
|
|
56
56
|
| `content_type` | Auto-detected: decision, deductive, preference, note, handoff, conversation, progress, research, hub, antipattern, project, milestone, problem |
|
|
57
57
|
| `quality_score` | 0.0-1.0 based on length, structure, headings, lists, decision keywords, frontmatter |
|
|
58
58
|
| `confidence` | Starts at 0.5, adjusted by contradiction detection and feedback |
|
|
59
|
-
| `pinned` |
|
|
59
|
+
| `pinned` | Lifecycle retention + priority among relevance-equivalent results (+0.3 on composite surfaces; exact-tie precedence on the raw vector routes) |
|
|
60
60
|
| `snoozed_until` | Temporarily hidden from context surfacing |
|
|
61
61
|
|
|
62
62
|
## Fragments
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Composite Scoring
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Composite scoring blends multiple signals beyond raw search relevance. **It applies to the hook pipeline (context surfacing), the `query` hybrid pipeline, `search`, and `memory_retrieve`'s keyword/hybrid/causal/complex modes.** Since v0.22.0 the direct vector routes — MCP `vsearch` and `memory_retrieve` semantic/discovery — do NOT use it for non-recency queries: they rank by raw vector cosine, with metadata (including pin) breaking exact score ties only, and report `scoreBasis: "vector-cosine"`. That split is measured, not aesthetic: on a judged set against the live vault, raw cosine ranked 16/19 targets #1 (MRR 0.912) while this composite ranked 1/19 (MRR 0.307) and pushed 14/19 correct answers below the old minScore floor — in the compressed-high similarity band of modern embedding models, every multiplier below is larger than the raw margins separating right answers from wrong ones. Recency-intent queries keep composite (the Recency column) on every route that had it.
|
|
4
4
|
|
|
5
5
|
## Formula
|
|
6
6
|
|
|
@@ -19,7 +19,9 @@ compositeScore = (w_search * searchScore + w_recency * recencyScore + w_confiden
|
|
|
19
19
|
|
|
20
20
|
Recency intent is detected automatically when queries contain "latest", "recent", "last session", etc. — and **takes precedence over the `query`-tool weights**: a recency-phrased `query` call still uses the Recency-intent column.
|
|
21
21
|
|
|
22
|
-
The **`query` tool** uses retrieval-tuned weights (search 0.70) derived from a held-out judged-relevance eval (v0.13.0) — more weight on topical relevance measurably improves graded NDCG@10 without demoting the newest-correct version of evolving docs.
|
|
22
|
+
The **`query` tool** uses retrieval-tuned weights (search 0.70) derived from a held-out judged-relevance eval (v0.13.0) — more weight on topical relevance measurably improves graded NDCG@10 without demoting the newest-correct version of evolving docs. `search`, the composite `memory_retrieve` modes, and the context-surfacing hook **keep the Normal column**. The v0.21.0 `retrieval.mcp_direct_tuned_weights` knob is **superseded as of v0.22.0 and has no effect** — the direct-pipeline eval it was gated on measured tuned weights at 1/19 hit@1, and the direct vector routes moved to raw ordering instead. The key is still parsed (a once-per-process warning is logged if set) so existing configs don't break.
|
|
23
|
+
|
|
24
|
+
Threshold note: EOS-anchored last-token embedding models (e.g. zembed-1 served correctly) produce a **compressed-high similarity band** — unrelated pairs sit near ~0.4 rather than ~0.2. Relative ordering is what matters; treat absolute `minScore` cutoffs as model-dependent rather than universal.
|
|
23
25
|
|
|
24
26
|
## Signal breakdown
|
|
25
27
|
|
|
@@ -90,13 +92,13 @@ coActivationBoost = 1 + min(coCount / 10, 0.15)
|
|
|
90
92
|
|
|
91
93
|
Documents frequently surfaced together in the same session get up to 15% boost.
|
|
92
94
|
|
|
93
|
-
**Where co-activation is applied depends on the caller.** MCP
|
|
95
|
+
**Where co-activation is applied depends on the caller.** The composite MCP surfaces (`query`, `search`, and `vsearch` on recency-intent queries only) pass a co-activation function into `applyCompositeScoring()`, so the boost is part of the composite score used for ranking and — on `vsearch` and `search`, the tools that expose `minScore` — for `minScore` filtering. On `vsearch`'s non-recency (raw) regime, co-activation contributes only to the exact-tie key, never to ranking or filtering. The context-surfacing hook does NOT pass co-activation into composite scoring — instead it applies a separate spreading-activation step *after* adaptive threshold filtering. This means the hook's threshold decisions are based on scores without co-activation, and co-activation only boosts results that already passed the threshold. This is intentional: it prevents relationship boosts from rescuing otherwise-weak results into the surfaced set.
|
|
94
96
|
|
|
95
97
|
## Additional modifiers
|
|
96
98
|
|
|
97
99
|
### Pin boost
|
|
98
100
|
|
|
99
|
-
|
|
101
|
+
On composite surfaces, pinned documents receive a +0.3 additive boost (capped at 1.0 total). Pin's contract is **lifecycle retention + prioritization among relevance-equivalent results** — on the raw vector routes (v0.22.0) it therefore breaks exact raw-score ties only and never lifts a document over a more relevant one.
|
|
100
102
|
|
|
101
103
|
### Length normalization
|
|
102
104
|
|
|
@@ -60,9 +60,18 @@ ZeroEntropy's distillation-paired stack — best retrieval quality, total ~16 GB
|
|
|
60
60
|
| Reranker | 8090 | [zerank-2 seq-cls sidecar](../../extras/rerankers/zerank-2-seq/) (transformers, bf16) | ~9 GB | SOTA reranker — **not** a GGUF |
|
|
61
61
|
|
|
62
62
|
```bash
|
|
63
|
-
# Embedding (zembed-1) — -ub MUST equal -b for non-causal attention
|
|
63
|
+
# Embedding (zembed-1) — -ub MUST equal -b for non-causal attention.
|
|
64
|
+
# --pooling last: zembed-1 is a last-token model; declare it explicitly.
|
|
65
|
+
# --override-kv ...add_eos_token: last-token models read the embedding at their EOS
|
|
66
|
+
# anchor. If the GGUF conversion lost add_eos_token, the server never appends the
|
|
67
|
+
# terminator and similarity collapses to last-token identity (see troubleshooting →
|
|
68
|
+
# "Vector search returns weak or irrelevant results"). The override restores it and
|
|
69
|
+
# is a no-op when the metadata is already correct. Do NOT add these two flags to
|
|
70
|
+
# mean-pooling models like the default EmbeddingGemma.
|
|
64
71
|
llama-server -m zembed-1-Q4_K_M.gguf \
|
|
65
|
-
--embeddings --
|
|
72
|
+
--embeddings --pooling last \
|
|
73
|
+
--override-kv tokenizer.ggml.add_eos_token=bool:true \
|
|
74
|
+
--port 8088 --host 0.0.0.0 -ngl 99 -c 8192 -b 2048 -ub 2048
|
|
66
75
|
|
|
67
76
|
# Reranker (zerank-2) — seq-cls SIDECAR (transformers, bf16), NOT a llama-server GGUF:
|
|
68
77
|
cd extras/rerankers/zerank-2-seq
|
package/docs/guides/upgrading.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Upgrading ClawMem
|
|
2
2
|
|
|
3
|
-
Guide for upgrading between released versions. Current: **v0.
|
|
3
|
+
Guide for upgrading between released versions. Current: **v0.22.0**.
|
|
4
4
|
|
|
5
5
|
ClawMem upgrades are designed to be drop-in: pull the new version, restart any long-lived processes, and the SQLite schema auto-migrates on first open. This guide documents per-version specifics for upgrades that have additional considerations beyond the quick path below.
|
|
6
6
|
|
|
@@ -59,6 +59,36 @@ docker compose up -d reranker # /v1/rerank on :8090
|
|
|
59
59
|
|
|
60
60
|
---
|
|
61
61
|
|
|
62
|
+
## v0.22.0: raw-cosine ranking on the direct vector routes
|
|
63
|
+
|
|
64
|
+
No migration command, no schema change, no re-embed. Restart long-lived processes per the quick path.
|
|
65
|
+
|
|
66
|
+
**Behavior change — MCP `vsearch` and `memory_retrieve` semantic/discovery rank non-recency queries by RAW cosine.** Reported scores on those routes are raw cosine (`scoreBasis: "vector-cosine"`), not composite values — expect a different numeric scale (unrelated results sit near ~0.4–0.55 on compressed-band embedding models, not near 0). `vsearch`'s `minScore` filters that raw scale and no longer defaults to 0.3 — omitted means no filter. If a workflow passed `minScore` tuned to composite values, re-tune it to your embedding model's band or omit it. Recency-phrased queries ("latest…", "recently…") behave exactly as before on every route.
|
|
67
|
+
|
|
68
|
+
**Pinned documents** no longer float above more relevant results on those two routes — pin now means lifecycle retention plus winning exact-score ties. Hooks, `query`, and `search` keep the +0.3 composite pin boost.
|
|
69
|
+
|
|
70
|
+
**`retrieval.mcp_direct_tuned_weights` / `CLAWMEM_MCP_DIRECT_TUNED_WEIGHTS` no longer has any effect** (superseded by its own gating eval). Configs that set it keep working; a once-per-process warning is logged — remove the key at your convenience.
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## v0.21.0: MCP internal-collection exclusion + embedding-geometry canary
|
|
75
|
+
|
|
76
|
+
No migration command required. Two things to know:
|
|
77
|
+
|
|
78
|
+
**Behavior change — `_clawmem` excluded from MCP retrieval by default.** `search`, `vsearch`, `query`, `query_plan`, `memory_retrieve`, and `find_similar` no longer return the system-internal `_clawmem` collection (observations/deductions/handoffs) unless asked. If a workflow depended on those appearing in MCP results, pass `includeInternal: true` or name `_clawmem` in an explicit `collection` filter. `intent_search`, `find_causal_links`, `kg_query`, `session_log`, and `timeline` are unfiltered by design, and hooks already filtered internal docs — `<vault-context>` behavior is unchanged. Details: [docs/reference/mcp-tools.md](../reference/mcp-tools.md).
|
|
79
|
+
|
|
80
|
+
**What auto-applies on first open** (additive, idempotent — same contract as prior releases): the `embed_canary` and `vault_flags` tables, and an `embed_input_fp` column on `content_vectors`.
|
|
81
|
+
|
|
82
|
+
**No re-embed required.** Existing vectors stay valid. Pre-0.21.0 rows carry no input fingerprint, so `clawmem doctor`'s new sampled vector validation checks them structurally and flags title provenance as unavailable ("legacy") until each document's next natural re-embed — informational, not an error.
|
|
83
|
+
|
|
84
|
+
**The canary baseline seeds itself.** The first `clawmem embed` run after upgrade (including a timer-fired one) probes the embedding server with a pair-separation battery and persists a first-healthy baseline; subsequent runs alert relative to it, and a broken-geometry server now aborts `embed --force` BEFORE anything is cleared. `--force-geometry` (proceed despite a failed probe; the vault is flagged tainted until a verified rebuild) and `--force --recalibrate-canary` (replace the baseline after a deliberate model/server change) are operator overrides, not upgrade steps.
|
|
85
|
+
|
|
86
|
+
**Opt-in knob:** `retrieval.mcp_direct_tuned_weights` (config) / `CLAWMEM_MCP_DIRECT_TUNED_WEIGHTS` (env), default `false` — scored the MCP direct tools' non-recency queries with the retrieval-tuned `query`-tool weights. *(Superseded in v0.22.0 — the knob no longer has any effect; see the v0.22.0 section above.)*
|
|
87
|
+
|
|
88
|
+
Upgrades from v0.13 → v0.20 shipped no steps beyond the [quick path](#quick-path) — schema changes auto-apply; see [RELEASE_NOTES.md](../../RELEASE_NOTES.md) for what each version changed.
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
62
92
|
## v0.12.0: query reranking blend (no action required)
|
|
63
93
|
|
|
64
94
|
v0.12.0 changes the `query` tool's rerank/RRF blend so the cross-encoder reranker can promote the best document to the top — the previous blend left RRF #1 mathematically immovable. It is a pure ranking-quality change: **no migration, no schema change, no config change.** It applies automatically on upgrade. Hooks and the per-session MCP stdio server pick it up on their next invocation; restart any long-lived `query` host — `clawmem serve` and persistent MCP/daemon processes — to pick up the improved ordering. The default reranker (`qwen3-reranker-0.6B`) is unchanged, and the blend improvement applies whatever reranker `:8090` serves. (`intent_search` and the context-surfacing hook keep their existing blends.)
|
|
@@ -145,7 +175,7 @@ Hooks and the stdio MCP server pick up the new binary automatically on their nex
|
|
|
145
175
|
- **`plugins.slots.memory: "clawmem"` replaces `plugins.slots.contextEngine: "clawmem"`.** On the new pure-memory plugin, the exclusive slot is `memory`. The `setup openclaw` next-steps output tells you to run `openclaw plugins enable clawmem`, which sets the slot and disables competing memory plugins (`memory-core`, `memory-lancedb`) in a single command. You do NOT need to run the older `openclaw config set plugins.slots.contextEngine clawmem` pattern on v0.10.0.
|
|
146
176
|
- **`src/openclaw/package.json` is now the plugin's discovery manifest.** OpenClaw v2026.4.11's `discoverInDirectory` reads `package.json` for the `openclaw.extensions` field and uses that to decide whether a directory under `~/.openclaw/extensions/` is a valid plugin. The older `openclaw.plugin.json` manifest is still shipped and parsed at runtime, but it is not sufficient to pass discovery on v2026.4.11+ without the `package.json` companion file. v0.10.0 adds the `package.json` to the plugin source tree, and `clawmem setup openclaw` verifies it is present before copying.
|
|
147
177
|
- **`clawmem setup openclaw` defaults to recursive copy instead of symlink.** OpenClaw v2026.4.11 walks `~/.openclaw/extensions/` with `readdirSync({ withFileTypes: true })` and uses `dirent.isDirectory()` to descend into candidate plugin directories. Symlinks to directories report `isDirectory() === false` on that API shape, so a symlinked plugin is silently skipped during discovery. v0.10.0's `cmdSetupOpenClaw` therefore copies the plugin source into `~/.openclaw/extensions/clawmem/` with `cpSync(..., { recursive: true, dereference: true })`. A `--link` opt-in flag preserves the old symlink behavior for local development and for older OpenClaw versions, with a warning that v2026.4.11+ discovery will skip the symlink. Setup is idempotent: any existing plugin directory or stale symlink is removed before the new copy is written.
|
|
148
|
-
- **Multi-user ownership check (OpenClaw v2026.4.11+).** If the gateway runs as a dedicated system user (e.g. `openclaw`) and you run `clawmem setup openclaw` as a different user (e.g. `
|
|
178
|
+
- **Multi-user ownership check (OpenClaw v2026.4.11+).** If the gateway runs as a dedicated system user (e.g. `openclaw`) and you run `clawmem setup openclaw` as a different user (e.g. `alice`), the copied plugin directory is owned by the installer user, but OpenClaw's ownership check rejects it with `suspicious ownership (uid=1001, expected uid=997 or root)`. This is a security feature that prevents a privileged gateway process from loading code a less-privileged user dropped into its extensions directory. Fix: `sudo chown -R <gateway-user>:<gateway-group> ~/.openclaw/extensions/clawmem`. Single-user installs where you ARE the gateway user are not affected — your own user owns the copy, and the ownership check passes.
|
|
149
179
|
|
|
150
180
|
### Rollback
|
|
151
181
|
|
|
@@ -191,7 +221,7 @@ Hooks + MCP stdio pick up new code automatically on next invocation — no resta
|
|
|
191
221
|
|
|
192
222
|
When the user's prompt mentions entities already known to the vault (via `entity_nodes`), `context-surfacing` now appends a token-bounded `<vault-facts>` block of raw SPO triple lines to `<vault-context>`, alongside the existing `<facts>` / `<relationships>` blocks. This feeds the model current-state knowledge about entities the user is talking about, without requiring the agent to call `kg_query` explicitly.
|
|
193
223
|
|
|
194
|
-
- **Three-path entity seeding** — canonical-ID regex (e.g. `default:project:clawmem`) → proper-noun extraction via `resolveEntityTypeExact` → longer-first n-gram scan (3-gram > 2-gram > 1-gram) for lowercase/hyphenated vocabulary like `
|
|
224
|
+
- **Three-path entity seeding** — canonical-ID regex (e.g. `default:project:clawmem`) → proper-noun extraction via `resolveEntityTypeExact` → longer-first n-gram scan (3-gram > 2-gram > 1-gram) for lowercase/hyphenated vocabulary like `side-project`, `oauth2`, `vm 12`. All three paths run prompt-only — entity seeds NEVER come from surfaced doc bodies, so topic-boosted off-topic docs cannot pollute the facts block.
|
|
195
225
|
- **Profile-gated token sub-budget** — `factsTokens=0` on `speed` disables the stage entirely. `balanced` uses 200 tokens, `deep` uses 250. The sub-budget is dedicated — `<vault-facts>` cannot steal budget from `<facts>` or `<relationships>`.
|
|
196
226
|
- **Truncation** — at the triple boundary, never mid-triple, never emits an empty block.
|
|
197
227
|
- **Fail-open** — empty entity set → skip. Budget too small → drop block. Per-entity DB error → skip that entity. Any exception in the stage → return baseline `vault-context` unchanged.
|
package/docs/introduction.md
CHANGED
|
@@ -6,7 +6,7 @@ ClawMem is an open-source memory engine for Claude Code and AI agents. It runs o
|
|
|
6
6
|
|
|
7
7
|
- **Indexes** markdown documents into a local SQLite vault with full-text search (BM25) and vector embeddings
|
|
8
8
|
- **Retrieves** relevant context automatically via hooks or on-demand via MCP tools / REST API
|
|
9
|
-
- **Scores** results
|
|
9
|
+
- **Scores** results per route: raw vector cosine on the direct vector tools (v0.22.0), composite scoring (relevance, recency, confidence, quality, co-activation) on the hook and hybrid pipelines
|
|
10
10
|
- **Tracks** decisions, handoffs, and session history across conversations
|
|
11
11
|
- **Traverses** causal and semantic graphs to answer "why" and "what led to" questions
|
|
12
12
|
|
package/docs/quickstart.md
CHANGED
|
@@ -70,7 +70,7 @@ llama-server -m Qwen3-Reranker-0.6B-Q8_0.gguf \
|
|
|
70
70
|
--reranking --port 8090 --host 0.0.0.0 -ngl 99 -c 2048 --batch-size 512
|
|
71
71
|
```
|
|
72
72
|
|
|
73
|
-
> **SOTA upgrade (16GB+ GPU):** Replace embedding with zembed-1-Q4_K_M (2560d, `-b 2048 -ub 2048
|
|
73
|
+
> **SOTA upgrade (16GB+ GPU):** Replace embedding with zembed-1-Q4_K_M (2560d, `-b 2048 -ub 2048`, **plus `--pooling last --override-kv tokenizer.ggml.add_eos_token=bool:true`** — last-token models need their EOS anchor; the exact launch line is in [the inference services guide](guides/inference-services.md)). For the reranker, use the **zerank-2 seq-cls sidecar** (transformers, bf16) at [`extras/rerankers/zerank-2-seq/`](../extras/rerankers/zerank-2-seq/) — the `zerank-2-Q4_K_M` GGUF is deprecated (llama.cpp drops its score head). **CC-BY-NC-4.0** — non-commercial only.
|
|
74
74
|
|
|
75
75
|
See [GPU services guide](guides/systemd-services.md) for systemd setup and remote GPU configuration.
|
|
76
76
|
|
package/docs/reference/cli.md
CHANGED
|
@@ -7,7 +7,7 @@ Complete command reference for the ClawMem memory engine. Always use the `bin/cl
|
|
|
7
7
|
```bash
|
|
8
8
|
clawmem init # Initialize vault (creates SQLite DB)
|
|
9
9
|
clawmem status # Quick index status
|
|
10
|
-
clawmem doctor # Full health check (GPU connectivity, index integrity)
|
|
10
|
+
clawmem doctor # Full health check (GPU connectivity, index integrity, embedding-geometry canary, sampled vector validation)
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
## Collection management
|
|
@@ -30,8 +30,10 @@ clawmem mine <dir> --dry-run # Preview without importing
|
|
|
30
30
|
clawmem mine <dir> --synthesize # v0.7.2: import + post-import LLM fact extraction
|
|
31
31
|
clawmem mine <dir> --synthesize --synthesis-max-docs 50 # Cap synthesis to first 50 conversations (default 20)
|
|
32
32
|
clawmem reindex # Force re-scan all collections
|
|
33
|
-
clawmem embed # Embed all un-embedded fragments
|
|
34
|
-
clawmem embed --force # Re-embed everything (clears existing vectors)
|
|
33
|
+
clawmem embed # Embed all un-embedded fragments (geometry-canary preflight runs first)
|
|
34
|
+
clawmem embed --force # Re-embed everything (clears existing vectors; aborts BEFORE clearing if the canary preflight fails)
|
|
35
|
+
clawmem embed --force --force-geometry # v0.21.0: proceed despite a failed/unavailable canary — vault is tainted until a verified rebuild
|
|
36
|
+
clawmem embed --force --recalibrate-canary # v0.21.0: replace the stored canary baseline after a deliberate model/server change (requires --force)
|
|
35
37
|
```
|
|
36
38
|
|
|
37
39
|
### Conversation Import
|
|
@@ -38,6 +38,7 @@ Full provider matrix and behavior: [../guides/cloud-embedding.md](../guides/clou
|
|
|
38
38
|
|---|---|---|
|
|
39
39
|
| `CLAWMEM_PROFILE` | `balanced` | `speed` / `balanced` / `deep`. Sets the kept-score ratio (65% / 55% / 45%), vector timeout, max results, and the `factsTokens` sub-budget. Only `deep` adds query expansion + reranking to the hook path. `speed` makes hooks BM25-only (sub-500ms). |
|
|
40
40
|
| `CLAWMEM_NUDGE_INTERVAL` | `15` | Prompts between lifecycle tool use before a `<vault-nudge>` is injected. `0` to disable. |
|
|
41
|
+
| `CLAWMEM_MCP_DIRECT_TUNED_WEIGHTS` | (superseded) | **No effect since v0.22.0.** The direct-pipeline eval this knob was gated on measured tuned weights at 1/19 hit@1; the direct vector routes now rank by raw cosine instead (see [mcp-tools](mcp-tools.md) → Scoring regimes). Still parsed for backward compatibility — setting it (env or `retrieval.mcp_direct_tuned_weights` in `config.yaml`) logs a once-per-process warning. |
|
|
41
42
|
|
|
42
43
|
The context-surfacing hook `timeout` is **not** an env var — it lives in `~/.claude/settings.json` (8s default). See [../troubleshooting.md](../troubleshooting.md) → *Tuning the context-surfacing hook timeout*.
|
|
43
44
|
|
|
@@ -4,6 +4,12 @@ Complete reference for ClawMem's MCP server tools. These let AI agents search, r
|
|
|
4
4
|
|
|
5
5
|
## Retrieval
|
|
6
6
|
|
|
7
|
+
**Internal-collection visibility (v0.21.0):** the retrieval tools `search`, `vsearch`, `query`, `query_plan`, `memory_retrieve`, and `find_similar` exclude the system-internal `_clawmem` collection (observations/deductions/handoffs) by default. Opt-ins: pass `includeInternal: true` (all six tools), or — on the tools that expose a `collection` parameter (`search`, `vsearch`, `query`) — name `_clawmem` explicitly in the filter. `find_similar` auto-includes internal results when the REFERENCE document is itself internal. `intent_search`, `find_causal_links`, `kg_query`, `session_log`, and `timeline` are NOT filtered — system memory is their substrate by design.
|
|
8
|
+
|
|
9
|
+
**Scoring regimes (v0.22.0):** the direct vector routes — `vsearch` and `memory_retrieve`'s semantic/discovery modes — rank non-recency queries by RAW vector cosine. Their `structuredContent` carries `scoreBasis: "vector-cosine"`; raw cosine values are specific to the embedding model that produced them and are NOT comparable across models or to composite scores. Document metadata — including pin — participates only inside groups of exactly-equal raw scores. On these routes `minScore` filters the raw score and has NO default (omitted = no filter; an explicit `0` is honored). Recency-intent queries ("latest…", "recently…", "yesterday…") keep the composite regime with its 0.3 default floor and report `scoreBasis: "composite"`, as do `search`, `query`, `query_plan`, and `memory_retrieve`'s keyword/hybrid/causal/complex modes. `find_similar` has always ranked by raw cosine. Rationale: on the measured vault, raw cosine ranked 16/19 judged targets #1 (MRR 0.912) while the composite stack ranked 1/19 and filtered 14/19 out entirely.
|
|
10
|
+
|
|
11
|
+
**Degraded vector results (v0.21.0):** under default exclusion the vector scan escalates its depth to fill `limit` with allowed documents, up to a hard cap. When the cap prevents an exhaustive scan and the result is under-filled, `structuredContent` carries `degraded: true` with `degradedReason`: `"excluded-dominant"` (distinct excluded docs account for the shortfall — the guidance line suggests `includeInternal: true` or a refined query) or `"cap-truncation"` (shortfall driven by fragment dedup, neutral guidance). Multi-leg routes (`query`, `query_plan`, `memory_retrieve` complex mode) aggregate `degraded = any(leg)` and list per-leg reasons in `structuredContent.degradedLegs`; single-vector routes (`vsearch`, `find_similar`, `memory_retrieve`'s other modes) report the flat `degraded` + `degradedReason` pair. A small vault whose whole index is scanned without hitting the cap returns a plain short list with NO marker.
|
|
12
|
+
|
|
7
13
|
### memory_retrieve
|
|
8
14
|
|
|
9
15
|
**Recommended entry point.** Auto-classifies query and routes to the optimal backend.
|
|
@@ -14,6 +20,7 @@ Complete reference for ClawMem's MCP server tools. These let AI agents search, r
|
|
|
14
20
|
| `mode` | enum | `auto` | Override: `keyword`, `semantic`, `causal`, `timeline`, `discovery`, `complex`, `hybrid` |
|
|
15
21
|
| `limit` | number | 10 | Max results |
|
|
16
22
|
| `compact` | boolean | true | Compact output (snippets vs full content) |
|
|
23
|
+
| `includeInternal` | boolean | false | Include system-internal `_clawmem` docs |
|
|
17
24
|
| `vault` | string | — | Named vault |
|
|
18
25
|
|
|
19
26
|
Auto-routing:
|
|
@@ -35,6 +42,7 @@ Full hybrid pipeline: BM25 + vector + query expansion + cross-encoder reranking.
|
|
|
35
42
|
| `collection` | string | — | Filter by collection (comma-separated for multi) |
|
|
36
43
|
| `intent` | string | — | Domain hint for ambiguous queries (steers expansion, reranking, chunk selection) |
|
|
37
44
|
| `candidateLimit` | number | 30 | Candidates for reranking (tune precision vs speed) |
|
|
45
|
+
| `includeInternal` | boolean | false | Include system-internal `_clawmem` docs |
|
|
38
46
|
| `vault` | string | — | Named vault |
|
|
39
47
|
|
|
40
48
|
BM25 strong-signal bypass: skips expansion when top BM25 hit >= 0.85 with gap >= 0.15 (disabled when `intent` is provided).
|
|
@@ -49,18 +57,21 @@ BM25 only. Zero GPU cost.
|
|
|
49
57
|
| `limit` | number | 10 | Max results |
|
|
50
58
|
| `compact` | boolean | true | Compact output |
|
|
51
59
|
| `collection` | string | — | Filter by collection |
|
|
60
|
+
| `includeInternal` | boolean | false | Include system-internal `_clawmem` docs |
|
|
52
61
|
| `vault` | string | — | Named vault |
|
|
53
62
|
|
|
54
63
|
### vsearch
|
|
55
64
|
|
|
56
|
-
Vector only. Semantic similarity.
|
|
65
|
+
Vector only. Semantic similarity. Non-recency queries rank by RAW cosine (`scoreBasis: "vector-cosine"`, v0.22.0); recency-intent queries use the composite regime.
|
|
57
66
|
|
|
58
67
|
| Param | Type | Default | Description |
|
|
59
68
|
|-------|------|---------|-------------|
|
|
60
69
|
| `query` | string | required | Search query |
|
|
61
70
|
| `limit` | number | 10 | Max results |
|
|
71
|
+
| `minScore` | number | — | Raw-cosine floor on non-recency queries (no default — omitted means no filter; explicit `0` honored). Recency-intent queries keep the composite-scale 0.3 default. |
|
|
62
72
|
| `compact` | boolean | true | Compact output |
|
|
63
73
|
| `collection` | string | — | Filter by collection |
|
|
74
|
+
| `includeInternal` | boolean | false | Include system-internal `_clawmem` docs |
|
|
64
75
|
| `vault` | string | — | Named vault |
|
|
65
76
|
|
|
66
77
|
### intent_search
|
|
@@ -84,6 +95,7 @@ Multi-topic decomposition. Use for complex queries spanning multiple subjects.
|
|
|
84
95
|
| `query` | string | required | Complex or multi-topic query |
|
|
85
96
|
| `limit` | number | 10 | Max results |
|
|
86
97
|
| `compact` | boolean | true | Compact output |
|
|
98
|
+
| `includeInternal` | boolean | false | Include system-internal `_clawmem` docs |
|
|
87
99
|
| `vault` | string | — | Named vault |
|
|
88
100
|
|
|
89
101
|
## Document access
|
|
@@ -120,6 +132,7 @@ k-NN vector neighbors of a reference document.
|
|
|
120
132
|
|-------|------|---------|-------------|
|
|
121
133
|
| `file` | string | required | Path of reference document |
|
|
122
134
|
| `limit` | number | 5 | Max results |
|
|
135
|
+
| `includeInternal` | boolean | false | Include system-internal `_clawmem` docs (auto-included when the reference doc is itself internal) |
|
|
123
136
|
| `vault` | string | — | Named vault |
|
|
124
137
|
|
|
125
138
|
### find_causal_links
|
|
@@ -168,7 +181,7 @@ Recent session history with handoffs and file changes.
|
|
|
168
181
|
|
|
169
182
|
### memory_pin
|
|
170
183
|
|
|
171
|
-
Pin a memory
|
|
184
|
+
Pin a memory: lifecycle retention plus prioritization among relevance-equivalent results. On composite surfaces (hooks, `query`, `search`) pinned docs get the +0.3 composite boost; on the raw vector routes (v0.22.0) pin wins exact raw-score ties but never overrides a relevance difference.
|
|
172
185
|
|
|
173
186
|
| Param | Type | Default | Description |
|
|
174
187
|
|-------|------|---------|-------------|
|
package/docs/troubleshooting.md
CHANGED
|
@@ -93,10 +93,13 @@ Common issues when running ClawMem with hooks, MCP server, or OpenClaw plugin. O
|
|
|
93
93
|
- Fix: re-deploy a working reranker — the **zerank-2 seq-cls sidecar** (`extras/rerankers/zerank-2-seq/`, see CLAUDE.md "SOTA upgrade") or the default `qwen3-reranker-0.6B` — and confirm `CLAWMEM_RERANK_URL` points at it. Re-run `clawmem rerank-health`; it should exit 0. For remote-sidecar setups, schedule `clawmem-rerank-health.timer` (CLAUDE.md → Background Services) so a future silent reversion pages you.
|
|
94
94
|
|
|
95
95
|
**Vector search returns weak or irrelevant results even though embeddings exist**
|
|
96
|
-
- BM25/keyword search works and `doctor` shows vectors present + consistent, but `vsearch`/`find_similar` (and the vector half of `query`) return loosely-related results, or "the same few docs regardless of query." This is an embedding-**quality** problem, not a ClawMem index problem: the model is producing poorly-discriminating vectors.
|
|
97
|
-
-
|
|
98
|
-
-
|
|
99
|
-
-
|
|
96
|
+
- BM25/keyword search works and `doctor` shows vectors present + consistent, but `vsearch`/`find_similar` (and the vector half of `query`) return loosely-related results, or "the same few docs regardless of query." This is an embedding-**quality** problem, not a ClawMem index problem: the model is producing poorly-discriminating vectors. Two common causes, both server-side:
|
|
97
|
+
- **Pooling misconfiguration** — serving a last-token model (Qwen3-Embedding family) without `--pooling last`, or without L2 normalization. Mean-pooling a last-token model gives usable self-retrieval but collapsed semantic separation (paraphrases score ~0.5 instead of ~0.85).
|
|
98
|
+
- **Missing EOS anchor** — a last-token model whose GGUF conversion lost `tokenizer.ggml.add_eos_token`: the server never appends the terminator the model reads its embedding from, so last-token pooling reads an arbitrary final text token. Signature: similarity tracks how texts END, not what they mean — identical-vocabulary pairs score low; similarity swings with the truncation point; texts sharing a final word score deceptively high; self-similarity stays ~1.0 (so stored-vs-fresh checks pass). Verified real-world: this exact failure served an entire vault ~0.33 on echo pairs while basic-English probes looked healthy.
|
|
99
|
+
- Diagnose: embed two paraphrases and one unrelated sentence through your endpoint and compare cosine similarity. A healthy model scores the paraphrase pair > 0.75 and the unrelated pair < 0.45. Also test a near-identical pair differing only in the final word — it must score HIGH; low means an unanchored last-token readout. Beware the shared-suffix confound when testing terminators by hand: appending ANY common suffix to both texts inflates similarity by last-token identity — only genuine semantic separation (related high AND unrelated low) proves the fix. `clawmem doctor` runs this battery automatically (geometry canary), and `clawmem embed` refuses to build against a failing geometry (override: `--force-geometry`).
|
|
100
|
+
- Fix: launch the embedding `llama-server` with the pooling its model requires (`--pooling last` for Qwen3-Embedding / last-token models), restore the EOS append when the GGUF lost it (`--override-kv tokenizer.ggml.add_eos_token=bool:true` — a no-op when the metadata is already correct), and ensure outputs are L2-normalized. **A full `clawmem embed --force` is REQUIRED after any serving-side pooling/normalization/EOS change**: the old vectors are faithful to the old geometry, and two geometries at the same dimension are mutually incompatible — fresh queries against stale vectors are cosine-meaningless.
|
|
101
|
+
- Note on `_clawmem/` system docs (observations/deductions): since v0.21.0 the MCP retrieval tools exclude the `_clawmem` collection by default (pass `includeInternal: true` to include it; an explicit `collection` filter naming `_clawmem` also overrides). If internal docs dominate results even with a HEALTHY model, that is the composite-scoring floor (system docs carry high confidence and non-decaying recency), not geometry — the default exclusion is the remedy there.
|
|
102
|
+
- Operational: don't run `embed --force` while the file watcher is indexing bulk changes — stop the watcher or expect write contention (the run now survives transient `SQLITE_BUSY`, but contention still slows it). If you pipe embed output through `tee`, remember the pipeline exit code is `tee`'s — check `PIPESTATUS[0]` for the embed's own status.
|
|
100
103
|
|
|
101
104
|
**kg_query returns empty for every entity**
|
|
102
105
|
- `entity_triples` is populated by the decision-extractor Stop hook from observer-emitted `<triples>` blocks. Zero rows typically means either (a) the Stop hook has never fired in this vault, or (b) the observer LLM is not emitting `<triples>` blocks.
|
package/package.json
CHANGED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SQLITE_BUSY detection + bounded ASYNC retry (VSEARCH-TRUST-HARDENING (f).2).
|
|
3
|
+
*
|
|
4
|
+
* The awaits between attempts let the event loop breathe so the embed-lease heartbeat
|
|
5
|
+
* (a setInterval on the same loop) fires; the caller's leaseLost flag is re-checked
|
|
6
|
+
* between attempts so a reclaimed lease ABORTS instead of writing as a zombie holder.
|
|
7
|
+
* Retry scope is SQLITE_BUSY only — every other error (including FatalVectorError
|
|
8
|
+
* dimension/model/schema aborts) propagates unchanged on the first throw.
|
|
9
|
+
*/
|
|
10
|
+
import { EmbedLeaseLostError } from "./store.ts";
|
|
11
|
+
|
|
12
|
+
const SQLITE_BUSY_RE = /database is locked|SQLITE_BUSY/i;
|
|
13
|
+
|
|
14
|
+
export function isSqliteBusyError(err: unknown): boolean {
|
|
15
|
+
return err instanceof Error && SQLITE_BUSY_RE.test(err.message);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export async function retryOnBusyAsync<T>(
|
|
19
|
+
fn: () => T,
|
|
20
|
+
label: string,
|
|
21
|
+
isLeaseLost: () => boolean,
|
|
22
|
+
opts?: { delaysMs?: number[]; onRetry?: (label: string, attempt: number, delayMs: number) => void }
|
|
23
|
+
): Promise<T> {
|
|
24
|
+
const delays = opts?.delaysMs ?? [1000, 2000, 4000];
|
|
25
|
+
for (let attempt = 0; ; attempt++) {
|
|
26
|
+
try { return fn(); }
|
|
27
|
+
catch (err) {
|
|
28
|
+
if (!isSqliteBusyError(err) || attempt >= delays.length) throw err;
|
|
29
|
+
opts?.onRetry?.(label, attempt + 1, delays[attempt]!);
|
|
30
|
+
await new Promise(res => setTimeout(res, delays[attempt]!));
|
|
31
|
+
if (isLeaseLost()) throw new EmbedLeaseLostError();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|