clawmem 0.1.3 → 0.1.5

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 CHANGED
@@ -257,6 +257,8 @@ ClawMem hooks handle ~90% of retrieval automatically. Agent-initiated MCP calls
257
257
 
258
258
  **Hook blind spots (by design):** Hooks filter out `_clawmem/` system artifacts, enforce score thresholds, and cap token budget. Absence in `<vault-context>` does NOT mean absence in memory. If you expect a memory to exist but it wasn't surfaced, escalate to Tier 3.
259
259
 
260
+ **Adaptive thresholds:** Context-surfacing uses ratio-based scoring that adapts to vault characteristics (size, document quality, content age, embedding model). Results are kept within a percentage of the best result's composite score rather than a fixed absolute threshold. An activation floor prevents surfacing when all results are weak. Profiles control the ratio: `speed` (65%), `balanced` (55%), `deep` (45% + query expansion + reranking). `CLAWMEM_PROFILE=deep` is recommended for vaults with older content or lower-quality documents. MCP tools use fixed absolute thresholds, not adaptive.
261
+
260
262
  ### Tier 3 — Agent-Initiated (one targeted MCP call)
261
263
 
262
264
  **Escalate ONLY when one of these three rules fires:**
@@ -631,8 +633,8 @@ Symptom: "UserPromptSubmit hook error" on context-surfacing hook (intermittent)
631
633
  (including non-.md files like session .jsonl transcripts) and holds brief write locks. If the
632
634
  hook fires during a lock, it can exceed its timeout. More likely during active conversations
633
635
  when the watcher is processing rapid transcript changes.
634
- → Fix: Bump the hook timeout from 5s to 8s in ~/.claude/settings.json. If persistent, restart
635
- the watcher to clear memory bloat: `systemctl --user restart clawmem-watcher.service`.
636
+ → Fix: The default timeout is 8s (since v0.1.1). If you have an older install, re-run
637
+ `clawmem setup hooks` to update. If persistent, restart the watcher: `systemctl --user restart clawmem-watcher.service`.
636
638
  ```
637
639
 
638
640
  ## CLI Reference
package/CLAUDE.md CHANGED
@@ -257,6 +257,8 @@ ClawMem hooks handle ~90% of retrieval automatically. Agent-initiated MCP calls
257
257
 
258
258
  **Hook blind spots (by design):** Hooks filter out `_clawmem/` system artifacts, enforce score thresholds, and cap token budget. Absence in `<vault-context>` does NOT mean absence in memory. If you expect a memory to exist but it wasn't surfaced, escalate to Tier 3.
259
259
 
260
+ **Adaptive thresholds:** Context-surfacing uses ratio-based scoring that adapts to vault characteristics (size, document quality, content age, embedding model). Results are kept within a percentage of the best result's composite score rather than a fixed absolute threshold. An activation floor prevents surfacing when all results are weak. Profiles control the ratio: `speed` (65%), `balanced` (55%), `deep` (45% + query expansion + reranking). `CLAWMEM_PROFILE=deep` is recommended for vaults with older content or lower-quality documents. MCP tools use fixed absolute thresholds, not adaptive.
261
+
260
262
  ### Tier 3 — Agent-Initiated (one targeted MCP call)
261
263
 
262
264
  **Escalate ONLY when one of these three rules fires:**
@@ -631,8 +633,8 @@ Symptom: "UserPromptSubmit hook error" on context-surfacing hook (intermittent)
631
633
  (including non-.md files like session .jsonl transcripts) and holds brief write locks. If the
632
634
  hook fires during a lock, it can exceed its timeout. More likely during active conversations
633
635
  when the watcher is processing rapid transcript changes.
634
- → Fix: Bump the hook timeout from 5s to 8s in ~/.claude/settings.json. If persistent, restart
635
- the watcher to clear memory bloat: `systemctl --user restart clawmem-watcher.service`.
636
+ → Fix: The default timeout is 8s (since v0.1.1). If you have an older install, re-run
637
+ `clawmem setup hooks` to update. If persistent, restart the watcher: `systemctl --user restart clawmem-watcher.service`.
636
638
  ```
637
639
 
638
640
  ## CLI Reference
package/README.md CHANGED
@@ -606,7 +606,7 @@ clawmem doctor Full health check
606
606
  clawmem status Quick index status
607
607
  ```
608
608
 
609
- ## MCP Tools (25)
609
+ ## MCP Tools (28)
610
610
 
611
611
  Registered by `clawmem setup mcp`. Available to any MCP-compatible client.
612
612
 
@@ -652,6 +652,13 @@ Registered by `clawmem setup mcp`. Available to any MCP-compatible client.
652
652
  |---|---|
653
653
  | `beads_sync` | Sync Beads issues from Dolt backend (`bd` CLI) into memory: creates docs, bridges all dep types to `memory_relations`, runs A-MEM enrichment |
654
654
 
655
+ ### Vault Management
656
+
657
+ | Tool | Description |
658
+ |---|---|
659
+ | `list_vaults` | Show configured vault names and paths. Empty in single-vault mode. |
660
+ | `vault_sync` | Index markdown from a directory into a named vault. Restricted-path validation rejects sensitive directories. |
661
+
655
662
  ### Memory Management & Lifecycle
656
663
 
657
664
  | Tool | Description |
@@ -998,7 +1005,7 @@ Manual layers benefit from periodic re-indexing — a cron job running `clawmem
998
1005
 
999
1006
  Three-tier retrieval architecture: infrastructure (watcher + embed timer) → hooks (~90%) → agent MCP (~10%). Works out of the box without a dedicated GPU (all models auto-download via `node-llama-cpp`, uses Metal on Apple Silicon). For best performance, run three `llama-server` instances — see [GPU Services](#gpu-services) for model tiers (SOTA vs QMD native) and [Cloud Embedding](#option-c-cloud-embedding-api) for cloud embedding alternatives.
1000
1007
 
1001
- Key services: `clawmem-watcher` (auto-index on file change + beads sync), `clawmem-embed` timer (daily embedding sweep), 9 Claude Code hooks (context injection, session bootstrap, decision extraction, handoffs, feedback, compaction support). Optional `clawmem-curator` agent for on-demand lifecycle triage, retrieval health checks, and maintenance (`clawmem setup curator`).
1008
+ Key services: `clawmem-watcher` (auto-index on file change + beads sync), `clawmem-embed` timer (daily embedding sweep), 7 Claude Code hooks installed by default (context injection, curator nudge, compaction support, decision extraction, handoffs, feedback). Optional `clawmem-curator` agent for on-demand lifecycle triage, retrieval health checks, and maintenance (`clawmem setup curator`).
1002
1009
 
1003
1010
  ## Acknowledgments
1004
1011
 
@@ -1015,6 +1022,21 @@ Built on the shoulders of:
1015
1022
  - [SAME](https://github.com/sgx-labs/statelessagent) — agent memory concepts (recency decay, confidence scoring, session tracking)
1016
1023
  - [supermemory](https://github.com/supermemoryai/clawdbot-supermemory) — hook patterns and context surfacing ideas
1017
1024
 
1025
+ ## Roadmap
1026
+
1027
+ | Status | Feature | Description |
1028
+ |--------|---------|-------------|
1029
+ | :white_check_mark: | Adaptive thresholds | Ratio-based filtering that adapts to vault characteristics (v0.1.3) |
1030
+ | :white_check_mark: | Deep escalation | Budget-aware query expansion + cross-encoder reranking for `deep` profile |
1031
+ | :white_check_mark: | Cloud embedding providers | Jina, OpenAI, Voyage, Cohere with batch embedding + TPM pacing |
1032
+ | :construction: | Calibration probes | One-time `clawmem calibrate` command that measures your vault's score distribution and tunes thresholds automatically |
1033
+ | :construction: | Rolling threshold learning | Learns optimal activation floor from actual usage patterns (which surfaced content gets referenced vs ignored) |
1034
+ | :memo: | Multi-vault namespacing | Isolated vaults with independent calibration and lifecycle policies |
1035
+ | :memo: | REST API authentication | Token-scoped access for multi-agent deployments |
1036
+ | :memo: | Streaming rerank | Cross-encoder reranking within the hook timeout budget for larger candidate sets |
1037
+
1038
+ :white_check_mark: Shipped&ensp; :construction: Planned&ensp; :memo: Exploring
1039
+
1018
1040
  ## License
1019
1041
 
1020
1042
  MIT
package/SKILL.md CHANGED
@@ -191,6 +191,8 @@ Hooks handle ~90% of retrieval. Zero agent effort.
191
191
 
192
192
  **Hook blind spots (by design):** Hooks filter out `_clawmem/` system artifacts, enforce score thresholds, and cap token budget. Absence in `<vault-context>` does NOT mean absence in memory. Escalate to Tier 3 if expected memory wasn't surfaced.
193
193
 
194
+ **Adaptive thresholds:** Context-surfacing uses ratio-based scoring that adapts to vault characteristics. Results are kept within a percentage of the best result's composite score (speed: 65%, balanced: 55%, deep: 45%). An activation floor prevents surfacing when all results are weak. `CLAWMEM_PROFILE=deep` adds query expansion + reranking. MCP tools use fixed absolute thresholds, not adaptive.
195
+
194
196
  ---
195
197
 
196
198
  ## Tier 3 — Agent-Initiated Retrieval (MCP Tools)
@@ -635,8 +637,8 @@ Symptom: "UserPromptSubmit hook error" on context-surfacing hook (intermittent)
635
637
  -> SQLite contention between watcher and hook. Watcher processes filesystem events (including
636
638
  non-.md files like session .jsonl transcripts) and holds brief write locks. If the hook fires
637
639
  during a lock, it can exceed its timeout. More likely during active conversations.
638
- -> Fix: Bump hook timeout from 5s to 8s in ~/.claude/settings.json. If persistent, restart
639
- the watcher: `systemctl --user restart clawmem-watcher.service`.
640
+ -> Fix: Default timeout is 8s (since v0.1.1). If you have an older install, re-run
641
+ `clawmem setup hooks`. If persistent, restart the watcher: `systemctl --user restart clawmem-watcher.service`.
640
642
  ```
641
643
 
642
644
  ---
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clawmem",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "On-device context engine and memory for AI agents. Claude Code and OpenClaw. Hooks + MCP server + hybrid RAG search.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/config.ts CHANGED
@@ -70,7 +70,16 @@ export interface ProfileConfig {
70
70
  maxResults: number;
71
71
  useVector: boolean;
72
72
  vectorTimeout: number;
73
+ /** Legacy absolute threshold — used by MCP tools and as fallback when thresholdMode="absolute" */
73
74
  minScore: number;
75
+ /** Adaptive: keep results within this ratio of best score (e.g., 0.55 = top 55%) */
76
+ minScoreRatio: number;
77
+ /** Adaptive: never surface below this regardless of ratio */
78
+ absoluteFloor: number;
79
+ /** Adaptive: if best result is below this, return empty (prevents all-weak surfacing) */
80
+ activationFloor: number;
81
+ /** "adaptive" uses ratio-based filtering; "absolute" uses legacy minScore */
82
+ thresholdMode: "adaptive" | "absolute";
74
83
  /** Budget-aware escalation: if fast path finishes early, spend remaining time on expansion + reranking */
75
84
  deepEscalation: boolean;
76
85
  /** Max time (ms) allowed for the fast path before escalation is considered */
@@ -78,9 +87,9 @@ export interface ProfileConfig {
78
87
  }
79
88
 
80
89
  export const PROFILES: Record<PerformanceProfile, ProfileConfig> = {
81
- speed: { tokenBudget: 400, maxResults: 5, useVector: false, vectorTimeout: 0, minScore: 0.55, deepEscalation: false, escalationBudgetMs: 0 },
82
- balanced: { tokenBudget: 800, maxResults: 10, useVector: true, vectorTimeout: 900, minScore: 0.45, deepEscalation: false, escalationBudgetMs: 0 },
83
- deep: { tokenBudget: 1200, maxResults: 15, useVector: true, vectorTimeout: 2000, minScore: 0.25, deepEscalation: true, escalationBudgetMs: 4000 },
90
+ speed: { tokenBudget: 400, maxResults: 5, useVector: false, vectorTimeout: 0, minScore: 0.55, minScoreRatio: 0.65, absoluteFloor: 0.18, activationFloor: 0.24, thresholdMode: "adaptive", deepEscalation: false, escalationBudgetMs: 0 },
91
+ balanced: { tokenBudget: 800, maxResults: 10, useVector: true, vectorTimeout: 900, minScore: 0.45, minScoreRatio: 0.55, absoluteFloor: 0.15, activationFloor: 0.20, thresholdMode: "adaptive", deepEscalation: false, escalationBudgetMs: 0 },
92
+ deep: { tokenBudget: 1200, maxResults: 15, useVector: true, vectorTimeout: 2000, minScore: 0.25, minScoreRatio: 0.45, absoluteFloor: 0.12, activationFloor: 0.16, thresholdMode: "adaptive", deepEscalation: true, escalationBudgetMs: 4000 },
84
93
  };
85
94
 
86
95
  export function getActiveProfile(): ProfileConfig {
@@ -178,7 +178,10 @@ export async function contextSurfacing(
178
178
  }
179
179
 
180
180
  // Phase 2: Cross-encoder reranking — reorder with deeper relevance signal
181
+ // Sort by score first so reranking covers the best candidates, not just
182
+ // the first-inserted (expansion hits appended later would otherwise be missed)
181
183
  if (Date.now() - startTime < 6000 && results.length >= 3) {
184
+ results.sort((a, b) => b.score - a.score);
182
185
  const toRerank = results.slice(0, 15).map(r => ({
183
186
  file: r.filepath,
184
187
  text: (r.body || "").slice(0, 2000),
@@ -253,8 +256,26 @@ export async function contextSurfacing(
253
256
  }
254
257
 
255
258
  // Apply composite scoring
256
- const scored = applyCompositeScoring(enriched, prompt)
257
- .filter(r => r.compositeScore >= minScore);
259
+ const allScored = applyCompositeScoring(enriched, prompt);
260
+
261
+ // Threshold filtering — adaptive (ratio-based) or absolute (legacy)
262
+ let scored: typeof allScored;
263
+ if (profile.thresholdMode === "adaptive") {
264
+ // Use max composite score across the set (not positional [0], which may be
265
+ // reordered by recency-intent sorting in applyCompositeScoring)
266
+ const bestScore = allScored.length > 0
267
+ ? Math.max(...allScored.map(r => r.compositeScore))
268
+ : 0;
269
+
270
+ // Activation floor: if even the best result is too weak, bail entirely
271
+ if (bestScore < profile.activationFloor) return makeEmptyOutput("context-surfacing");
272
+
273
+ const adaptiveMin = Math.max(bestScore * profile.minScoreRatio, profile.absoluteFloor);
274
+ scored = allScored.filter(r => r.compositeScore >= adaptiveMin);
275
+ } else {
276
+ // Legacy absolute threshold (backward compat)
277
+ scored = allScored.filter(r => r.compositeScore >= minScore);
278
+ }
258
279
 
259
280
  if (scored.length === 0) return makeEmptyOutput("context-surfacing");
260
281