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 +4 -2
- package/CLAUDE.md +4 -2
- package/README.md +24 -2
- package/SKILL.md +4 -2
- package/package.json +1 -1
- package/src/config.ts +12 -3
- package/src/hooks/context-surfacing.ts +23 -2
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:
|
|
635
|
-
|
|
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:
|
|
635
|
-
|
|
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 (
|
|
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),
|
|
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  :construction: Planned  :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:
|
|
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
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
|
|
257
|
-
|
|
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
|
|