ClawMem — On-device memory layer for Claude Code, OpenClaw, and Hermes agents
Memory server
First committed by yoloshii
Published in yoloshii/ClawMem. Publisher page
212 GitHub stars
What it is
On-device memory layer for AI agents. Claude Code, OpenClaw, and Hermes. Hooks + MCP server + hybrid RAG search.
AutoGineer overview, from the brain’s own files
ClawMem is a local-first memory system designed to provide persistent, context-aware memory for AI agents like Claude Code, OpenClaw, and Hermes. It operates entirely on-device without cloud dependencies or API keys, using a hybrid architecture that combines BM25, vector search, and multi-graph traversal. The system automatically captures session decisions, preferences, and milestones, while providing an MCP server and hooks to surface relevant context during agent interactions. It features sophisticated memory management, including contradiction detection, causal relationship inference, and document lifecycle policies, ensuring agents maintain continuity across sessions.
How it works
Memory model: Hybrid
AutoGineer overview, from the brain’s own files
ClawMem functions as a local SQLite-backed memory vault. It uses hooks to automatically inject relevant context into agent prompts and captures session data for future use. The system employs a hybrid retrieval model that includes BM25, vector search, and graph traversal to surface information. It processes data through an enrichment pipeline that extracts entities, links facts, and evolves memory metadata. Background workers handle maintenance tasks like consolidation and deductive synthesis, while the MCP server allows agents to perform targeted queries and retrieve specific information when needed.
| Folder | Role | Files |
|---|---|---|
| .github | agent-config | 5 |
| agents | agent-instructions | 1 |
| bin | scripts | 1 |
| docs | docs | 30 |
| scripts | scripts | 14 |
| src | source-code | 121 |
| tests | tests | 211 |
| eval-bundles | folder | 4 |
| extras | folder | 7 |
The agent reads
- query_plan evidence: AGENTS.md
- find_similar evidence: AGENTS.md
- find_causal_links evidence: AGENTS.md
- SKILL.md evidence: AGENTS.md
- CLAUDE.md evidence: CLAUDE.md
- AGENTS.md evidence: CLAUDE.md
The agent writes
- src/indexer.ts evidence: AGENTS.md
Requirements
Runtimes: Node.js, Bun
Databases: LanceDB, SQLite
API keys (by name): ANTHROPIC_API_KEY, CLAWMEM_API_TOKEN, CLAWMEM_EMBED_API_KEY, CLAWMEM_JUDGE_API_KEY, CLAWMEM_LLM_API_KEY, CLAWMEM_RERANK_API_KEY
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Google Antigravity, Kiro, OpenCode, Amp, Roo Code, Cline, JetBrains Junie, Devin (ex-Windsurf)
Set it up
This brain runs code automatically: 1 script. Review README.md before opening the folder in Claude Code. No step below turns a hook on for you.
README.md:- [Bun](https://bun.sh) v1.0+ — runtime for ClawMem. On Linux, install via `curl -fsSL https://bun.sh/install | bash` (not snap — snap Bun cannot read stdin, which breaks hooks).
- Not scanned by AutoGineerThe author’s MCP configuration (README.md) also starts it in a way AutoGineer does not offer. Read that file: AutoGineer did not scan that path; what it runs is listed under “This brain runs”. https://github.com/yoloshii/ClawMem/blob/284b55a3f23432d45412749c7717f32cfbdfbffa/README.md
- Not scanned by AutoGineerThe author’s README also describes installing it from a clone of its repository. Read its install section: AutoGineer did not scan that path. https://github.com/yoloshii/ClawMem/blob/284b55a3f23432d45412749c7717f32cfbdfbffa/README.md#install-from-source
- Not scanned by AutoGineerIts dependencies are installed by npm when you run it and were not scanned by AutoGineer (12 declared). https://www.npmjs.com/package/clawmem
First committed by yoloshii. Published in yoloshii/ClawMem. Licence: MIT License.
Usage
AutoGineer overview, from the brain’s own files
- Automatic context surfacing during agent prompts
- Persistent storage of session decisions and handoffs
- Targeted retrieval via MCP tools for cross-session questions
- Automated extraction of facts and causal links from transcripts
- “Why did we decide to use the current database schema?”
- The agent uses intent_search to traverse causal links and retrieve the specific decision record from past sessions.
- “What are the open questions from our last session?”
- The agent surfaces the session handoff and extracted open questions injected via the context-surfacing hook.
Documentation by yoloshii
ClawMem — On-device memory layer for Claude Code, OpenClaw, and Hermes agents
<p align="center"> <img src="docs/clawmem_hero.jpg" alt="ClawMem" width="100%"> </p>
On-device memory for Claude Code, OpenClaw, Hermes, and AI agents. Retrieval-augmented search, hooks, and an MCP server in a single local system. No API keys, no cloud dependencies.
ClawMem fuses recent research into a retrieval-augmented memory layer that agents actually use. The hybrid architecture combines QMD-derived multi-signal retrieval (BM25 + vector search + reciprocal rank fusion + query expansion + cross-encoder reranking), SAME-inspired composite scoring (recency decay, confidence, content-type half-lives, co-activation reinforcement), MAGMA-style intent classification with multi-graph traversal (semantic, temporal, and causal beam search), and A-MEM self-evolving memory notes that enrich documents with keywords, tags, and causal links between entries. Pattern extraction from Engram adds deduplication windows, frequency-based durability scoring, and temporal navigation.
Integrates via Claude Code hooks, an MCP server (works with any MCP-compatible client), a native OpenClaw plugin, or a Hermes Agent MemoryProvider plugin. All paths write to the same local SQLite vault. A decision captured during a Claude Code session shows up immediately when an OpenClaw or Hermes agent picks up the same project.
TypeScript on Bun. MIT License.
What It Does
ClawMem turns your markdown notes, project docs, and research dumps into persistent memory for AI coding agents. It automatically:
Surfaces relevant context on every prompt (context-surfacing hook)
Bootstraps sessions with your profile, latest handoff, recent decisions, and stale notes
Captures decisions, preferences, milestones, and problems from session transcripts using a local GGUF observer model
Imports conversation exports from Claude Code, ChatGPT, Claude.ai, Slack, and plain text via
clawmem mine, with optional post-import LLM fact extraction (--synthesize) that pulls structured decisions / preferences / milestones / problems and cross-fact links out of otherwise full-text conversation dumps (v0.7.2). Imports preserve authorship time (v0.27.0): ranking recency and temporal queries run on when content was actually written, so historical conversations mined today don't rank as fresh — with a metadata-only--backfill-dateslane for vaults mined earlierGenerates handoffs at session end so the next session can pick up where you left off
Learns what matters via a feedback loop that boosts referenced notes and decays unused ones
Guards against prompt injection in surfaced content
Classifies query intent (WHY / WHEN / ENTITY / WHAT) to weight search strategies
Traverses multi-graphs (semantic, temporal, causal) via adaptive beam search
Evolves memory metadata as new documents create or refine connections
Infers causal relationships between facts extracted from session observations
Detects contradictions between new and prior decisions, auto-decaying superseded ones — when a contradiction judge is configured (
CLAWMEM_JUDGE_*, v0.29.0; disabled otherwise) (with an additional merge-time contradiction gate in the consolidation worker that blocks cross-observation contradictions before they land, v0.7.1)Guards against cross-entity merges during consolidation — name-aware dual-threshold merge safety compares entity anchors before merging similar observations, preventing "Alice decided X" from merging into "Bob decided X" (v0.7.1)
Prevents context bleed in derived insights — the Phase 3 deductive synthesis pipeline validates every draft against an anti-contamination wrapper (deterministic entity contamination check + LLM validator + dedupe) before writing cross-session deductive observations (v0.7.1)
Frames surfaced facts as background knowledge —
context-surfacingwraps injected content in<instruction>+<facts>+<relationships>blocks, telling the model to treat facts as already-known and exposing memory-graph edges between surfaced docs directly in-prompt (v0.7.1)Injects knowledge-graph facts as structured triples — when the user's prompt mentions entities already known to the vault,
context-surfacingresolves them via a three-path prompt-only extractor (canonical IDs, proper nouns, lowercased n-grams), queries the SPO graph for current-state triples, and appends a<vault-facts>block of rawsubject predicate objectlines to<vault-context>— off forspeed, 200 tokens onbalanced, 250 ondeep, token-truncated at the triple boundary (v0.9.0)Session-scoped focus topic —
clawmem focus set "<topic>" --session-id <id>writes a per-session focus file used as a snippet-selection intent: surfaced docs prefer sentences matching the topic. Presentation only since v0.38.0 — a focus never changes expansion, reranking, scoring, ordering, or the surfaced set — session-isolated, fail-open, never writes to SQLite or lifecycle columns (v0.9.0, narrowed v0.38.0)Ranks hook injections on one channel-aware key — every retrieval leg (BM25, vector, file-aware, gated prior-turn, expansion variants) contributes a ranked lane; weighted reciprocal-rank fusion yields a single ordering key (current-support band, fused mass) that decides membership, final order, AND admission — no mixed raw-score sorts, no metadata reordering (v0.38.0)
Admits by relevance, abstains honestly — the context-surfacing hook admits candidates by a relative floor on the fused ordering key and abstains at query level when current-turn support is missing or keyword-degenerate, instead of surfacing weak lists (v0.38.0)
Guards the deep rerank lane — cross-encoder scores apply only under full candidate coverage AND a discriminating score set (degeneracy gate); the reranker joins the final order as a rank-fused lane, and remote rerank scores are cached only under an attested provider identity (
clawmem rerank-health) (v0.38.0)Keeps the hook's write path off your prompt latency — turn alignment is one early fail-closed row; recall attribution, token accounting, and vault mirrors are handed to a detached drainer process through an on-disk spool after the payload is emitted (v0.38.0)
Scores document quality using structure, keywords, and metadata richness signals
Boosts co-accessed documents — notes the agent verifiably referenced together in one turn (v0.41.0) get retrieval reinforcement on the composite MCP surfaces (removed from hook ordering in v0.38.0 — the injected order is the channel-aware fusion key alone)
Decomposes complex queries into typed retrieval clauses (BM25/vector/graph) for multi-topic questions
Cleans stale embeddings automatically before embed runs, removing orphans from deleted/changed documents
Transaction-safe indexing — crash mid-index leaves zero partial state (atomic commit with rollback)
Processes each turn once — the extraction and handoff hooks keep a cursor per transcript and the feedback hook decides each surfaced turn once (v0.41.0), so a turn is extracted, summarised and credited once instead of again at every response, and each session's documents are its own
Navigates temporal neighborhoods around any document via the
timelinetool — progressive disclosure from search to chronological context to full contentBoosts frequently-revised memories — documents with higher revision counts get a durability signal in composite scoring (capped at 10%)
Supports pin/snooze lifecycle for persistent boosts and temporary suppression
Manages document lifecycle — policy-driven archival sweeps with restore capability
Auto-routes queries via
memory_retrieve— classifies intent and dispatches to the optimal search backendSyncs project issues from Beads issue trackers into searchable memory
Runs a quiet-window heavy maintenance lane — a second consolidation worker, off by default behind
CLAWMEM_HEAVY_LANE=true, that runs on a longer interval only inside a configurable hour window. Gated bycontext_usagequery-rate so it never competes for CPU/GPU with interactive sessions, scoped exclusively via DB-backedworker_leases, stale-first by default with an optional surprisal selector, and journals every attempt inmaintenance_runsfor operator visibility (v0.8.0)
Runs fully local with no API keys and no cloud services. Integrates via Claude Code hooks and MCP tools, as a native OpenClaw plugin, or as a Hermes Agent MemoryProvider plugin. All modes share the same vault for cross-runtime memory. Works with any MCP-compatible client.
Full version history is in RELEASE_NOTES.md. Upgrade instructions for existing vaults are in docs/guides/upgrading.md.
Architecture
<p align="center"> <img src="docs/clawmem-architecture.png" alt="ClawMem Architecture" width="100%"> </p>
Install
Platform Support
| Platform | Status | Notes |
|---|---|---|
| Linux | Full support | Primary target. systemd services for watcher + embed timer. |
| macOS | Full support | Homebrew SQLite handled automatically. GPU via Metal (llama.cpp). |
| Windows (WSL2) | Full support | Recommended for Windows users. Install Bun + ClawMem inside WSL2. |
| Windows (native) | Not recommended | Bun and sqlite-vec work, but bin/clawmem wrapper is bash, hooks expect bash commands, and systemd services have no equivalent. Use WSL2 instead. |
Prerequisites
Required:
Bun v1.0+ — runtime for ClawMem. On Linux, install via
curl -fsSL https://bun.sh/install | bash(not snap — snap Bun cannot read stdin, which breaks hooks).SQLite with FTS5 — included with Bun. On macOS, install
brew install sqlitefor extension loading support (ClawMem detects and uses Homebrew SQLite automatically).
Optional (for better performance):
llama.cpp (
llama-server) — for dedicated GPU inference. Without it,node-llama-cppruns models in-process (auto-downloads on first use). GPU servers give better throughput and prevent silent CPU fallback.systemd (Linux) or launchd (macOS) — for persistent background services (watcher, embed timer, GPU servers). ClawMem ships systemd unit templates; macOS users can create equivalent launchd plists. See systemd services.
Optional integrations:
Claude Code — for hooks + MCP integration
OpenClaw — for native plugin integration
Hermes Agent — for
MemoryProviderplugin integrationbd CLI v0.58.0+ (verified through v1.1.0) — for Beads issue tracker sync (only if using Beads)
Install from npm (recommended)
npm install -g clawmemIf you use Bun as your package manager:
bun add -g clawmemInstall from source
git clone https://github.com/yoloshii/clawmem.git ~/clawmem
cd ~/clawmem && bun install
ln -sf ~/clawmem/bin/clawmem ~/.bun/bin/clawmemSetup roadmap
After installing, here's the full journey from zero to working memory:
| Step | What | How | Details |
|---|---|---|---|
| 1. Bootstrap | Create a vault, index your first collection, embed, install hooks and MCP | clawmem bootstrap ~/notes --name notes | One command does it all. Or run each step manually (see below). |
| 2. Choose models | Pick embedding + reranker models based on your hardware | 16GB+ VRAM → SOTA stack (zembed-1 + zerank-2). Less → QMD native combo. No GPU → cloud embedding or CPU fallback. | Inference services |
| 3. Download models | Get the model files for your chosen stack (GGUFs for all three services; for zerank-2, only a GGUF that carries its score head works) | wget from HuggingFace, let node-llama-cpp auto-download the QMD native models, or build the zerank-2 bf16 sidecar | Inference services |
| 4. Start services | Run GPU servers (if using dedicated GPU) and background services. Optionally enable the v0.8.2 background maintenance workers in the watcher unit so consolidation + deductive synthesis run automatically. | llama-server for each model. systemd units for watcher + embed timer. Drop-in for the watcher to enable workers + tune intervals + set the quiet window. | systemd services, background workers |
| 5. Decide what to index | Add collections for your projects, notes, research, and domain docs | clawmem collection add ~/project --name project | The more relevant markdown you index, the better retrieval works. See building a rich context field. |
| 6. Connect your agent | Hook into Claude Code, OpenClaw, Hermes, or any MCP client | clawmem setup hooks && clawmem setup mcp for Claude Code. clawmem setup openclaw for OpenClaw. Copy src/hermes/ to Hermes plugins for Hermes. | Integration |
| 7. Verify | Confirm everything is working | clawmem doctor (full health check) or clawmem status (quick index stats) | Verify Installation |
Fastest path: Step 1 alone gets you a working system with in-process CPU/GPU inference and default models — no manual model downloads or service configuration needed. Steps 2-4 are optional upgrades for better performance. Steps 5-6 are where you customize what gets indexed and how your agent connects.
Customize what gets indexed: Each collection has a pattern field in ~/.config/clawmem/config.yaml (default: **/*.md). Tailor it per collection — index project docs, research notes, decision records, Obsidian vaults, or anything else your agents should know about. The more relevant content in the vault, the better retrieval works. See the quickstart for config examples.
Quick start commands
# One command: init + index + embed + hooks + MCP
clawmem bootstrap ~/notes --name notes
# Or step by step:
clawmem init
clawmem collection add ~/notes --name notes
clawmem update --embed
clawmem setup hooks
clawmem setup mcp
# Add more collections (the more you index, the richer retrieval gets)
clawmem collection add ~/projects/myapp --name myapp
clawmem collection add ~/research --name research
clawmem update --embed
# Verify
clawmem doctorUpgrading
bun update -g clawmem # or: npm update -g clawmemDatabase schema migrates automatically on next startup (new tables and columns are added via CREATE IF NOT EXISTS / ALTER TABLE ADD COLUMN).
After major version updates (e.g. 0.1.x → 0.2.0) that add new enrichment pipelines, run a full enrichment pass to backfill existing documents:
clawmem reindex --enrich # Full enrichment: entity extraction (backfill) + links + evolution for all docs
clawmem embed # Re-embed if upgrading embedding models (not needed for most updates)--enrich runs the complete A-MEM pipeline (entity extraction, link generation, memory evolution) on all documents, not just new ones; entity extraction inside it skips a document unchanged since its last extraction (enrichment lifecycle). Without it, reindex only refreshes metadata for existing docs.
Routine patch updates (e.g. 0.2.0 → 0.2.1) do not require reindexing.
For version-specific upgrade notes (opt-in features, optional cleanup steps, verification commands), see docs/guides/upgrading.md.
Integration
Claude Code
ClawMem integrates via hooks (settings.json) and an MCP stdio server. Hooks handle 90% of retrieval automatically - the agent never needs to call tools for routine context.
clawmem setup hooks # Install lifecycle hooks (SessionStart, UserPromptSubmit, Stop, PreCompact)
clawmem setup mcp # Register MCP server in ~/.claude.json (33 tools)Automatic (90%): context-surfacing injects relevant memory on every prompt. postcompact-inject re-injects state after compaction. decision-extractor, handoff-generator, feedback-loop capture session state on stop.
Agent-initiated (10%): MCP tools (query, intent_search, find_causal_links, timeline, etc.) for targeted retrieval when hooks don't surface what's needed.
OpenClaw
ClawMem registers as a native OpenClaw memory plugin (kind: memory, v0.10.0+). Same 90/10 automatic retrieval, delivered through OpenClaw's plugin-hook bus instead of Claude Code hooks.
# v0.10.4+: profile-aware. Delegates to `openclaw plugins install --force` when the OpenClaw CLI
# is on PATH (auto-enables the plugin, honors OPENCLAW_STATE_DIR, OPENCLAW_CONFIG_PATH, --profile).
# Falls back to a recursive copy honoring OPENCLAW_STATE_DIR when the CLI is absent.
clawmem setup openclaw
# Custom profile (e.g. dev profile at ~/.openclaw-dev):
OPENCLAW_STATE_DIR=~/.openclaw-dev clawmem setup openclawWhat the plugin provides:
before_prompt_buildhook (load-bearing) - prompt-aware retrieval (context-surfacing + session-bootstrap) AND the pre-emptiveprecompact-extractrun when token usage approaches the compaction threshold. This is the authoritative path for precompact state capture because it runs synchronously before the LLM call that would trigger compaction, so it cannot race the compactor.agent_endhook - decision extraction, handoff generation, feedback loop (parallel, fire-and-forget at the OpenClaw call site). OpenClaw v2026.4.26+ also enforces a 30s default void-hook timeout onagent_end— slow handlers are logged but the underlying postrun work is not cancelled (fail-open).before_compactionhook (defense-in-depth fallback) - firesprecompact-extractagain for the rare case wherebefore_prompt_build's proximity heuristic missed a sudden token-count jump. Fire-and-forget at OpenClaw's call site, so it races the compactor and offers no correctness guarantee on its own — thebefore_prompt_buildpath is what actually holds the invariant.session_starthook - session registration + cached first-turn bootstrap context5 agent tools -
clawmem_search,clawmem_get,clawmem_session_log,clawmem_timeline,clawmem_similar
Disable OpenClaw's native memory search to avoid duplicate injection:
openclaw config set agents.defaults.memorySearch.extraPaths "[]"ClawMem coexists cleanly with OpenClaw's Active Memory plugin (v2026.4.10+) and, on OpenClaw v2026.4.18+ (#65411), with the memory-core dreaming sidecar — both run alongside ClawMem instead of being mutually exclusive. They search different backends and inject into different prompt regions, so they do not conflict. See the OpenClaw plugin guide — Active Memory coexistence and the memory-core dreaming sidecar section for the two patterns.
Pair ClawMem (memory) with a context-engine plugin (v0.10.0+). OpenClaw and Hermes maintainers have converged on a two-surface plugin model: one slot for memory plugins (cross-session, retrieval-first) and a separate slot for context-engine plugins (in-session, compression/compaction-first). Under that model ClawMem is a memory layer — it has always been one in Hermes via the MemoryProvider ABC, and v0.10.0 moves the OpenClaw integration to the same semantic slot. You can now run ClawMem in the memory slot alongside an LCM-style compression plugin (for example, lossless-claw) in the context-engine slot. The two plugins do not overlap: one persists across sessions, the other reshapes the live window. See the OpenClaw plugin guide — memory vs context engine for the full rationale.
OpenClaw v2026.4.11+ recommended (required for ClawMem v0.10.0+). v2026.4.11 introduced a new plugin discovery contract that requires each plugin directory to ship a
package.jsonwithopenclaw.extensionsdeclared, and that rejects symlinked plugin directories. ClawMem v0.10.0 includes both fixes. Older ClawMem versions (< v0.10.0) on OpenClaw v2026.4.11+ will fail to discover silently — upgrade ClawMem, then re-runclawmem setup openclaw. See docs/guides/upgrading.md.
Alternative: OpenClaw agents can also use ClawMem's MCP server directly (clawmem setup mcp), with or without hooks. This gives full access to all 33 MCP tools but bypasses OpenClaw's plugin lifecycle, so you lose token budget awareness, native compaction orchestration, and the agent_end message pipeline. The native OpenClaw plugin is recommended for new setups; MCP is available as an additional or standalone integration.
Hermes Agent
ClawMem integrates as a native MemoryProvider plugin — Hermes's pluggable interface for agent memory. Same automatic retrieval and extraction, delivered through Hermes's memory lifecycle instead of Claude Code hooks.
Install:
# Preferred — user-plugin path (Hermes #10529, v2026.4.13+).
# Survives `git pull` of hermes-agent and avoids dual-registration with bundled providers.
# Copies the directory's CONTENTS, so the same command installs and upgrades.
mkdir -p "${HERMES_HOME:-$HOME/.hermes}/plugins/clawmem"
cp -r /path/to/ClawMem/src/hermes/. "${HERMES_HOME:-$HOME/.hermes}/plugins/clawmem/"
# Or, the bundled-style path (always supported, takes precedence on name collisions).
# Recommended only when you actively work in the hermes-agent source tree.
mkdir -p /path/to/hermes-agent/plugins/memory/clawmem
cp -r /path/to/ClawMem/src/hermes/. /path/to/hermes-agent/plugins/memory/clawmem/
# Symlink alternative for in-place development (either path).
ln -s /path/to/ClawMem/src/hermes ${HERMES_HOME:-~/.hermes}/plugins/clawmemConfigure in your Hermes profile's .env or environment:
CLAWMEM_BIN=/path/to/clawmem # Path to clawmem binary (or ensure it's on PATH)
CLAWMEM_SERVE_PORT=7438 # REST API port (default: 7438)
CLAWMEM_SERVE_MODE=external # "external" (you run clawmem serve) or "managed" (plugin manages it)
CLAWMEM_PROFILE=balanced # speed | balanced | deepThen set memory.provider: clawmem in your Hermes config.yaml, or run hermes memory setup to configure interactively.
What the plugin provides:
prefetch()— prompt-aware retrieval viacontext-surfacinghook (automatic every turn)sync_turn()— appends the turn to the plugin's transcript, then runs decision extraction, handoff generation and the feedback loop over it in the background (v0.41.0: after every turn; each turn is processed once)on_session_end()— a last pass, then the SessionEnd handoff flushon_pre_compress()— pre-compaction state preservationsession-bootstrap— session registration + first-turn context injection5 agent tools —
clawmem_retrieve,clawmem_get,clawmem_session_log,clawmem_timeline,clawmem_similarPlugin-managed transcript — maintains its own JSONL transcript for ClawMem hooks
Requirements: clawmem binary on PATH and clawmem serve running (external mode) or the plugin starts it automatically (managed mode). Python 3.10+. No pip dependencies beyond Hermes itself (uses urllib for REST calls, httpx optional for better performance).
Alternative: Hermes also has built-in MCP client support. You can add ClawMem as an MCP server in Hermes's config.yaml under mcp_servers for tool-only access. But this misses the lifecycle hooks (prefetch, session_end, pre_compress), so the native plugin is recommended.
See Hermes plugin guide for architecture details, lifecycle mapping, and troubleshooting.
Multi-Framework Operation
All three integrations share the same SQLite vault by default. Claude Code, OpenClaw, and Hermes can run simultaneously — decisions captured in one runtime are immediately available in the others, giving agents persistent shared memory across sessions and platforms. WAL mode + busy_timeout handles concurrent access.
Multi-Vault (Optional)
By default, ClawMem uses a single vault at ~/.cache/clawmem/index.sqlite. For users who want separate memory domains (e.g., work vs personal, or isolated vaults per project), ClawMem supports named vaults.
Configure in ~/.config/clawmem/config.yaml:
vaults:
work: ~/.cache/clawmem/work.sqlite
personal: ~/.cache/clawmem/personal.sqliteOr via environment variable:
export CLAWMEM_VAULTS='{"work":"~/.cache/clawmem/work.sqlite","personal":"~/.cache/clawmem/personal.sqlite"}'Using vaults with MCP tools:
All retrieval tools (memory_retrieve, query, search, vsearch, intent_search) accept an optional vault parameter. Omit it to use the default vault.
# Search the default vault (no vault param needed)
query("authentication flow")
# Search a named vault
query("project timeline", vault="work")
# List configured vaults
list_vaults()
# Sync content into a vault
vault_sync(vault="work", content_root="~/work/docs")Single-vault users: No action needed. Everything works without configuration. The vault parameter is always optional and ignored when no vaults are configured.
Inference services (GPU, in-process, or cloud)
ClawMem uses three inference services — embedding, LLM (query expansion / intent / A-MEM / the Stop hooks' observer), and reranker. In the default stack all three run as llama-server instances, each with an in-process node-llama-cpp fallback that auto-downloads on first use, so ClawMem works without a dedicated GPU (Metal on Apple Silicon, Vulkan where available, CPU as last resort). The bin/clawmem wrapper points at localhost:8088/8089/8090. Always run via bin/clawmem — it sets the endpoints.
Choose a stack:
| Stack | Models | VRAM | License | When |
|---|---|---|---|---|
| QMD native (default) | EmbeddingGemma-300M + qmd-query-expansion-1.7B + qwen3-reranker-0.6B | ~4 GB, or in-process | Permissive — commercial OK | Any GPU or none; zero-config start |
| z / SOTA | zembed-1 + qmd-query-expansion-1.7B + zerank-2 (Q8_0 GGUF that carries its score head) | ~13 GB | Apache-2.0 — commercial OK | 16 GB+ GPU; best recall |
| Cloud embedding | Jina / OpenAI / Voyage / Cohere (embedding only) | none | provider ToS | No local GPU for embedding; LLM + reranker stay local |
Heads-up before you serve: most zerank-2 GGUFs are inert — llama.cpp's standard converter drops the score head. Serve the Q8_0 GGUF that carries it (launch line) or the bf16 seq-cls sidecar, and verify with clawmem rerank-health. zembed-1 / reranking need -ub = -b (non-causal attention). Changing embedding dimensions requires clawmem embed --force. Set CLAWMEM_NO_LOCAL_MODELS=true to fail fast instead of silent CPU fallback.
→ Full stack decision matrix, model/VRAM tables, and server-setup commands: docs/guides/inference-services.md. Cloud providers, batch + TPM behavior: docs/guides/cloud-embedding.md. All environment variables: docs/reference/configuration.md. Keeping servers running: docs/guides/systemd-services.md.
MCP Server
ClawMem exposes 33 MCP tools via the Model Context Protocol and an optional HTTP REST API. Any MCP-compatible client or HTTP client can use it.
Claude Code (automatic):
./bin/clawmem setup mcp # Registers in ~/.claude.jsonManual (any MCP client):
Add to your MCP config (e.g. ~/.claude.json, claude_desktop_config.json, or your client's equivalent):
{
"mcpServers": {
"clawmem": {
"command": "/absolute/path/to/clawmem/bin/clawmem",
"args": ["mcp"]
}
}
}The server runs via stdio — no network port needed. The bin/clawmem wrapper sets the GPU endpoint env vars automatically.
Verify: After registering, your client should see tools including memory_retrieve, search, vsearch, query, query_plan, intent_search, timeline, etc.
HTTP REST API (optional)
For web dashboards, non-MCP agents, cross-machine access, or programmatic use:
./bin/clawmem serve # localhost:7438; every request needs the token (below)
./bin/clawmem serve --port 8080 # custom port
./bin/clawmem serve-token # print the token serve usesEndpoints:
| Method | Path | Description |
|---|---|---|
| GET | /health | Liveness probe + version + doc count |
| GET | /stats | Full index statistics |
| POST | /search | Unified search (mode: auto/keyword/semantic/hybrid) |
| POST | /retrieve | Smart retrieve with auto-routing (mode: auto/keyword/semantic/causal/timeline/hybrid) |
| GET | /documents/:docid | Single document by 6-char hash prefix |
| GET | /documents?pattern=... | Multi-get by glob pattern |
| GET | /timeline/:docid | Temporal neighborhood (before/after) |
| GET | /sessions | Recent session history |
| GET | /collections | List all collections |
| GET | /lifecycle/status | Active/archived/forgotten/pinned/snoozed counts + deactivation_reasons (absent/forget/archive/unknown_legacy) |
| POST | /documents/:docid/pin | Pin/unpin |
| POST | /documents/:docid/snooze | Snooze until date |
| POST | /documents/:docid/forget | Deactivate |
| POST | /lifecycle/sweep | Archive stale docs (dry_run default) |
| GET | /graph/causal/:docid | Causal chain traversal |
| GET | /graph/similar/:docid | k-NN neighbors |
| GET | /export | Active-document export as JSON (?full=true includes legacy precompact-state.md snapshot copies) |
| POST | /reindex | Trigger re-scan |
| POST | /graphs/build | Rebuild temporal + semantic graphs |
Auth (v0.42.0): every request needs Authorization: Bearer <token>: CLAWMEM_API_TOKEN when set (32+ characters), otherwise the token file serve generates at ~/.config/clawmem/serve-token; clawmem serve-token prints it. Every POST needs Content-Type: application/json, and requests from web pages (a foreign Origin or Host) are refused. See the REST API reference.
Search example:
curl -X POST http://localhost:7438/search \
-H "Authorization: Bearer $(clawmem serve-token)" \
-H 'Content-Type: application/json' \
-d '{"query": "authentication decisions", "mode": "hybrid", "compact": true}'Verify Installation
./bin/clawmem doctor # Full health check
./bin/clawmem status # Quick index status
bun test # Run test suite (from the repository root)Agent Instructions
ClawMem ships agent instruction files and an optional maintenance agent:
| File | Loaded | Purpose |
|---|---|---|
AGENTS.md | Automatically (most agents, when working in this repo) | Lean root SSOT — agent-facing quick reference (inference at a glance, install, retrieval routing, MCP tools, indexing rules, integrations) + an index into docs/ |
CLAUDE.md | Automatically (Claude Code) | @AGENTS.md import — Claude Code reads CLAUDE.md natively, so it just pulls in the SSOT |
SKILL.md | On-demand (agent reads when needed) | Portable operating reference — escalation gate, tool routing, the 4 query-optimization levers, pipeline behavior, composite scoring, lifecycle. Shipped with the package for cross-project use |
docs/ | On-demand (linked throughout AGENTS.md) | Deep reference — inference setup, configuration, concepts, internals, guides, troubleshooting |
agents/clawmem-curator.md | On-demand via clawmem setup curator | Maintenance agent — lifecycle triage, retrieval health checks, dedup sweeps, graph rebuilds |
Working in the ClawMem repo: No action needed — CLAUDE.md (which imports AGENTS.md) loads automatically.
Using ClawMem from other projects: Your agent needs instructions on how to use ClawMem's hooks and MCP tools. Two options:
Option A: Copy instructions into your project
Copy the contents of AGENTS.md (or the relevant sections) into your project's own AGENTS.md or CLAUDE.md. Simple but requires manual updates when ClawMem changes.
Option B: Add a trigger block (recommended)
Add this minimal trigger block to your global ~/.claude/CLAUDE.md. It gives the agent routing rules always loaded, and tells it how to find the full reference (SKILL.md) shipped with your installation when deeper guidance is needed:
## ClawMem
Architecture: hooks (automatic, ~90%) + MCP tools (explicit, ~10%).
Vault: `~/.cache/clawmem/index.sqlite` | Config: `~/.config/clawmem/config.yaml`
### Escalation Gate (3 rules — ONLY escalate to MCP tools when one fires)
1. **Low-specificity injection** — `<vault-context>` is empty or lacks the specific fact needed
2. **Cross-session question** — "why did we decide X", "what changed since last time"
3. **Pre-irreversible check** — before destructive or hard-to-reverse changes
### Tool Routing (once escalated)
**Preferred:** `memory_retrieve(query)` — auto-classifies and routes to the optimal backend.
**Direct routing** (when calling specific tools):
"why did we decide X" → intent_search(query) NOT query()
"what happened last session" → session_log() NOT query()
"what else relates to X" → find_similar(file) NOT query()
Complex multi-topic → query_plan(query) NOT query()
General recall → query(query, compact=true)
Keyword spot check → search(query, compact=true)
Conceptual/fuzzy → vsearch(query, compact=true)
Full content → multi_get("path1,path2")
Lifecycle health → lifecycle_status()
Stale sweep → lifecycle_sweep(dry_run=true)
Restore archived → lifecycle_restore(query)
ALWAYS `compact=true` first → review → `multi_get` for full content.
### Proactive Use (no escalation gate needed)
- User says "remember this" / critical decision made → `memory_pin(query)` immediately
- User corrects a misconception → `memory_pin(query)` the correction
- `<vault-context>` surfaces irrelevant/noisy content → `memory_snooze(query, until)` for 30 days
- Need to correct a memory → `memory_forget(query)`
- After bulk ingestion → `build_graphs`
### Anti-Patterns
- Do NOT use `query()` for everything — match query type to tool, or use `memory_retrieve`
- Do NOT call query/intent_search every turn — 3 rules above are the only gates
- Do NOT re-search what's already in `<vault-context>`
- Do NOT pin everything — pin is for persistent high-priority items, not routine decisions
- Do NOT forget memories to "clean up" — let confidence decay handle it
- Do NOT wait for curator to pin decisions — pin immediately when critical
For detailed operating guidance (escalation gate, tool routing, query-optimization levers, pipeline behavior, composite scoring, lifecycle), find and read the shipped SKILL.md (setup, inference, and internals live in AGENTS.md + docs/):
Bash: CLAWMEM_ROOT=$(cd "$(dirname "$(which clawmem)")/.." && pwd) && echo "$CLAWMEM_ROOT/SKILL.md"
Then: Read the file at that path.This gives your agent the 3-rule gate, tool routing, and proactive behaviors always loaded. When it needs deeper guidance, it locates and reads the full SKILL.md reference shipped with your installation — no symlinks or skill registration required.
CLI Reference
clawmem init Create DB + config
clawmem bootstrap <vault> [--name N] [--skip-embed] One-command setup
clawmem collection add <path> --name <name> Add a collection
clawmem collection list List collections
clawmem collection remove <name> Remove a collection
clawmem update [--pull] [--embed] Incremental re-scan
clawmem mine <dir> [-c name] [--embed] [--synthesize] Import conversation exports (--synthesize runs post-import LLM fact extraction, v0.7.2; preserves per-exchange authored_at, v0.27.0)
clawmem mine <dir> -c name --backfill-dates [--apply] Derive authored_at for already-mined docs (metadata-only; dry-run without --apply)
clawmem embed [-f] Generate fragment embeddings
clawmem reindex [--force] Full re-index
clawmem watch File watcher daemon
clawmem search <query> [-n N] [--json] BM25 keyword search
clawmem vsearch <query> [-n N] [--json] Vector semantic search
clawmem query <query> [-n N] [--json] Full hybrid pipeline
clawmem profile Show user profile
clawmem profile rebuild Force profile rebuild
clawmem update-context Regenerate per-folder CLAUDE.md
clawmem list [-n/--limit N] [-c col] [--json] Browse recent documents
clawmem budget [--session ID] Token utilization
clawmem log [--last N] Session history
clawmem hook <name> Manual hook trigger
clawmem surface --context --stdin IO6: pre-prompt context injection
clawmem surface --bootstrap --stdin IO6: per-session bootstrap injection
clawmem reflect [N] Cross-session reflection (last N days, default 14)
clawmem consolidate [--dry-run] [N] Find and archive duplicate low-confidence docs
clawmem eval run --gold <file.jsonl> Offline eval: replay gold-labeled queries, score J_doc/recall/MRR
clawmem install-service [--enable] [--remove] Systemd watcher service
clawmem setup hooks [--remove] Install/remove Claude Code hooks
clawmem setup mcp [--remove] Register/remove MCP server
clawmem setup curator [--remove] Install/remove curator maintenance agent
clawmem mcp Start stdio MCP server
clawmem serve [--port 7438] [--host 127.0.0.1] [--no-token] Start HTTP REST API server (token required)
clawmem serve-token Print the token serve uses
clawmem path Print database path
clawmem doctor Full health check
clawmem status Quick index statusMCP Tools (31)
Registered by clawmem setup mcp. Available to any MCP-compatible client.
Internal-collection visibility (v0.21.0): the retrieval tools search, vsearch, query, query_plan, memory_retrieve, and find_similar (plus memory_rank since v0.36.0) 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.
| Tool | Description |
|---|---|
__IMPORTANT | Workflow guide: prefer memory_retrieve → match query type to tool → multi_get for full content |
Core Search & Retrieval
| Tool | Description |
|---|---|
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. |
search | BM25 keyword search — for exact terms, config names, error codes, filenames. v0.24.0: non-recency queries rank by the RAW BM25 transform (scoreBasis: "fts-bm25"; judged keyword eval MRR 0.848 vs composite 0.415; metadata breaks exact ties only; minScore filters raw, no default); recency-intent queries keep composite. Collection filter supports comma-separated values. Prefer memory_retrieve for auto-routing. |
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. |
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. |
get | Retrieve single document by path or docid |
multi_get | Retrieve multiple docs by glob or comma-separated list |
find_similar | USE THIS for "what else relates to X", "show me similar docs". Finds k-NN vector neighbors — discovers connections beyond keyword overlap that search/query cannot find. |
Intent-Aware Search
| Tool | Description |
|---|---|
intent_search | USE THIS for "why did we decide X", "what caused Y", "who worked on Z". Classifies intent (WHY/WHEN/ENTITY/WHAT), traverses causal + semantic graph edges. Returns decision chains that query() cannot find. |
query_plan | USE THIS for complex multi-topic queries ("tell me about X and also Y", "compare A with B"). Decomposes into parallel typed clauses (bm25/vector/graph), executes each, merges via RRF. query() searches as one blob — this tool splits topics and routes each optimally. |
intent_search pipeline: Query → Intent Classification → BM25 + Vector → Intent-Weighted RRF → Graph Expansion (WHY/ENTITY intents) → Cross-Encoder Reranking → Composite Scoring
query_plan pipeline: Query → LLM decomposition into 2-4 typed clauses → Parallel execution (BM25/vector/graph per clause) → RRF merge across clauses → Composite scoring. Falls back to single-query for simple inputs.
Multi-Graph & Causal
| Tool | Description |
|---|---|
build_graphs | Build temporal and/or semantic graphs from document corpus |
find_causal_links | Trace decision chains: "what led to X", "how we got from A to B". Follow up intent_search with this tool on a top result to walk the full causal chain. Traverses causes / caused_by / both up to N hops with depth-annotated reasoning. |
kg_query | Query the SPO knowledge graph: "what does X relate to?", "what was true about X when?". Returns temporal entity-relationship triples with validity windows. Accepts an entity name or a canonical ID in vault:type:slug form; an exact name wins over a partial match, and entities that share the name are listed separately (resolution). Triples are populated by the decision-extractor hook from observer-emitted <triples> blocks. |
memory_evolution_status | Show how a document's A-MEM metadata evolved over time |
timeline | Show the temporal neighborhood around a document — what was created/modified before and after it. Progressive disclosure: search → timeline (context) → get (full content). Supports same-collection scoping and session correlation. |
Beads Integration
| Tool | Description |
|---|---|
beads_sync | Sync Beads issues from Dolt backend (bd CLI) into memory: syncs the full backlog (no 50-issue cap), creates docs, bridges all dep types to memory_relations, surfaces bd ≥1.1.0 claim leases, runs A-MEM enrichment |
Vault Management
| Tool | Description |
|---|---|
list_vaults | Show configured vault names and paths. Empty in single-vault mode. |
vault_sync | Index markdown from a directory into a named vault. Restricted-path validation rejects sensitive directories. |
Agent Diary
| Tool | Description |
|---|---|
diary_write | Write a diary entry. Use for recording important events, decisions, or observations in environments without hook support. Stored as searchable memories. |
diary_read | Read recent diary entries. Filter by agent name. |
Memory Management & Lifecycle
| Tool | Description |
|---|---|
memory_forget | Search → deactivate closest match (with audit trail). Weak matches return a disambiguation list instead of acting (v0.23.0) |
memory_pin | Pin a memory: lifecycle retention + priority among relevance-equivalent results (+0.3 composite boost on hook/query surfaces; exact-tie precedence on the raw routes — vector + search non-recency). 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. |
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. |
status | Index health with content type distribution |
reindex | Trigger vault re-scan |
index_stats | Detailed stats: types, staleness, access counts, sessions |
memory_stats | Lifecycle + ranking-metadata aggregates per collection (v0.36.0): origin×active cross-tabs, pinned, accrual, deactivation reasons, and access/confidence/quality/effective-age distributions (mean/median/min/max over active rows). Deeper than index_stats; includes system collections. |
memory_rank | Ranking diagnostic (v0.36.0): real-pipeline composite breakdown per result — weights, recency, confidence blend, quality/length/frequency/canonical multipliers, signed pinΔ, co-activation — plus raw-vs-composite rank shifts; demoted raw winners stay visible. FTS-only candidates; read-only. |
session_log | USE THIS for "last time", "yesterday", "what happened", "what did we do". Returns session history with handoffs and file changes. DO NOT use query() for cross-session questions — this tool has session-specific data that search cannot find. |
profile | Current static + dynamic user profile |
lifecycle_status | Document lifecycle statistics: active, archived, forgotten, pinned, snoozed counts, the deactivation-reason breakdown, and policy summary |
lifecycle_sweep | Run lifecycle policies: archive stale docs past retention threshold. Archives only — never deletes. Defaults to dry_run (preview only) |
lifecycle_restore | Restore documents that were auto-archived by lifecycle policies. Filter by query, collection, or restore all |
ClawMem never physically deletes a document row (v0.30.0). Forget and archive deactivate; lifecycle_restore reverses archival; purge_after_days is inert. Through v0.29.0 a configured retention window permanently deleted archived rows from a non-dry-run sweep and from the SessionStart hook, without reporting it — see upgrading.
Compact Mode
search, vsearch, and query accept compact: true to return { id, path, title, score, snippet, content_type, fragment } instead of full content. Saves ~5x tokens for initial filtering.
Hooks (Claude Code Integration)
Hooks installed by clawmem setup hooks:
| Hook | Event | What It Does |
|---|---|---|
context-surfacing | UserPromptSubmit | Retrieval gate → lane-based hybrid search (BM25 + vector + file-aware (E13) + gated prior-turn + deep expansion variants) → weighted RRF fusion onto one channel-aware ordering key → snooze/noise filters → relevance admission with query-level abstention (v0.38.0) → tiered injection (HOT/WARM/COLD) → <vault-context> + <vault-routing> hint. Profile-driven budget/results/timeout; CLAWMEM_HOOK_BUDGET_MS is the authoritative internal deadline. |
postcompact-inject | SessionStart (compact) | Re-injects context after compaction, framed as reference data: this session's pre-compaction state + recent decisions + antipatterns + vault context (1200 token budget) |
curator-nudge | SessionStart | Surfaces curator report actions, nudges when report is stale (>7 days) |
precompact-extract | PreCompact | Extracts the last typed request, decisions, file paths and open questions before compaction → the vault's session-keyed compaction_state row, taken once by the same session's postcompact-inject |
decision-extractor | Stop | GGUF observer extracts structured observations (decisions, preferences, milestones, problems, bugfixes, features, refactors, discoveries) from the turns after its per-transcript cursor, each turn once (v0.41.0), into the session's own decision and antipattern docs; detects contradictions with prior decisions (judge-gated — requires CLAWMEM_JUDGE_*, v0.29.0) |
handoff-generator | Stop | Digests each new turn without a model, then folds the digests into an incremental, throttled observer summary → the session's handoff |
handoff-generator | SessionEnd | Renders the handoff's latest turns at session end (no transcript read, no model; v0.41.0) |
feedback-loop | Stop | Silently credits each surfaced note once per turn when that turn verifiably names it (path, file name or rendered title): access count, co-activation + usage relations among the notes that turn referenced, utility signals (surfaced vs referenced ratio for lifecycle automation) |
Additional hooks available but not installed by default:
| Hook | Event | Why Not Default |
|---|---|---|
session-bootstrap | SessionStart | Injects ~2000 tokens before user types anything. context-surfacing on first prompt is more precise. |
staleness-check | SessionStart | Redundant without session-bootstrap (stale notes are part of its output). |
pretool-inject | PreToolUse | Disabled in HOOK_EVENT_MAP (cannot inject additionalContext via PreToolUse). |
Hooks handle ~90% of retrieval automatically. For agent escalation logic (when to use MCP tools vs rely on hooks), see CLAUDE.md.
Search Pipeline
User Query + optional intent hint
→ BM25 Probe → Strong Signal Check (skip expansion if top hit ≥ 0.85 with gap ≥ 0.15; disabled when intent provided)
→ Query Expansion (intent steers LLM prompt when provided)
→ BM25 + Vector Search (parallel, original query 2× weight)
→ Reciprocal Rank Fusion → slice to candidateLimit (default 30)
→ Intent-Aware Chunk Selection (intent terms at 0.5× weight alongside query terms at 1.0×)
→ Cross-Encoder Reranking (4000 char context; intent prepended; chunk dedup; batch cap=4)
→ Rerank/RRF Blend (blendRerank: 0.9·reranker + 0.1·normalized-RRF tiebreaker; reranker can promote over RRF #1; falls back to RRF order if reranker unavailable)
→ Composite Scoring (query-tuned: (search × 0.70 + recency × 0.15 + confidence × 0.15) × qualityMultiplier × lengthNorm × coActivationBoost + pinBoost; recency-intent queries → 0.10/0.70/0.20; other tools keep the 0.50/0.25/0.25 default)
→ MMR Diversity Filter (Jaccard bigram similarity > 0.6 → demoted)
→ Ranked ResultsFor agent-facing query optimization (tool selection, query string quality, intent parameter, candidateLimit), see CLAUDE.md.
Multi-Graph Traversal
For WHY and ENTITY queries, the search pipeline expands results through the memory graph:
Start from top-10 baseline results as anchor nodes
For each frontier node: get neighbors via any relation type
Score transitions:
λ1·structure + λ2·semantic_affinityApply decay:
new_score = parent_score * γ + transition_scoreKeep top-k (beam search), repeat until max depth or budget
Graph types:
Semantic — vector similarity edges (threshold > 0.7)
Temporal — chronological document ordering
Causal — LLM-inferred cause→effect from Observer facts + Beads
blocks/waits-fordepsSupporting — LLM-analyzed document relationships + Beads
discovered-fromdepsContradicts — LLM-analyzed document relationships. Additional
contradictsedges are inserted by Phase 3 deductive synthesis when a new draft contradicts a prior deductive observation. (Phase 2's merge-time gate does not insert edges — a blocked merge underlinksets the old consolidated row'sinvalidated_bybacklink instead.)
Content Type Scoring
| Type | Half-life | Baseline | Notes |
|---|---|---|---|
decision | 180d | 0.85 | Very slow ranking decay (§36.11) — silently-abandoned decisions stop winning ranking; attention-decay-exempt; lifecycle policy separate |
deductive | ∞ | 0.85 | Never decays — cross-session derived insights with source provenance |
preference | ∞ | 0.80 | Never decays — user preferences are durable facts |
hub | ∞ | 0.80 | Never decays |
antipattern | ∞ | 0.75 | Never decays — accumulated negative patterns persist |
problem | 60 days | 0.75 | High priority but resolves over time |
research | 90 days | 0.70 | |
milestone | 60 days | 0.70 | Important at the time, fades as project moves forward |
project | 120 days | 0.65 | |
handoff | 30 days | 0.60 | Fast decay — most recent matters |
conversation | 45 days | 0.55 | Imported chat exchanges |
progress | 45 days | 0.50 | |
note | 60 days | 0.50 | Default |
Content types are inferred from frontmatter or file path patterns. Half-lives extend up to 3× for frequently-accessed memories (access reinforcement, decays over 90 days). Non-durable types (handoff, progress, conversation, note, project) lose 5% confidence per week without access (attention decay). Decision/deductive/preference/hub/research/antipattern are exempt.
Quality scoring: Each document gets a quality_score (0.0–1.0) computed during indexing based on length, structure (headings, lists), decision/correction keywords, and frontmatter richness. Applied as qualityMultiplier = 0.7 + 0.6 × qualityScore (range: 0.7× penalty to 1.3× boost).
Length normalization: 1/(1 + 0.5 × log2(max(bodyLength/500, 1))) — penalizes verbose entries that dominate via keyword density. Floor at 30% of original score.
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%.
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 routes — the vector tools (v0.22.0) and non-recency search (v0.24.0) — pin breaks exact raw-score ties only. Use memory_pin to pin critical memories.
Snooze: Snoozed documents are filtered out of context surfacing until their snooze date. Use memory_snooze for temporary suppression.
Contradiction detection (judge-gated, v0.29.0): Contradiction analysis runs only when a judge is configured via CLAWMEM_JUDGE_* — without one it is disabled as an audited no-op, because the stock expansion model cannot meet the judge contract (details). With a judge: when decision-extractor identifies a new decision that contradicts a prior one, the old decision's confidence is automatically lowered (−0.25 for contradictions, −0.15 for updates). Superseded decisions naturally fade from context surfacing without manual intervention. When erosion reaches the 0.2 floor the hook can additionally set invalidated_at, which removes the document from FTS and vector retrieval entirely. That step applies only to content_type='observation' rows — a superseded decision is eroded but never retired — and is off by default behind CLAWMEM_CONTRADICTION_INVALIDATE and logs WOULD invalidate instead of writing, because its exposure depends on the vault's confidence distribution and content-type mix (calibration guide). Two contract defects fixed in v0.28.0 had previously prevented this path from applying any classification at all — earlier versions classified but never mutated a document. v0.7.1 adds a second layer at the consolidation boundary: before the background worker merges a new pattern into an existing consolidated observation, a deterministic heuristic (negation asymmetry, number/date mismatch) plus the configured judge detect contradictions (heuristic-only, and constrained to link, when no judge is configured). Blocked merges route to either link policy (both rows remain active; the old row gains an invalidated_by backlink, default) or supersede policy (old row marked status='inactive' — requires a configured judge, otherwise loudly constrained to link). Configurable via CLAWMEM_CONTRADICTION_POLICY and CLAWMEM_CONTRADICTION_MIN_CONFIDENCE. Mutation-authorizing evaluations commit their durable judge_runs/judge_events audit rows in the same transaction as the mutation (Phase-3 deductive checks commit a precondition audit first; non-mutating outcomes write standalone rows) — that audit is what calibration reads. Data-egress note: a cloud or subscription judge receives the new decisions and the retrieved candidate snippets.
Features
A-MEM (Adaptive Memory Evolution)
Documents are automatically enriched with structured metadata when indexed:
Keywords (3-7 specific terms)
Tags (3-5 broad categories)
Context (1-2 sentence description)
When new documents create links, neighboring documents' metadata evolves — keywords merge, context updates, and the evolution history is tracked with version numbers and reasoning.
Causal Inference
The decision-extractor hook analyzes Observer facts for causal relationships. When multiple facts exist in an observation, an LLM identifies cause→effect pairs (confidence ≥ 0.6). Causal chains can be queried via find_causal_links with multi-hop traversal using recursive CTEs.
Beads Integration
Projects using Beads (v0.58.0+, Dolt backend) issue tracking are fully integrated into the MAGMA memory graph:
Auto-sync: Watcher detects
.beads/directory changes →syncBeadsIssues()queriesbdCLI for live Dolt data → creates markdown docs inbeadscollectionDependency bridging: All Beads dependency types map to
memory_relationsedges —blocks/conditional-blocks/waits-for/caused-by→causal,discovered-from/supersedes/duplicates→supporting,relates-to/related/parent-child→semantic. Tagged{origin: "beads"}for traceability.A-MEM enrichment: New beads docs get full
postIndexEnrich()— memory note construction, semantic/entity link generation, memory evolutionGraph traversal:
intent_searchandfind_causal_linkstraverse beads dependency edges alongside observation-inferred causal chainsRequirement:
bdbinary on PATH or at~/go/bin/bd
beads_sync MCP tool for manual sync; watcher handles routine operations automatically.
Fragment-Level Embedding
Documents are split into semantic fragments (sections, lists, code blocks, frontmatter, facts) and each fragment gets its own vector embedding. Full-doc embedding is preserved for broad-match queries.
Local Observer Agent
Uses the LLM server (shared with query expansion and intent classification) to extract structured observations from session transcripts. Observation types: decision, bugfix, feature, refactor, discovery, change, preference, milestone, problem. Each observation includes title, facts, narrative, concepts, and files read/modified. Preferences, milestones, and problems get first-class content_type treatment with dedicated confidence baselines and half-lives instead of being flattened to generic "observation". Regex patterns find decisions and antipatterns beside the model. A batch the model cannot answer (unavailable, or refusing the request) is quarantined and replayed later, never committed as empty; its regex finds are committed when the replay succeeds (v0.41.0). Each prompt is fitted in tokens to the LLM server's own context, with room kept for the reply, and a turn too long for one prompt runs as checkpointed windows that resume after a timeout (v0.41.2). Only the reply <none/> means "nothing to record"; a reply that does not parse gets up to two retries whose feedback names the failing field (a batch whose replies never parse is quarantined like an unanswered one), and on llama-server the observer asks for grammar-constrained replies — a GBNF grammar that admits only well-formed ones, sent unless the server refused one in the last 24 hours; enforcement is not verified in advance, and clawmem doctor counts completed replies that break it (v0.41.4). Serve the observer with -c 8192; inference services covers the server's context size.
Recall Tracking
Empirical tracking of which documents are surfaced by retrieval, which queries surfaced them, and whether the assistant actually cited them. Provides signals beyond raw search relevance for lifecycle decisions:
Per-query diversity: docs surfaced by multiple distinct queries have proven cross-domain relevance
Multi-day spacing: docs surfaced across separate calendar days (spaced frequency) are more valuable than binge recalls in one session
Negative signals: docs surfaced frequently but rarely referenced are noise candidates for snooze
Per-turn attribution: feedback-loop pairs each transcript turn with the context-surfacing row that served it (prompt hash + the host's order of events, never position) and tests only that turn's answer against that turn's injected documents (v0.41.0)
Data feeds lifecycle_status (pin/snooze candidate reports) and lifecycle_sweep (recall-based recommendations). Adapted from OpenClaw dreaming promotion patterns.
User Profile
Two-tier auto-curated profile extracted from your decisions and hub documents:
Static: persistent facts (Levenshtein-deduplicated)
Dynamic: recent session context
Injected at session start for instant personalization.
Prompt Injection Filtering
Five detection layers protect injected content: legacy string patterns, role injection regex, instruction override patterns, delimiter injection, and unicode obfuscation detection. Filtered results are skipped entirely (no placeholder tokens wasted).
Consolidation Worker
Optional background process that enriches documents missing A-MEM metadata. Runs on a configurable interval, processing 3 documents per tick. Non-blocking (Timer.unref).
Per-Folder CLAUDE.md Generation
Automatically generates context sections in per-folder CLAUDE.md files from recent decisions and session activity related to that directory.
Feedback Loop
A surfaced note gets access_count + 1 when a turn it was injected into names it — once per turn, when the turn is over (v0.41.0; earlier versions counted the whole session again at every Stop). Unreferenced notes decay via recency. Over time, useful notes rise and noise fades.
Offline Eval Harness
clawmem eval run --gold <file.jsonl> replays hand-labeled queries through the real query tool handler and scores the retrieved documents against gold evidence: doc-level Jaccard (|C∩E|/|C∪E|), precision/recall@k, hit@k, MRR. Touches no retrieval, lifecycle, or telemetry state (normal inference caches may populate, as in any live query); writes run.json + report.md for A/B comparison between checkouts or DB snapshots. Gold schema, trust gates, and labeling discipline: docs/guides/eval-harness.md.
Feature Flags
| Variable | Default | Effect |
|---|---|---|
CLAWMEM_ENABLE_AMEM | enabled | A-MEM note construction + link generation during indexing |
CLAWMEM_ENABLE_CONSOLIDATION | disabled | Background worker for backlog A-MEM enrichment |
CLAWMEM_CONSOLIDATION_INTERVAL | 300000 | Worker interval in ms (min 15000) |
CLAWMEM_EMBED_URL | http://localhost:8088 | Embedding server URL. Uses llama-server (GPU or CPU) or cloud API. Falls back to in-process node-llama-cpp if unset. |
CLAWMEM_EMBED_API_KEY | (none) | API key for cloud embedding. Enables cloud mode: batch embedding, provider-specific params, TPM-aware pacing. |
CLAWMEM_EMBED_MODEL | embedding | Model name for embedding requests. Override for cloud providers (e.g. jina-embeddings-v5-text-small). |
CLAWMEM_EMBED_TPM_LIMIT | 100000 | Tokens-per-minute limit for cloud embedding pacing. Match to your provider tier. |
CLAWMEM_EMBED_WAIT_SEC | 120 | v0.43.5: how long clawmem embed waits for a self-hosted embedding server at start (URL set, no API key, CLAWMEM_NO_LOCAL_MODELS=true). Not ready in time → the embedding is skipped, exit 1. embed --wait overrides it. |
CLAWMEM_EMBED_WAIT_INTERVAL_MS | 5000 | v0.43.5: time between that wait's probes. |
CLAWMEM_EMBED_PROBE_TIMEOUT_MS | 15000 | v0.43.5: how long one probe of that wait may take. |
CLAWMEM_EMBED_DIMENSIONS | (none) | Output dimensions for OpenAI text-embedding-3-* Matryoshka models (e.g. 512, 1024). |
CLAWMEM_LLM_URL | http://localhost:8089 | LLM server URL for intent/query/A-MEM and the Stop hooks' observer. Without it, falls to node-llama-cpp (if allowed). |
CLAWMEM_LLM_API_KEY | (none) | Bearer token for an authenticated remote LLM endpoint. Independent of the embed and rerank keys. |
CLAWMEM_LLM_MODEL | qwen3 | Model name sent to the configured LLM endpoint. Override this for OpenAI-compatible proxies such as gpt-5.4-mini. |
CLAWMEM_LLM_REASONING_EFFORT | (none) | 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 your serving stack explicitly accepts that field. |
CLAWMEM_LLM_NO_THINK | true | Append /no_think to remote LLM prompts. Set to false for standard OpenAI models and other endpoints that reject or treat the Qwen-style suffix as literal prompt text. |
CLAWMEM_LLM_CONTEXT_TOKENS | (none) | v0.41.2. The LLM server's context per request, in tokens, for a server without llama.cpp's /props (cloud gateways, vLLM, Ollama). The Stop hooks' observer and summary fit their prompts to it. With /props the server's own number wins; with neither, 4096 is assumed. |
CLAWMEM_OBSERVER_GRAMMAR | auto | v0.41.4. auto: the Stop hooks' observer sends a GBNF grammar that admits only well-formed observation blocks or <none/> to llama-server (a /props naming the model, template and build) and to the in-process model; off: never. A server that refuses one (HTTP 400, or in process a grammar that does not compile) gets none for 24 hours and until a grammarless request reaches it. Enforcement is not verified in advance: clawmem doctor counts completed replies that break the grammar. |
CLAWMEM_JUDGE_URL | (none) | v0.29.0. OpenAI-compatible endpoint for the contradiction judge — a task-scoped override, independent of CLAWMEM_LLM_* (query expansion stays on the stock model). Setting it activates contradiction analysis. Data-egress note: the judge receives new decisions + retrieved candidate snippets. Guide. |
CLAWMEM_JUDGE_PROVIDER | openai when _URL set | v0.29.0. openai | anthropic | claude-cli. anthropic calls the Messages API directly (default model claude-haiku-4-5); claude-cli runs a sandboxed headless claude -p on your Claude Code subscription — no API key. |
CLAWMEM_JUDGE_MODEL | provider-specific | v0.29.0. Wire model id. Required on openai (no universal default); defaults to claude-haiku-4-5 on anthropic/claude-cli (the suite-verified recommended default; claude-sonnet-5 is an unverified upgrade candidate — see the judge guide for its honest evaluation status). |
CLAWMEM_JUDGE_API_KEY | (none) | v0.29.0. Bearer / x-api-key for the judge endpoint. On anthropic, falls back to ANTHROPIC_API_KEY. |
CLAWMEM_JUDGE_NO_THINK | false | v0.29.0. Append /no_think on the judge lane (only useful for a local Qwen-family judge on the openai lane). |
CLAWMEM_JUDGE_STRUCTURED | lane-specific | v0.29.0. Schema-constrained judge output. Default false on openai (endpoint support varies), true on anthropic/claude-cli. Set explicitly to override. |
CLAWMEM_RERANK_URL | http://localhost:8090 | Reranker server URL. Without it, falls to node-llama-cpp (if allowed). |
CLAWMEM_RERANK_API_KEY | (none) | Bearer token for an authenticated remote reranker endpoint. Independent of the embed and LLM keys. |
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. Since v0.43.5 clawmem embed first waits for a self-hosted embedding server under this setting (CLAWMEM_EMBED_WAIT_SEC). |
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. |
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. |
CLAWMEM_MERGE_SCORE_STRICT | 0.98 | v0.7.1. Strictest merge-safety threshold — fallback when anchor sets are ambiguous. |
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. |
CLAWMEM_CONTRADICTION_POLICY | link | v0.7.1, judge-gated v0.29.0. Merge-time contradiction gate policy. link inserts a new row and sets the old row's invalidated_by backlink (default). supersede marks the old row status='inactive' — requires a configured judge; without one it is loudly constrained to link and clawmem doctor reports the policy as inactive. |
CLAWMEM_CONTRADICTION_MIN_CONFIDENCE | 0.5 | v0.7.1. Minimum confidence required before the contradiction gate blocks a merge. The judge prompt states this same threshold — the prompt never overrides your configured value. |
CLAWMEM_CONTRADICTION_INVALIDATE | false | v0.28.0, judge-gated v0.29.0. A different subsystem from the two rows above — this one governs the decision-extractor hook, not the merge-time gate. Set to exactly true to let a contradiction that erodes a document to the 0.2 confidence floor also set invalidated_at, removing it from FTS and vector retrieval. Off by default: the hook logs WOULD invalidate, writes a durable audit row, and mutates nothing further. Confidence erosion runs whenever a judge is configured (without a judge, nothing runs at all). Eligible rows are content_type='observation' only. Calibration guide. |
Configuration
Collection Config
~/.config/clawmem/config.yaml:
collections:
notes:
path: /home/user/notes
pattern: "**/*.md"
autoEmbed: true
docs:
path: /home/user/docs
pattern: "**/*.md"
update: "git pull"
directoryContext: false # opt-in per-folder CLAUDE.md generationDatabase
~/.cache/clawmem/index.sqlite — single SQLite file with FTS5 + sqlite-vec extensions.
Frontmatter
YAML (or JSON) between --- lines that open the document, parsed through a bounded engine (v0.43.6 — a ---js block
used to run as code): only yaml/yml/json blocks are read; a block with a YAML anchor, deeper than 32 levels, over
4,096 nodes, over 64 KiB or over 1,024 lines is indexed as plain text; a << key does not merge (it is kept as an
ordinary key); tags keeps at most 64 scalar entries. Supported fields:
---
title: "Document Title"
tags: [tag1, tag2]
domain: "infrastructure"
workstream: "project-name"
content_type: "decision" # decision|preference|hub|research|project|handoff|conversation|progress|note
review_by: "2026-03-01"
---Suggested Memory Filesystem
This structure separates human-curated content from auto-generated memories, and within auto-generated content, separates user memories (persist across agents, owned by the human) from agent memories (operational, generated from sessions). Static knowledge lives in resources/ with no recency decay, distinct from ephemeral session logs. The layout works with any MCP-compatible client (Claude Code, OpenClaw, custom agents).
Workspace Collection
The primary workspace where the agent operates. Path varies by client (e.g., ~/workspace/, ~/.openclaw/workspace/, or any directory you choose).
<workspace>/ ← Collection: "workspace"
├── MEMORY.md # Human-curated long-term memory
├── memory/ # Session logs (daily entries)
│ ├── 2026-02-05.md
│ └── 2026-02-06.md
├── resources/ # Static knowledge — use content_type: hub (∞ half-life)
│ ├── runbooks/
│ │ └── deploy-checklist.md
│ └── onboarding.md
├── _clawmem/ # Auto-generated — DO NOT EDIT
│ ├── user/ # User memories (persist across agents/sessions)
│ │ ├── profile.md # Static facts + dynamic context
│ │ ├── preferences/ # Extracted preferences
│ │ └── entities/ # Named entities (people, services, repos)
│ └── agent/ # Agent memories (operational, session-derived)
│ ├── observations/ # Decisions + observations from transcripts
│ ├── handoffs/ # Session summaries with next steps
│ └── antipatterns/ # Accumulated negative patterns (∞ half-life)
└── ...Project Collections
Each project gets its own collection. Same structure, with optional Beads integration.
~/Projects/<project>/ ← Collection: "<project>"
├── .beads/ # Beads issue tracker (Dolt backend, auto-synced)
│ └── dolt/ # Dolt SQL database (source of truth)
├── MEMORY.md # Human-curated project memory
├── memory/ # Project session logs
│ └── 2026-02-06.md
├── resources/ # Static project knowledge (∞ half-life)
│ ├── architecture.md
│ └── api-reference.md
├── research/ # Research dumps (fragment-embedded, 90-day decay)
│ └── 2026-02-06-topic-slug.md
├── _clawmem/ # Auto-generated per-project
│ ├── user/
│ │ └── preferences/
│ └── agent/
│ ├── observations/
│ ├── handoffs/
│ ├── antipatterns/
│ └── beads/ # Beads issues as searchable markdown
├── CLAUDE.md
├── src/
└── README.mdDesign Principles
| Principle | Rationale | ClawMem Mechanism |
|---|---|---|
| User/agent separation | User memories (preferences, entities, profile) are owned by the human and persist indefinitely. Agent memories (observations, handoffs) are operational artifacts with lifecycle management. | _clawmem/user/ vs _clawmem/agent/ — different decay rules per content type |
| Resources are first-class | Static knowledge (runbooks, architecture docs, API refs) should never lose relevance due to recency decay. | resources/ indexed with content_type: hub → ∞ half-life in composite scoring |
| Progressive disclosure | Hook injection (2000 token budget) benefits from tiered loading: compact snippets first, full content on demand. | compact=true (L1) → multi_get (L2) at query time. Pre-computed abstracts not yet implemented — candidate for future L0 tier. |
| Beads as memory edges | Issue tracker data bridges into the knowledge graph via typed relations, not just as flat documents. | syncBeadsIssues() maps deps → memory_relations: blocks→causal, discovered-from→supporting, relates-to→semantic |
| Each turn captured once, per session | Session-derived memory must neither repeat itself at every response nor overwrite another session's. | Transcript cursors for extraction and handoffs, a once-per-turn feedback verdict, items rendered into per-session decision/antipattern/handoff docs (v0.41.0; the cross-session merge policies and hash-window dedup they replaced are gone) |
Layer Mapping
| Layer | Path | Owner | Decay | ClawMem Role |
|---|---|---|---|---|
| Long-Term Memory | MEMORY.md | Human | ∞ | Indexed, profile supplements, human-curated anchor |
| Session Logs | memory/*.md | Human | 60 days | Indexed, daily entries, handoff auto-generated |
| Static Resources | resources/**/*.md | Human | ∞ (hub) | Fragment-embedded, no recency penalty |
| Research | research/*.md | Human | 90 days | Fragment-embedded for granular retrieval |
| User Profile | _clawmem/user/profile.md | Auto | ∞ | Static facts + dynamic context |
| User Preferences | _clawmem/user/preferences/*.md | Auto | ∞ | Extracted preferences |
| User Entities | _clawmem/user/entities/*.md | Auto | ∞ | Named entities across sessions |
| Observations | _clawmem/agent/observations/*.md | Auto | 180d (decision) | Decisions + observations from transcripts |
| Handoffs | _clawmem/agent/handoffs/*.md | Auto | 30 days | Session summaries with next steps |
| Antipatterns | _clawmem/agent/antipatterns/*.md | Auto | ∞ | Accumulated negative patterns |
| Beads | _clawmem/agent/beads/*.md | Auto | ∞ | Beads issues synced from Dolt, relations in memory graph |
Manual layers benefit from periodic re-indexing — a cron job running clawmem update --embed keeps the index fresh for content edited outside of watched directories.
Setup
# Bootstrap a content directory (creates vault + indexes + embeds + installs hooks + MCP)
clawmem bootstrap ~/notes --name notes
# Bootstrap each project you want indexed
clawmem bootstrap ~/Projects/my-project --name my-project
# Install watcher + embed timer as systemd services
clawmem install-service --enableOpenClaw-specific
# Install the OpenClaw plugin
# v0.10.4+: delegates to `openclaw plugins install --force` when the CLI is on PATH (auto-enables;
# honors OPENCLAW_STATE_DIR / OPENCLAW_CONFIG_PATH / --profile). Falls back to recursive copy
# honoring OPENCLAW_STATE_DIR when the CLI is absent.
# v0.10.0–v0.10.3: hardcoded recursive copy into ~/.openclaw/extensions/clawmem (issue #11).
clawmem setup openclaw
# Then follow the printed next steps. The exact list depends on which path ran:
# Path 1 (delegated): plugin already auto-enabled — just `openclaw gateway restart` + GPU config
# Path 3 (CLI absent): manually `openclaw plugins enable clawmem`, then restart + GPU config
# Multi-user installs also need: sudo chown -R <gateway-user>:<gateway-group> <extensions>/clawmem
# Requires OpenClaw v2026.4.11+.Index your content directories with clawmem bootstrap as above. The OpenClaw plugin shares the same vault as Claude Code hooks.
Hermes-specific
# Install the memory provider plugin.
# Preferred: $HERMES_HOME/plugins/clawmem/ (user-plugin path, Hermes #10529, v2026.4.13+).
ln -s $(npm root -g)/clawmem/src/hermes ${HERMES_HOME:-~/.hermes}/plugins/clawmem
# Bundled-style path is also supported (takes precedence on name collisions):
# ln -s $(npm root -g)/clawmem/src/hermes /path/to/hermes-agent/plugins/memory/clawmem
# Start the REST API (required for Hermes tool calls)
clawmem serve --port 7438 &
# Configure Hermes to use ClawMem (in your Hermes config.yaml):
# memory:
# provider: clawmemDependencies
| Package | Purpose |
|---|---|
@modelcontextprotocol/sdk | MCP server |
gray-matter | frontmatter delimiting (pinned 4.0.3; engines replaced by ClawMem's bounded YAML/JSON, see v0.43.6) |
js-yaml | the YAML loader under ClawMem's bounded frontmatter engine (3.14.x) |
node-llama-cpp | GGUF model inference (reranking, query expansion, A-MEM) |
sqlite-vec | Vector similarity extension |
yaml | Config parsing |
zod | MCP schema validation |
Deployment
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 the inference services on GPU (three llama-server instances in either stack; the SOTA stack's zerank-2 reranker runs as a Q8_0 GGUF that carries its score head, with a bf16 transformers sidecar as the reference alternative) — see Inference services for model tiers (SOTA vs QMD native) and cloud embedding for cloud embedding alternatives.
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).
Acknowledgments
Built on the shoulders of:
A-MEM — self-evolving memory architecture
Beads — Dolt-backed issue tracker for AI agents
claude-mem — Claude Code memory integration reference
Engram — observation dedup window, topic-key upsert pattern, temporal timeline navigation, duplicate metadata scoring signals
Hermes Agent — MemoryProvider plugin integration, memory nudge system (periodic lifecycle tool prompting)
Hindsight — entity resolution, MPFP graph traversal, temporal extraction, 3-tier consolidation, observation invalidation, 4-way parallel retrieval
Honcho — deductive observation synthesis patterns, surprisal-based anomaly scoring concept, embed-state self-healing, retrieval separation (raw vs derived)
MAGMA — multi-graph memory agent
MemPalace — conversation import patterns, broadened observation taxonomy (preference/milestone/problem), session-bootstrap synthesis
memory-lancedb-pro — retrieval gate, length normalization, MMR diversity, access reinforcement algorithms
OpenClaw — recall tracking patterns (per-query diversity, multi-day spacing, negative signal tracking, promotion scoring) extracted from the dreaming memory consolidation system
OpenViking — query decomposition patterns, collection-scoped retrieval, transaction-safe indexing
QMD — search backend (BM25 + vectors + RRF + reranking)
SAME — agent memory concepts (recency decay, confidence scoring, session tracking)
supermemory — hook patterns and context surfacing ideas
Thoth — anti-contamination deductive synthesis, contradiction-aware + name-aware merge gates, post-import conversation fact extraction, quiet-window heavy maintenance lane with worker leases, context instruction framing, relationship snippets, multi-turn prior-query lookback
Roadmap
| Status | Feature | Description |
|---|---|---|
| :white_check_mark: | Relevance admission | Distribution-relative admission on the fused ordering key with query-level abstention — replaced the v0.1.3 adaptive composite thresholds (v0.38.0) |
| :white_check_mark: | Deep escalation | Budget-aware query expansion + cross-encoder reranking for deep profile |
| :white_check_mark: | Cloud embedding providers | Jina, OpenAI, Voyage, Cohere with batch embedding + TPM pacing |
| :construction: | Calibration probes | One-time clawmem calibrate command that measures your vault's score distribution and tunes thresholds automatically |
| :white_check_mark: | Judged hook eval harness | clawmem eval hook-run — labeled replay of the real hook with paired A/B counterfactuals, replicated draws, and acceptance gates (v0.38.0) |
| :memo: | Multi-vault namespacing | Isolated vaults with independent calibration and lifecycle policies |
| :memo: | REST API authentication | Token-scoped access for multi-agent deployments |
| :white_check_mark: | Budget-bounded rerank lane | Deep-profile cross-encoder rerank inside the hook budget with full-coverage + degeneracy contracts (v0.38.0) |
:white_check_mark: Shipped  :construction: Planned  :memo: Exploring
License
MIT
docs/troubleshooting.md
Troubleshooting
Common issues when running ClawMem with hooks, MCP server, or OpenClaw plugin. Organized by subsystem.
Bun runtime
Snap Bun: EPERM on stdin (hooks return empty)
On Linux, Bun installed via snap (
/snap/bin/bun) cannot read stdin due to snap's confinement sandbox. Hooks receive no prompt input and silently return empty context.Fix: Install Bun via the official installer (
curl -fsSL https://bun.sh/install | bash) which places it at~/.bun/bin/bun. Thebin/clawmemwrapper prefers~/.bun/bin/bunover the system bun for this reason. If hooks return empty on a snap-based system, verify~/.bun/bin/bunexists and is executable.
Two Bun binaries on PATH
If both snap bun (
/snap/bin/bun) and native bun (~/.bun/bin/bun) are installed,which bunmay return the snap version. Directbun -eorbun runcommands will use the wrong binary.Fix: The
bin/clawmemwrapper handles this automatically. For manual commands, use~/.bun/bin/bunexplicitly or add~/.bun/binto PATH before/snap/bin.
macOS: bootstrap / doctor fails with "does not support dynamic extension loading" (sqlite-vec on macOS)
clawmem bootstrap(orclawmem doctor) fails at the database step because macOS's built-in SQLite — which Bun uses by default — is compiled without extension-loading support, so thesqlite-vecvector extension cannot load. Symptom:✗ Database: ... This build of sqlite3 does not support dynamic extension loading. Yoloshii/ClawMem#20.Fix: install an extension-capable SQLite via Homebrew, then re-run bootstrap:
brew install sqlite clawmem bootstrap ~/notes --name notesClawMem auto-detects Homebrew's SQLite at the standard prefixes (
/opt/homebrewon Apple Silicon,/usr/localon Intel) and atbrew --prefix sqlitefor non-standard prefixes — installing it is all that's required, no env var or config. If it still fails afterbrew install sqlite, runbrew reinstall sqliteand confirmls $(brew --prefix sqlite)/lib/libsqlite3.dylibresolves.
Embedding & GPU
"Local model download blocked" error
The llama-server endpoint is unreachable while
CLAWMEM_NO_LOCAL_MODELS=true.Fix: Start the llama-server instance. Or set
CLAWMEM_NO_LOCAL_MODELS=falsefor in-process fallback.
"Remote LLM in cooldown, falling back to in-process generation"
A transport failure (ECONNREFUSED, ETIMEDOUT) triggered a 60-second cooldown on the remote LLM server. During cooldown,
generate()andexpandQuery()use local node-llama-cpp. Remote is retried automatically after cooldown expires. A single HTTP error (400, 500) and AbortError do NOT trigger cooldown — remote is retried on the next call. Since v0.37.0, HTTP errors that indicate the endpoint is not actually serving the API DO trip the same cooldown: 405/501 immediately (a correctly-routed endpoint never returns these), any other non-2xx — including 404, which cloud gateways legitimately return for an unknown model — after 3 consecutive failures; 429 never counts. See the squatted-port entry below.Fix: Start the llama-server. Or set
CLAWMEM_NO_LOCAL_MODELS=trueto prevent local fallback (returns null / passthrough instead).
[generate] The LLM server cut a reply at its context limit … (v0.41.2)
A reply stopped at the server's context, not at the request's
max_tokens. It is logged once per process, whichever caller hit it (A-MEM notes, query expansion, the observer, which also re-runs that window at half its size). Raise the server's-c; with--parallel N, each request gets only-c / N.
Enrichment produces nothing while indexing reports success ([amem] LLM returned null on every doc)
The classic cause is a squatted port:
CLAWMEM_LLM_URLpoints at a port where an unrelated service answers HTTP (a file browser, a dashboard, anything), so everyPOST /v1/chat/completionsreturns 404/501. The endpoint is "reachable", so through v0.36.0 the down-cache never tripped, the local fallback never engaged, and A-MEM notes / entities / links were silently produced by nobody — whileclawmem updatekept ending in a normal success summary. Ironically a dead port degraded gracefully (connection refused → cooldown → local fallback); a squatted one failed forever. (Public issue #24.)Since v0.37.0: an endpoint-shape status (405/501) trips the 60s cooldown immediately, any other non-2xx (404 included) trips after 3 consecutive failures, and one loud line names the URL and the env var to fix (
Remote endpoint at <url> answers HTTP but not the chat-completions API …). During each cooldown the normal fallback engages when local fallback is permitted, so enrichment degrades to the in-process model instead of dying; underCLAWMEM_NO_LOCAL_MODELS=truethere is still no fallback by policy — you get the trip line plus the run-summary counter instead of silence. The same trip protects the self-hosted embedding lane (CLAWMEM_EMBED_URL); cloud embedding (API key set) is deliberately exempt — an auth/quota error on a chosen provider must not flip the vault onto a different local model.The run summary now counts it:
clawmem update/reindex/mine/ the watcher (and the MCPreindex/vault_synctools and REST/reindex) report✎stored/attempted notes, with an explicitN produced nothing (LLM endpoint problem? run 'clawmem doctor')when there is a gap — a run of nothing-but-nulls no longer ends in an unqualified success line. The metric is the note write specifically, not whole-pipeline success.Diagnose:
clawmem doctornow POSTs a minimal completion toCLAWMEM_LLM_URL(honoringCLAWMEM_LLM_MODEL/CLAWMEM_LLM_NO_THINK) and validates the response shape — a squatted port shows as✗ LLM endpoint: … reachable but NOT serving chat completions.Fix: point
CLAWMEM_LLM_URLat the actual llama-server (default convention:8089), or stop the squatter. Then re-run enrichment (clawmem reindex --enrichfor a full pass).
Unexpectedly slow inference (in-process fallback)
When a remote llama-server is unreachable, ClawMem falls back to in-process inference via
node-llama-cpp(logged as cooldown message). With GPU acceleration (Metal on Apple Silicon, Vulkan on supported hardware), the fallback is fast. On CPU-only systems, inference is significantly slower.Fix: Run GPU servers via systemd services with
Restart=on-failure. Or setCLAWMEM_NO_LOCAL_MODELS=trueto fail fast instead of falling back.
ggml_metal_library_init_from_source: error compiling source on Apple Silicon (in-process fallback)
The line comes from llama.cpp inside
node-llama-cpp, not from ClawMem. The bundled Metal shader source failed to compile on your macOS release, so ggml falls back to a slower path. Inference still completes and nothing crashes; embedding runs without Metal acceleration.Seen on macOS 26.6 with an M5 Pro when a source checkout resolved
node-llama-cpp3.15.1 (llama.cpp b7836, January 2026). Releases from 3.20.0 (llama.cpp b10361, August 2026) compile cleanly on that hardware. ClawMem'spackage.jsonnow requiresnode-llama-cpp^3.20.0; on an older checkout runbun update node-llama-cpp, then re-runclawmem embed. In one report the full embed of a 156-document vault went from 14.5 s to 9.6 s after the update.A
No results foundfromvsearchright after that line is a separate problem: the vault has no embeddings yet. Runclawmem embed(or wait for the embed timer) and check the unembedded count inclawmem status.The
[embed] Local embedding endpoint unavailable, cooldown 60s before retryline above it is expected when nollama-serveris running; that cooldown is what engages the in-process fallback. PointCLAWMEM_EMBED_URLat a server to skip in-process inference entirely.On CUDA the first in-process embedding after a node-llama-cpp upgrade can take about ten seconds while the driver compiles PTX for your card (measured on a GTX 1080 Ti with 3.20.0); the result lands in
~/.nv/ComputeCacheand later calls take around 130 ms. A hook killed during that compile leaves nothing cached, so runclawmem embedonce by hand after upgrading if you rely on hooks with local inference. The OpenClaw plugin does not warm the model itself (an automatic warm-up is deferred until it can run without touching the vault), so that manualclawmem embedis the upgrade step.
Query expansion always fails or returns garbage
On CPU-only systems (no Metal, no Vulkan), in-process inference is significantly slower and less reliable than a dedicated GPU server. Systems with GPU acceleration (Metal/Vulkan) handle these models well in-process.
Fix: Run llama-server on a GPU. Even a low-end NVIDIA card handles 1.7B models.
Some documents never get embedded (stuck after multiple sweeps)
A document is skipped only after 3 consecutive failed embedding attempts (to prevent infinite retry loops). As of v0.11.0 the retry budget resets on a successful embed and whenever the document's content changes (new hash, via a DB trigger), so a doc that later succeeds — or is edited — gets a fresh budget and can never be permanently excluded by stale failures.
Force a full retry of everything with
clawmem embed --force(resets all embed state). Check pending/synced/failed counts via the MCPstatustool (getEmbedStats).A partial embed (some fragments failed) marks the document
failedso it is retried in full next sweep — every fragment, not just the missing ones; seq=0 is required for surprisal scoring, semantic graph, and health checks.
Vector search returns no results but BM25 works
Missing embeddings. The watcher indexes but does NOT embed.
Fix: Run
clawmem embedor wait for the daily embed timer.
clawmem embed aborts: "Embedding dimension changed (N → M)"
The embedding model now returns a different vector dimension than the vault was built with — you switched models, or the GPU server is down and
node-llama-cppfell back to a different default. As of v0.11.0,embedrefuses to mix dimensions and aborts non-destructively. (Previously the first new-dimension insert dropped thevectors_vectable while the metadata-based worklist skipped the now-vectorless docs, silently wiping the vault's vectors — the dimension-migration safety fix; see RELEASE_NOTES v0.11.0.)Fix: decide which model you want, then
clawmem embed --forceto clear and rebuild the whole vault at the new dimension.--forceprobes the endpoint first and aborts without clearing if it's unreachable, so a force re-embed against a dead server cannot wipe the vault. To keep the old model, pointCLAWMEM_EMBED_URLback at it and setCLAWMEM_NO_LOCAL_MODELS=trueto prevent a silent fallback to a mismatched default.
clawmem embed aborts: "Embedding model changed (X → Y) at the same dimension"
A different embedding model is being used than the one the vault was built with, even though both produce the same dimension. Cosine similarity across two different models is meaningless, so
embedrefuses to mix them.clawmem doctorlikewise flags a vault that already contains mixed models.Fix:
clawmem embed --forceto rebuild with the current model, or point the endpoint back at the original model.Since v0.43.5 these stops (and "Embedding dimension changed", "mixed embedding models", "Force re-embed aborted") exit 1; through v0.43.4 they exited 0.
Since v0.43.5 a non-force run on a vault with one stored model checks every vector against that model, even when the dimension probe failed. Through v0.43.4 a failed probe left the model unchecked, so a same-dimension vector from another model — the in-process fallback during a cooldown, or a server that came back serving another model — was stored. Now the run stops with "Embedding model changed mid-run" and nothing of the other model is stored. With local fallback allowed (the stock launcher) a run can still meet the in-process model when the server is down; set
CLAWMEM_NO_LOCAL_MODELS=trueif the vault was built on a server.
clawmem embed exits 1: "Embed server … did not become ready within N s" (v0.43.5)
With
CLAWMEM_EMBED_URLset, noCLAWMEM_EMBED_API_KEYandCLAWMEM_NO_LOCAL_MODELS=true,embedtakes its lease, then waits for the server before the geometry canary, the stale-vector cleanup and any document, up to 120 s by default (underupdate --embedthe indexing has already run). It did not answer an embedding in time.(last: …)names the last probe's result:transport(nothing listening, or the connection dropped),timeout,httpwith the status (a server still starting may answer 503), ormalformed(an answer that is not an embedding). No document was charged an attempt and no stale vector was removed.Fix: start the server, or raise the wait for a slow start:
clawmem embed --wait 300, orCLAWMEM_EMBED_WAIT_SEC=300in the embed unit. See embed in the CLI reference."answers HTTP but not the embeddings API: HTTP 405" (or 501) stops at once: another service holds the port. Check
CLAWMEM_EMBED_URL.
clawmem embed exits 1: "No documents were embedded: N scheduled, 0 vectors written" (v0.43.5)
The run had documents to embed and stored no vector: every fragment failed (each answered an HTTP error, for example 413 for an input too large, or the server went away after the run started). Through v0.43.4 such a run exited 0 when its end check passed.
Fix: read the per-fragment warnings above the line. Each failed document is retried on the next run; after 3 failed runs in a row it is skipped (see above).
clawmem doctor reports a content_vectors ↔ vectors_vec desync
doctornow runs a vault-wide consistency check: everycontent_vectorsmetadata row must have a matchingvectors_vecentry and vice-versa. A nonzero "metadata rows missing a vector" / "orphan vectors" count (or "vectors_vec is MISSING but N content_vectors rows exist") means the two are out of sync — historically caused by an interrupted dimension migration on a pre-v0.11.0 build.Fix:
clawmem embed --forcerebuilds both tables atomically from scratch.
Two clawmem embed runs at once / "Another embed is already in progress"
As of v0.11.0, embed runs hold a renewable, token-fenced lease (
worker_leases, nameembedding) so two embeds (a manual run, the embed timer,update --embed) cannot run concurrently — concurrent runs could otherwise interleave a clear with an insert, or mix two models into one index. A second run prints "Another embed is already in progress; skipping" and exits.Fix: this is intended. Re-run after the active embed finishes. A crashed embed's lease expires after its TTL and is reclaimable automatically.
clawmem embed exits 1: "this run wrote 0 vectors … no taint set" (v0.41.2)
The run ended without storing a vector (the embedding server was down, or every fragment failed) and without a verified geometry. Since v0.43.5 a run with
CLAWMEM_NO_LOCAL_MODELS=trueand a self-hosted server first waits for the server and, when it is down from the start, stops with "did not become ready" (above) instead; this message then comes from a server that went away after it answered. Through v0.41.1 such a run set the geometry taint (✗ Geometry taintinclawmem doctor), and only a fullclawmem embed --forcecleared it; the embed timer firing while the server was down was enough. Since v0.41.2 a run that did not clear the index (no--force) and stored nothing leaves the taint alone. It still exits 1. Start the server and re-runclawmem embed.Unchanged: a run that stored vectors without a validated preflight sets the taint, and so does a
--forcerun that cleared the index, even with nothing stored. Clearing the taint now needs a--forcerebuild whose preflight passed; a run whose failed canary you overrode with--force-geometryno longer clears it.A taint set by v0.41.1 or earlier stays until a verified
clawmem embed --force.Limit: an embed run killed after it stored vectors (
SIGKILL, out of memory, power loss) sets no taint, as in v0.41.1, because the run never reaches its end check. Runclawmem doctorafter a crash; if the vault looks wrong, runclawmem embed --forceagainst a stable server.
Embedding fails with "input is too large to process"
The
fulldocument fragment exceeds the model's token context (2048 tokens for EmbeddingGemma).This is expected for large documents — the full-doc fragment fails but section/list/code fragments succeed.
Not a problem: vector search uses fragment-level embeddings, so the document is still searchable.
API key + localhost warning
You set
CLAWMEM_EMBED_API_KEYbutCLAWMEM_EMBED_URLpoints to localhost.If intentional (local API gateway), ignore. Otherwise, fix the URL to point to the cloud provider.
Search & retrieval
Historical/mined conversations rank as if they were written today
Fixed in v0.27.0: ranking recency, temporal filters, and the recent-decision windows run on effective time (
authored_atwhen known,modified_atotherwise). New mines capture authorship automatically.For vaults mined before v0.27.0: re-run
clawmem mineover the same export directory (metadata-only "dated" transition — no re-enrichment/re-embed), orclawmem mine <dir> -c <collection> --backfill-dates(dry-run) then--apply.Documents that still lack
authored_at(source transcripts without timestamps, plain-text imports) keep filing-time behavior by design.
context-surfacing hook returns empty
Prompt too short (< 20 chars — short memory-intent queries like "what did I say?" are exempt and force retrieval), starts with
/, or no docs score above threshold.Fix: Check
clawmem statusfor doc counts. Checkclawmem embedfor embedding coverage.
intent_search returns weak results for WHY/ENTITY
Graph may be sparse (few A-MEM edges).
Fix: Run
build_graphsto add temporal backbone + semantic edges.
build_graphs reports 0 new edges
Expected on a rebuild. Inserts are idempotent, so a second call over an unchanged corpus writes
nothing and correctly reports 0 new. Read the accompanying total (N new edge(s), M total) —
if the total is non-zero the graph is populated and there is nothing to fix.
Before v0.28.0 these counters reported insert attempts rather than rows written, so a call that persisted nothing could still report a healthy-looking count. If you are on an older version, a non-zero count is not evidence that edges landed.
Totals count only edges whose both endpoints are active, matching the population the builders operate on — so archiving documents legitimately lowers the total.
search returns results but query returns nothing
queryapplies stricter scoring (composite + MMR + expansion). If expansion LLM is down, the pipeline may return empty.Fix: Check GPU connectivity. Use
searchorvsearchas a fallback.
clawmem doctor reports "Reranker: degenerate / not discriminating" (or query results feel keyword-only / RRF-like)
The reranker endpoint responds but its scores do not discriminate — the classic cause is a zerank-2 GGUF without its score head — most uploads, including the
zerank-2-Q4_K_Mone ClawMem recommended before v0.11.3 (llama.cpp's standard converter drops the head → near-zero, uninformative scores), so the rerank stage contributes nothing and the final ranking collapses to RRF. The guard catches this:blendRerankfalls back to RRF when no score clearsRERANK_DEGENERATE_FLOOR(1e-4) and emits a rate-limited[clawmem] reranker degraded → RRF fallbackwarning;clawmem doctorsection 9 (andclawmem rerank-health) probe it directly with a golden hard-pair set.Diagnose:
clawmem rerank-health(add--jsonfor the raw coverage / max-score / min-margin numbers). A healthy reranker shows coverage N/N, max score ≥ 0.05, and a minimum per-pair margin ≥ 0.25; a degenerate one shows a near-zero max score or ~0 margins.Fix: re-deploy a working reranker — zerank-2 as the Q8_0 GGUF that carries its score head or the bf16 seq-cls sidecar (both in inference services), or the default
qwen3-reranker-0.6B— and confirmCLAWMEM_RERANK_URLpoints at it. Re-runclawmem rerank-health; it should exit 0. For a remote reranker, scheduleclawmem-rerank-health.timer(systemd services) so a future silent reversion pages you.
Vector search returns weak or irrelevant results even though embeddings exist
BM25/keyword search works and
doctorshows vectors present + consistent, butvsearch/find_similar(and the vector half ofquery) 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: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).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.
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 doctorruns this battery automatically (geometry canary), andclawmem embedrefuses to build against a failing geometry (override:--force-geometry).Fix: launch the embedding
llama-serverwith the pooling its model requires (--pooling lastfor 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 fullclawmem embed --forceis 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.Note on
_clawmem/system docs (observations/deductions): since v0.21.0 the MCP retrieval tools exclude the_clawmemcollection by default (passincludeInternal: trueto include it; an explicitcollectionfilter naming_clawmemalso 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.Operational: don't run
embed --forcewhile the file watcher is indexing bulk changes — stop the watcher or expect write contention (the run now survives transientSQLITE_BUSY, but contention still slows it). If you pipe embed output throughtee, remember the pipeline exit code istee's — checkPIPESTATUS[0]for the embed's own status.
kg_query returns empty for every entity
entity_triplesis 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.Check triple population:
sqlite3 ~/.cache/clawmem/index.sqlite "SELECT COUNT(*) FROM entity_triples".Check observation persistence:
sqlite3 ~/.cache/clawmem/index.sqlite "SELECT COUNT(*) FROM documents WHERE collection='_clawmem' AND content_type='observation' AND active=1". If zero, decision-extractor has never fired successfully.Check observer schema compatibility: the observer LLM must emit
<triples>blocks alongside<facts>. Older prompts may not include this schema — re-runclawmem setup hooksto refresh the hook binaries, and verify the observer is a recent build.Fix: Restart the clawmem-watcher service to clear stuck state. Run a real Claude Code session and check if the next
entity_triplescount increments.Historical context: BACKLOG.md §1.6 documents a pre-v0.8.5 bug cluster where
entity_triplesstayed at 0 regardless of activity due to regex+gate issues in decision-extractor. v0.8.5 fixes all of this — if you're on an older version, upgrade.Symptoms you're hitting the pre-v0.8.5 cluster (one or more present together): (1)
entity_triplesis 0 or near-0 despite tens of observations in activity; (2)SELECT COUNT(*) FROM entity_nodes WHERE entity_type='auto'returns > 0 — the old regex path minted nodes withentity_type='auto'which is not a valid bucket, so those entities never resolve viakg_query; (3)SELECT path FROM documents WHERE collection='_clawmem' AND path LIKE 'observations/%'shows at most one row per (date, session, obs_type) — the old path scheme had no hash disambiguator, so multiple same-type observations in one session collided onUNIQUE(collection, path)and were silently dropped (second observation's triples lost with it); (4) any survivingentity_triples.source_factvalues look like'Individual atomic fact'or similar schema-placeholder strings that leaked from the observer prompt.Upgrading to v0.8.5 on an already-polluted vault: upgrading alone does NOT retroactively repair damage — the broken triples/entities are still in SQLite and the lost observations are gone for good. Two cleanup options: (a) for a low-value vault, let it bleed in — new activity populates cleanly from v0.8.5 onward, and dead
entity_type='auto'rows are harmless (they never resolve viakg_query). (b) For a cleaner slate, delete just the polluted rows and let A-MEM re-enrich on next activity:sqlite3 ~/.cache/clawmem/index.sqlite "DELETE FROM entity_triples WHERE source_fact LIKE '%atomic fact%' OR source_fact LIKE '%canonical entity name%'; DELETE FROM entity_nodes WHERE entity_type='auto';". A fullclawmem reindex --enrichdoes not make extraction re-fire across the whole vault: it re-extracts entities only for documents that are new or changed since their last extraction (enrichment lifecycle), and it never runs triple extraction.Confirm v0.8.5 path is live: after a real Stop-hook-firing Claude Code session,
sqlite3 ~/.cache/clawmem/index.sqlite "SELECT source_fact FROM entity_triples ORDER BY created_at DESC LIMIT 5"should show reconstructedsubject predicate objectstrings (e.g.ClawMem depends_on Bun), never JSON or placeholder text.SELECT DISTINCT entity_type FROM entity_nodes WHERE entity_id IN (SELECT subject_id FROM entity_triples ORDER BY created_at DESC LIMIT 50)should show only real bucket types (project,service,tool,concept,person,org,location), neverauto.
kg_query shows facts under an entity with a different number in its name
Through v0.43.1 the entity resolver could merge names that differ only in a number (facts about
Node 200stored onNode 202), andkg_querycould answer a name or an ID with a more-mentioned entity that shared one word with it. v0.43.2 fixes both: the resolver for new links, andkg_query's lookup; links stored earlier stay where they are. To move the links made earlier, runclawmem repair entities(v0.43.4): a dry run first, then--apply --vault <name> --expect <digest>(repairing links; upgrading).
Indexing
Watcher fires events but collections show 0 docs
Fixed in current version. Was caused by
Bun.Globnot supporting brace expansion{a,b,c}.If still occurring: check collection patterns in config.yaml.
Watcher fires events but wrong collection processes them
Fixed in current version. Collections are now sorted by path length (most specific first).
A file saved by an editor or agent tool is not re-indexed until clawmem update (Bun before 1.4.0)
Symptom: after a save, the watcher journal shows no
[change]or[rename]line for the file, although atouchof the same file logs one. Common with Claude Code's Write and Edit tools, editors with safe-write or atomic save, and atomic-write libraries.Cause: those tools save atomically: they write a temp file beside the target (
notes.md.tmp.4242.9f3c) and rename it over the target. Bun before 1.4.0 folds the events that reach one watched directory together into one callback per event type, named after the first file, so the save arrives under the temp file's name and the watcher's.mdfilter drops it. A rename inside a directory arrives under the old name only, and of two files written or deleted back-to-back in one directory only the first arrives.Fixed in v0.40.2: every event schedules one rescan of its directory (
debounceMs, 2 s, after the first event), which compares each.mdfile with the directory's listing (inode, size, mtime and ctime) and re-indexes each one that appeared, changed or disappeared. Restart the watcher after upgrading and runclawmem updateonce to index anything it missed.One case stays out of reach of a rescan: a rewrite that keeps the file's size and lands within one filesystem timestamp tick of the watcher's last look at it leaves all four values unchanged. On Bun before 1.4.0, if its event is folded away, that write waits for the file's next change or a full pass; Bun 1.4.0 or later reports it by name.
On an older ClawMem: upgrade Bun to 1.4.0 or later (
bun upgrade) and restart the watcher, which fixes the event names; until then, runclawmem updateafter saves the watcher missed.
Files in a directory made after the watcher started are not re-indexed until clawmem update (before v0.40.3)
Symptom: a directory made under a watched collection while the watcher runs (a new Claude Code project and its
memory/, a copied or moved-in folder) never shows[change]or[rename]lines in the watcher journal;clawmem updateindexes its files, and after a watcher restart its changes re-index.Cause: the watcher walked each collection path once, at start, and never added a watch. A watched directory deleted and made again at the same path kept its old watch, which receives nothing for the new directory (on ext4 the new directory even gets the old inode number back).
Fixed in v0.40.3: every rescan also looks at its directory's subdirectories, with the startup walk's rules. A new one is watched, before it is listed, and so are the directories under it; each
.mdfile it already holds is re-indexed. A gone one stops being watched, and each file it held is re-indexed once more, so the removal reaches the vault. A replaced one (a new directory at the same path, told apart by its birth time) is watched anew. The journal logs[watcher] new directory <path>: watching N dirs(orreplaced directory). Restart the watcher after upgrading and runclawmem updateonce.Still unwatched: directories past a collection path's cap, where new directories count too (look for
WARNING: <path> is at its cap of <cap> watched dirs, then raiseCLAWMEM_WATCH_MAX_DIRS); excluded and.-prefixed directories; a symlink to a directory made while the watcher runs, unless it is a collection path itself (the index pass does not follow symlinked directories below a collection path, so nothing under one is indexed); every directory made under a collection path whose startup walk was already over the cap; and a collection path that did not exist when the watcher started, unless its parent is watched under another collection path. A new directory that cannot be watched yet (its permissions, the kernel's watch limit) is reported once as aWatch errorand tried again at each rescan of its parent. On a filesystem without birth times, a directory deleted and made again with the same inode number keeps its dead watch until a restart.
The watcher logs Watch error: database is locked, and a changed file keeps its previous version (before v0.43.3)
Symptom: the watcher journal shows
Watch error: database is locked, usually right after a[change]line, and the vault keeps the changed file's previous version until the file changes again orclawmem updateruns.clawmem update,clawmem reindex,clawmem mine, the MCP toolsreindexandvault_sync, and the REST server'sPOST /reindexcan fail with the same error.Cause: an index pass ran in a deferred transaction. It read the stored rows first and asked for the write lock only at its first write, for a new or changed file. SQLite does not call the busy handler when a connection that already holds a read transaction asks for the write lock, so when another process was writing to the vault (a hook, the MCP server,
clawmem embed), or had committed since the pass began reading, that write failed at once andbusy_timeoutnever applied. The pass rolled back whole.Fixed in v0.43.3: the pass opens with
BEGIN IMMEDIATE: it takes the write lock first, waiting up tobusy_timeout(5 s by default) for it. Restart the watcher after upgrading and runclawmem updateonce to index anything a failed pass left behind.Still possible: a pass fails as before when another process holds the write lock for longer than
busy_timeout, now after the wait; so can a pass with nothing to write, which took no write lock before. While the watcher's pass waits, the watcher answers no vector searches; a hook whose vector search runs out of time falls back to keyword search for that prompt.
reindex --force crashes with "UNIQUE constraint failed"
Fixed in current version. Force mode now reactivates inactive rows instead of inserting.
reindex --force after v0.2.0 upgrade shows no entity extraction
reindex --forcetreats existing documents as updates (isNew=false). The A-MEM pipeline skips entity extraction, link generation, and memory evolution for updates to avoid churn on routine reindexes.Fix: Use
clawmem reindex --enrichinstead. The--enrichflag runs the full enrichment pipeline (entity extraction + canonical resolution + co-occurrence tracking + link generation + memory evolution) on all documents, including unchanged ones; entity extraction itself runs only for a document with no recorded extraction or whose title or body changed since its last one (enrichment lifecycle), which covers documents indexed before entity resolution existed.--forcealone only refreshes A-MEM notes (keywords, tags, context).--enrichis needed after major upgrades that add new enrichment stages (e.g. 0.1.x → 0.2.0 added entity resolution).Always run ClawMem through the
bin/clawmemwrapper, notbun run src/clawmem.tsdirectly. The wrapper sets GPU endpoint defaults (CLAWMEM_EMBED_URL,CLAWMEM_LLM_URL,CLAWMEM_RERANK_URL). Bypassing the wrapper causes fallback to slow in-processnode-llama-cppinference.
Hooks
<vault-postcompact> shows another session's pre-compaction state (its last request, decisions or files)
ClawMem ≤ v0.39.1 kept one
precompact-state.mdper project directory and injected it on every session start there, so a session could receive another session's last compaction, or an old one again. Fixed in v0.40.0: the state is one row per session in the vault, taken once by the start that follows that session's own compaction. The block's recent decisions, antipatterns and vault context come from the whole vault on purpose; only the pre-compaction state is per session.Upgrade every ClawMem that shares the vault: the hooks, the watcher, the MCP server in every open session, and the OpenClaw or Hermes plugin. An older one still running keeps the old behaviour. Then re-run
clawmem setup hooksand delete the old filesclawmem doctorlists; it shows red while one is still being written after the upgrade.
No pre-compaction state after /compact
The PreCompact met a busy vault, failed or timed out. It then stores nothing, on purpose, so that nothing older is injected in its place. On the first open after the upgrade, a vault another process keeps busy can make that one open fail the same way.
postcompact-injectis not installed for thecompactstart: re-runclawmem setup hooks.More than 15 minutes passed between the PreCompact and the start that follows it: an older state is never injected.
The transcript had nothing to extract: no typed request, decision or file path. Open questions alone are not stored.
OpenClaw and Hermes store the state at compaction, but nothing in them reads it back yet.
clawmem doctor compaction lines (v0.40.0)
"postcompact-inject is installed under SessionStart matcher …": re-run
clawmem setup hooks."Legacy pre-compaction state: N precompact-state.md file(s) left by ClawMem ≤ v0.39.x": delete the files. In red ("written after this vault was upgraded"), an older ClawMem process is still running against the vault: upgrade it.
"… indexed cop(y|ies) of an old snapshot … still active":
clawmem updatedeactivates each one whose file is on disk or was deleted; one from before v0.34 whose file is gone stays until you forget it by its exact path.
clawmem doctor stop-pipeline lines (v0.41.0)
"✗ Stop pipeline: migration incomplete (…)": the migration transaction did not commit, usually because another process held the vault's write lock longer than the open waited. The store still opens, but the Stop hooks skip their counter and cursor work. Any writable open retries it; run
clawmem doctoragain after stopping the busy process."✗ Stop pipeline: an older ClawMem still writes to this vault …": the fence caught writes from a ClawMem older than v0.41.0 (each surface with its count and last time). Those writes were skipped, and that version's
context-surfacinginjects nothing. Upgrade or stop every ClawMem process that shares the vault — the watcher,clawmem serve, MCP servers in open sessions, the OpenClaw and Hermes plugins. Once nothing has been caught for 24 h, doctor reports the log as past instead of failing."! counter recompute pending":
clawmem watchruns it once at its next start; without a watcher, runclawmem repair counters --apply."! Stop pipeline queues: … older than 24 h": nothing drained them —
clawmem watchis not running, or its worker cannot reach the vault. Start the watcher, or drain by hand withclawmem repair stop-queue --run. A quarantined range whose bytes changed is listed as unavailable; dismiss it withclawmem repair stop-queue --dismiss <id>."N feedback verdict(s) provisional": an OpenClaw or Hermes turn credited on a quiet transcript; it becomes final at the next turn, Stop or session end. Informational.
"N feedback turn(s) wait for their OpenClaw transcript to be bound": surfacing rows written before OpenClaw could resolve the session's file. They are bound by the session's next prompt,
agent_endorsession_endthat resolves it."! … causal step(s) wait while CLAWMEM_CAUSAL_WRITER=off": ranges committed while the writer was
shadow/on. They run when it is on again; to keep the lane off for good, setCLAWMEM_CAUSAL_WRITER=offfor the watcher and the hooks, thenclawmem repair stop-queue --dismiss-causaldrops them. It refuses while this shell's writer is notoff, and while the vault shows a causal step queued or run in the last hour, since those steps are runnable. It cannot see an idle consumer, so switch the writer off everywhere first."N overwritten antipattern bodies preserved": review them with
clawmem recover antipatterns."! Claude Code hooks: the SessionEnd handoff flush is not installed": re-run
clawmem setup hooks.
Stop-hook ranges pile up as model unavailable while the LLM server is up (v0.41.0)
Symptom:
clawmem repair stop-queueshows quarantined ranges that keep coming back; the hook or watcher log shows[generate] Remote LLM HTTP 400and[llm-retry] observer.extractObservations: exhausted after 3 attempt(s); the server answersthe request exceeds the available context size, try increasing it. The observer model runs with-c 4096, as the docs prescribe.Cause: v0.41.0's observer prompt carried a CONTEXT section as large as its transcript, up to about 5,400 tokens. The server refused it, and three refusals in a row also put the process's LLM endpoint into its 60-second cooldown (in-process generation meanwhile, or none with
CLAWMEM_NO_LOCAL_MODELS=true).Fixed in v0.41.1: the section and the transcript, with a retry's error feedback, stay within the 8,000 characters v0.40's transcript could take. That is a bound in characters: text that tokenizes very densely can still pass 4,096 tokens, as in v0.40. Upgrade the hooks and restart the watcher; each queued range is due again at most 12 hours after its last attempt and replays when the watcher or a later Stop next runs. Raising the server's
-calso works on v0.41.0.v0.41.2 counts the prompt in tokens instead; see the next entry.
Stop-hook ranges stay quarantined on dense turns, or the observer's reply is cut short (v0.41.1)
Symptom: a range keeps coming back in
clawmem repair stop-queuewhile the server answers every request; the server's reply ends withfinish_reason: "length"after a few dozen tokens, or the hook log shows[llm-retry] observer.extractObservations: exhausted. Turns full of hashes, hex, JSON, logs or non-Latin text are the usual trigger.Cause: v0.41.1 bounded the prompt in characters. Such text runs about 1.1 to 1.3 characters per token (prose about 5.7), so an 8,000-character prompt plus the 2,825-character system prompt filled 4,072 of the 4,096 tokens and left the reply 24. The cut reply did not parse, every retry had the same size, and the range was quarantined for good. A cut reply with no
<in it was read as "nothing to record", so that turn's observations were lost.Fixed in v0.41.2: the observer reads the server's context from llama-server's
/propsbefore each model call of the Stop pipeline, retries included (elseCLAWMEM_LLM_CONTEXT_TOKENS, else an assumed 4,096), counts its prompt in tokens through/apply-templateand/tokenize, and keeps a reply reserve of 40% of the context (768 to 2,000 tokens). A turn larger than one prompt runs as windows inside one Stop, each window seeing the titles of the observations already found. A reply the server reports as cut is never parsed: that window runs again at half its size. A reply that did not finish as an answer (no completion choice, or a finish reason such ascontent_filter) is held for a retry, never read as "nothing to record". A server that sends nofinish_reasonat all (llama-server, vLLM, Ollama and OpenAI all send one) gets a best-effort reading, logged once per process as "The LLM server's replies carry no finish_reason": a reply that used its whole allowance counts as cut, any other as complete, so a reply its context cut can still be misread there. Progress is kept in a durable checkpoint, so a Stop that runs out of time between windows leaves a continuation that resumes after the last finished window (since v0.41.4, one that runs out while a window waits for its retry fails the attempt with the failure backoff instead).Upgrade every process that shares the vault (hooks, watcher, MCP servers, plugins). Each queued range is due again on its old schedule (at most 12 hours) and runs in windows. Serving the observer model with
-c 8192gives each window about three times the transcript room of-c 4096(measured figures in inference services; about +470 MiB VRAM); the docs now prescribe it.clawmem doctorshows the nominal window allowance for your server (an actual window can be smaller: see the doctor line below).
clawmem doctor observer lines (v0.41.2)
"✓ LLM context: N tokens (measured via /props); counting template-exact; fingerprint strong — an observer window holds W transcript tokens (R-token reply); mean observer call T s (latest K call(s))": the observer's nominal budget on this server. W is what one window leaves for the transcript after the system prompt, the reply reserve and the counting margin (none when the count is template-exact), computed from
/propsas read: the context section a window carries, and since v0.41.4 a remembered context ceiling below/props(an earlier validated oversize), make an actual window smaller. T is the mean of the latest K (at most 50) observer model calls the Stop pipeline recorded ("not measured yet" until a hook or the watcher has made one).The same line with "! … One observer call takes longer than the watcher's 18-s slice": the watcher cannot finish a window in its tick, so a long turn progresses only through Stops. Use a faster model or a GPU.
The same line with "! … Observer windows are small": W is under 1,000 tokens on a measured or configured context. Raise the server's
-c(8192 is the prescribed value) and restart it.The same line with "! … Prompt fits are best-effort here": the context is assumed (no
/propsand noCLAWMEM_LLM_CONTEXT_TOKENS) or the server does not serve/apply-template, so the observer counts by estimate with a margin. SetCLAWMEM_LLM_CONTEXT_TOKENSto the server's context per request (on llama-server,-cdivided by--parallel). "fingerprint weak" means the observer cannot see a model change behind the same URL, so a turn split into windows resumes across such a change instead of starting again from its first window. A/propsthat gives the context but not the model path, chat template and build reads weak too (its context still counts as measured). When a server whose/propsanswered stops giving a fingerprint (no answer, an error status, a 404, a body that is not llama.cpp's, one without the model, template and build), a turn in progress waits with its windows kept, however long (its queue reason ends "its server could not be verified"); it starts again from its first window only when/propsnames a different model, template or build."! Stop pipeline: N range(s) held because the observer's prompt cannot fit the LLM server's context (capacity: …)": one message, or the observer's fixed prompt, is larger than a window can ever be on this server. The ranges are kept, not dropped: they stay queued on the failure schedule (1 minute, rising to 12 hours) and replay by themselves. Raise the server's
-cand restart it."observer: N continuation(s) queued — the watcher resumes them": a long turn whose windows did not all fit in one Stop's time. Its next window is due within a minute, and
clawmem watchruns it first in its next tick; without a watcher, a later Stop orclawmem repair stop-queue --rundoes. Informational.The same line ending "K wait for their LLM server to answer /props again (it could not be verified)": K of those turns were split into windows on a server whose
/propsanswered, and it has not given a fingerprint since (a timeout, a dropped connection, an error status, a 404, a body that is not llama.cpp's, one without the model, template and build). They resume when it answers again. A server that no longer serves/propsat all, such as another kind of server behind the same URL, keeps them waiting: serve/propsagain, or drop the range withclawmem repair stop-queue --dismiss <id>(its turns are then not extracted)."observer: N live checkpoint(s) without a queued range — a later Stop resumes each one it reaches unchanged": a Stop that ended (killed, or out of time) after saving windows but before queueing its range, while its transcript's cursor is still before the range. The watcher replays queued ranges only, so such a checkpoint waits for a later Stop of the same transcript; that Stop resumes it when it packs the same range (new turns can change the packing, and then the unit starts again and the old checkpoint is swept). A session that has ended leaves it in place, with its turns unextracted, as in v0.41.1 (a catch-up is planned).
"observer: N first-Stop checkpoint(s) with no cursor — a later Stop that reads the same range resumes it; the watcher's sweep removes them after 7 days": a transcript's first Stop saved windows and ended before saving a cursor. A later Stop with no cursor starts at its own turn, so it resumes such a checkpoint when it reads the same range: a repeated Stop in that turn, or a Hermes transcript begun after the upgrade (it starts at its first line). Otherwise its turns are not extracted, and the sweep removes it after 7 days. Informational.
"observer: N checkpoint(s) behind their transcript's cursor (a dismissed or superseded range) — no later Stop reaches them; the watcher's sweep removes them": a range dismissed with
clawmem repair stop-queue --dismiss, one whose bytes changed, or one a re-anchored transcript left behind. Their turns are not extracted; the sweep removes them at the watcher's next tick. Informational."! Stop pipeline: N message(s) in M range(s) were beyond the observer's 100-message window (a very long turn)": the observer reads at most the last 100 messages of one turn, as before; v0.41.2 counts the ones it skipped. Informational.
Stop-hook ranges held with "no parseable response", or a turn committed with no observation (v0.41.3 and earlier)
Symptom:
clawmem doctorcounts quarantined ranges whose reason is "no parseable response within the budget", and they come back after every retry. Or a turn with real work produced no observation at all. The observer model is the documented qmd-query-expansion-1.7B, or another small model.Cause: the model's replies did not follow the schema. Measured on 34 replies to three held ranges: 21 typed an observation
tool_use(copied from the transcript's tool calls), 4 copied the prompt's...placeholder, and 7 came back in the model's query-expansion format. Through v0.41.3 a short reply without markup counted as "nothing to record", so such a turn committed empty and was never observed again. The format retry could not repair a reply: its feedback named a<content>tag the schema does not have and quoted the bad reply back. On a backend whose invocations each afford one call, the retry never ran at all: each invocation sent the same first call and the range came back as a continuation, every minute.Fixed in v0.41.4: only the exact reply
<none/>means "nothing"; the prompt names the allowed types and has no copyable placeholders; a rejected block says why, by class; up to two format retries per window carry feedback that names the failing field and its allowed values; a window that needs a retry it cannot afford fails its attempt with the failure backoff instead of looping; and llama-server (or the in-process model) is asked for a grammar that admits only well-formed replies. Upgrade, then retry the held ranges at once withclawmem repair stop-queue --retry-now held --run(otherwise each retries on its own schedule, up to 12 hours apart). Turns v0.41.3 committed empty after a query-expansion reply are not re-observed.A model that keeps answering in prose, or in another format, still fails each attempt: its ranges stay held with the class in their reason (
no parseable response: no-blocks), visible inclawmem doctor. Serve the observer model through llama-server so the grammar applies, or use a stronger model (see inference services).
clawmem doctor observer reply lines (v0.41.4)
"! Stop pipeline: N range(s) held after failed attempts — held ranges by class: …": the ranges waiting for their next retry, grouped by why their last attempt failed.
type-not-allowed (tool-role): the model typed an observation as a transcript tool role.type-not-allowed (type-list): it copied the list of allowed types.type-not-allowed (placeholder)ortitle-placeholder: it copied template text.no-blocks: it answered with no observation block and no<none/>.empty-reply: it answered nothing.facts-empty: no fact had 5 or more characters of real content.capacity: a window cannot fit, or its reply was cut and the smaller window was not reached in time.grammar: the server refused a grammar request (or the in-process model could not compile the grammar) and the attempt could not afford the grammarless retry.legacy (unclassified): a reason written by v0.41.2 or v0.41.3. The ranges retry on their own backoff;clawmem repair stop-queue --retry-now held --runretries them now."observer: grammar off until T after an HTTP 400 on a grammar request (cause unconfirmed)": the server answered a request that carried the grammar with HTTP 400, so the observer sends no grammar to that server until T (24 hours; a later refusal extends it). "… after the in-process model could not compile the grammar": the same, for the in-process model (its log names the compile error). The 400 may have had another cause: when T passes, the next request carries the grammar again and re-tests the server. "; a grammarless request must reach the server before the grammar is used again": no request without the grammar has been answered since the refusal; the observer sends one first, however late its next attempt comes.
"! Stop pipeline: N completed replies to grammar requests failed structurally — the server may be ignoring the grammar": replies that finished, to requests that carried the grammar, that the grammar should have made impossible (no observation block and no
<none/>, a type outside the list, a missing element, a raw<or&in a field). llama-server honours thegrammarfield; another OpenAI-compatible server behind the same URL may ignore it. Replies the server cut are not counted, and the check is partial (it does not verify element order or every length), so the line says "may". If the server is not llama.cpp, setCLAWMEM_OBSERVER_GRAMMAR=off."observer: K grammar reply(ies) rejected on content; E prompt-clause echo(es) kept and counted; D residue item(s) dropped …": informational. A content rejection is a well-formed block the parser refused (a blank title, template text as a title, no usable fact). An echo is a title, fact or narrative that restates one of the prompt's own rules; it is kept, since it can be true. The drops are triples naming a tool-call id or equal on both sides, copied skeleton identifiers, and repeated facts.
"N unfinished causal run(s) older than 24 hours; not automatically replayed": causal runs a crash interrupted more than a day ago. Informational; v0.41.3 counted them as "still in progress after 1 h" for ever. That warning now counts runs interrupted 1 to 24 hours ago.
Access counts and co-activations dropped after upgrading to v0.41.0
Expected. The one-time recompute set each document's
access_countto its verified references since the upgrade (near zero at first) and rebuilt co-activations andusagerelations the same way; through v0.40.3 every Stop counted the whole session again. Documents whose old access fell inside their archive window got a staggered archive grace (clawmem doctorprojects the expiries per week).clawmem repair counters --restore <op>reverses the recompute; the op id is in the watcher log.
A session's handoff lacks its last turns
The handoff document renders at the summary step, at SessionEnd and in the watcher. Without the SessionEnd hook (
clawmem setup hooksinstalls it since v0.41.0), or when the flush found the vault busy, the watcher renders it once the session has ended or its digests have been quiet for 10 minutes.clawmem repair stop-queue --runrenders it at once.
A handoff turn's request reads [background task …] or [message from …] (v0.43.0)
Expected. Since v0.43.0 a background task's notice and another Claude Code session's message open a turn of their own, and the Stop hooks and PreCompact see them only as labels: the request is the label, never the task's output or the message's text. See Turns.
Hermes sessions keep only their last turn and write no handoff (v0.41.0)
The Hermes plugin copied before v0.41.0 runs the Stop hooks only at session end, and a transcript's first Stop starts at its current turn. Copy the plugin's contents over it and restart Hermes:
cp -r /path/to/ClawMem/src/hermes/. "${HERMES_HOME:-$HOME/.hermes}/plugins/clawmem/"(with the trailing/.—cp -r src/hermesinto an existing directory nests a copy inside it and leaves the old plugin running). The v0.41 plugin runs them after every synced turn.
"UserPromptSubmit hook error" (intermittent)
SQLite contention between the watcher and the context-surfacing hook. During active conversations, Claude Code writes rapidly to session transcript
.jsonlfiles. Prior to v0.1.6, the watcher processed all.jsonlfile changes (not just Beads.beads/*.jsonl), triggering database opens and brief write locks on every transcript update. If the context-surfacing hook fired during a lock, it exceeded its timeout.Fixed in v0.1.6: The watcher now only processes
.jsonlfiles within.beads/directories (Dolt backend). Claude Code transcript.jsonlfiles are ignored entirely, eliminating the main source of lock contention and memory bloat.If you still see this error on v0.1.6+: the watcher's long-lived database connection can prevent SQLite WAL auto-checkpointing, allowing the WAL file to grow unbounded (observed 77MB+). A large WAL forces every concurrent reader (hooks, MCP) to traverse the entire log, amplifying contention under load. Fixed in v0.1.8: the watcher now runs
PRAGMA wal_checkpoint(PASSIVE)every 5 minutes to keep the WAL small.If the error persists after v0.1.8: restart the watcher to clear accumulated state (
systemctl --user restart clawmem-watcher.service). Checksystemctl --user status clawmem-watcher.servicefor memory usage — healthy is under 100MB, bloated is 400MB+.v0.2.4 fix: Hook's SQLite
busy_timeoutwas 500ms — too tight. During A-MEM enrichment or heavy indexing, the watcher can hold write locks for 500ms+, causing the hook's DB open to fail with SQLITE_BUSY. Raised to 5000ms (matches MCP server). The hook's 8s outer timeout still leaves 3s for actual work after a 5s busy wait.v0.3.1 fix: Shell
timeoutwrappers (e.g.,timeout 8 clawmem hook context-surfacing) kill the process with exit 124 and no stderr — Claude Code reports "Failed with non-blocking status code: No stderr output". This affects all hook events (UserPromptSubmit, Stop, SessionStart, PreCompact), not just Stop hooks. Fix: Remove shelltimeoutfrom all hook commands and use Claude Code's nativetimeoutproperty instead. Runclawmem setup hooksto reinstall with correct config (v0.3.1+), or manually update~/.claude/settings.json— see setup-hooks.Large vault + intermittent hook timeout (
timed out after 8s) — FIXED in v0.16.0. Earlier this was diagnosed as pure cold-start (fresh Bun process, opening a largeindex.sqlite, re-reading evicted index pages) with "give the host more RAM" as the durable fix — but the dominant causes were two code-level defects: (1) thecontext-surfacingvector leg ran a synchronoussqlite-vecscan that thePromise.race(vectorTimeout)guard could not bound (a synchronous call blocks the event loop, so the timer never fires), and (2) every writable hook open ran an unconditional backfillUPDATEthat could wait outbusy_timeoutunder writer contention. v0.16.0 fixes both:searchVectakes a real wall-clock deadline and self-aborts before the blocking scan; both vector legs race the embed against the remaining budget and clear their timers; the init backfill is read-guarded and the initbusy_timeoutis capped to the caller's value; and the watcher prewarms the sqlite-vec payload into the page cache on startup (embed-independent, watcher-only). A cold page cache still adds latency to the genuine first post-boot call, so host RAM headroom + the prewarm help the margin — but on a large vault the scan cost, not RAM, was the trigger. A modesttimeoutbump (see the tradeoffs table under Hooks slow or near timeout) remains a secondary margin. Thedeepprofile additionally reranks (extra remote round-trips), widening the cold-call window;balanced(default) does not rerank. v0.20.0 adds the true hard cap: runclawmem watchand the hook sends the query to the watcher, which runs the blocking scan off the hook's event loop and returns the raw matches for local hydration — a cold scan then times out fast and falls back to FTS instead of blocking the turn. It is a pure optimization layer: when the watcher isn't running the hook uses the in-process, deadline-bounded path unchanged.
Watcher memory bloat (400MB+)
The watcher accumulates memory when processing high-frequency file change events. The most common trigger was Claude Code session transcript
.jsonlfiles changing on every keystroke during active conversations. Each event opened the database briefly, and over hours of active use, memory grew to 400-800MB.Fixed in v0.1.6: transcript
.jsonlfiles are no longer watched. Memory stays under 100MB during normal operation.If memory still grows: check which files are triggering events (
journalctl --user -u clawmem-watcher -f). Common remaining causes:
Diagnosing watcher memory issues:
Identify what's triggering events. Watch the journal in real time:
journalctl --user -u clawmem-watcher -fEach
[change]or[rename]line shows the collection and file. High-frequency entries point to the source.Broad collection paths with narrow patterns. If a collection has a broad path (e.g.
path: ~/Projects) but a narrow pattern (e.g.pattern: "specific-file.md"), the watcher receivesfs.watchevents for every.mdchange under that entire tree — even files that don't match the pattern. Prior to v0.1.7, each event still triggeredindexCollection()and opened the database.Fixed in v0.1.7: the watcher pre-checks if the changed file could match the collection pattern before calling
indexCollection(). Non-matching files are silently skipped with no DB access.If you're on an older version: narrow the collection path to the smallest directory that contains the files you actually want indexed.
Fixed in v0.40.1: the pre-check read a pattern's directory part as literal text and split brace lists by stripping one leading
{and one trailing}, so it dropped every event for a pattern with a wildcard directory (*/memory/**/*.md) or a brace list followed by a suffix ({README,guide}.md). Those collections re-indexed only onclawmem update. The pre-check now matches the way an index pass scans, and an event reaches every collection that would index the file (before, only the collection with the longest matching path got it). After upgrading, restart the watcher and runclawmem updateonce to index anything the old pre-check skipped.
Git operations in watched directories.
git pull,git checkout, orgit mergein a directory covered by a**/*.mdcollection can change hundreds of.mdfiles at once. Each triggers a watcher event, and even with debouncing (2s), batches of changes arrive in rapid succession.Not a bug — the watcher is doing its job (re-indexing changed docs). But if this causes contention with hooks, restart the watcher afterward:
systemctl --user restart clawmem-watcher.service.
Editor autosave and temp files. Some editors (VS Code, JetBrains) write
.md~,.md.tmp, or shadow copies during autosave. These don't match the.mdextension check in the watcher, but frequent filesystem churn in the same directory can causefs.watchcallback overhead on some platforms (especially WSL2 where filesystem events cross the Linux/Windows boundary).Fix: If memory grows without visible
[change]log entries, the overhead is infs.watchitself, not in ClawMem's handler. Consider reducing the number of watched directories by consolidating collections or excluding directories with heavy non-.mdfile churn.Since v0.40.2 an event for any file,
.mdor not, also schedules one rescan of its directory, at most one per directory everydebounceMs(2 s): it reads the directory and stats its.mdfiles 256 at a time, letting other work run between batches, and it reaches the database only when one of those files changed (see the Indexing entry on atomic saves).
Too many watched directories / inotify FD exhaustion (v0.2.3 fix).
Prior to v0.2.3, the watcher used
fs.watch(dir, { recursive: true })which registers an OS-level inotify watch on every subdirectory in the tree — including excluded directories likegits/,node_modules/,.git/. TheshouldExclude()filter only prevented processing events from excluded paths but couldn't prevent the kernel from allocating inotify handles for them. A collection path like~/Projectswith 67,000 subdirectories would exhaust inotify limits and eventually hang WSL or Linux.Fixed in v0.2.3: The watcher now walks each collection directory at startup, skips excluded subtrees (using the same
EXCLUDED_DIRSlist as the indexer), and watches each non-excluded directory individually (non-recursive). A cap of 500 directories per collection path limits overly broad collection paths; since v0.40.1CLAWMEM_WATCH_MAX_DIRSsets it. Past the cap the watcher logsWARNING: /path has N dirs — watching the first 500; changes in the others wait for the next full index pass (clawmem update). Raise the cap with CLAWMEM_WATCH_MAX_DIRS, or narrow the collection path.(before v0.40.1:… capping at 500 to prevent FD exhaustion …). The directories past the cap are not watched, and which ones they are depends on the walk order, so a change in one of them reaches the vault only on the collection's next full index pass.Raising the cap: set
CLAWMEM_WATCH_MAX_DIRSon the watcher process (for the systemd unit, a drop-in — see systemd services) and restart it. Each watched directory is one inotify watch on Linux: compare the watcher's inotify watch count (the diagnosis above) with the per-user limit below, leaving room for other processes. The startup log's[watcher]counts (watching N dirs, or the cap where a line sayswatching the first) add up to an upper bound, since overlapping collection paths register some directories twice. See configuration.Symptoms (before v0.2.3): WSL hangs or becomes unresponsive during long sessions, hook timeouts increase, and system memory climbs without visible cause.
Diagnosis: count the watcher's inotify watches, not its file descriptors. Bun keeps all of a process's watches on one inotify descriptor, so the watcher's FD count stays small however many directories it watches:
cat /proc/$(pgrep -f "clawmem.*watch" | head -1)/fdinfo/* 2>/dev/null | grep -c '^inotify wd'. Nearmax_user_watches(below, shared with every other process) → narrow collection paths, lowerCLAWMEM_WATCH_MAX_DIRS, or raise the limit.If still high after v0.2.3: Narrow collection paths. A collection with
path: ~/Projectswatching a single file is wasteful — move the file to a subdirectory or create a dedicated directory for it. Check the watcher startup log for the[watcher]lines showing dir counts per collection.Check max inotify watches:
cat /proc/sys/fs/inotify/max_user_watches(Linux default: 8192). If the watcher reportsENOSPCerrors, increase:echo 65536 | sudo tee /proc/sys/fs/inotify/max_user_watches.macOS: FSEvents has no hard limit but memory scales with watched directory depth.
Healthy baseline. After a fresh restart, the watcher should stabilize under 100MB within 30 seconds. If it immediately spikes above 200MB during startup, check
journalctl --user -u clawmem-watcherfor rapid-fire events during initialization (common when collections contain recently-changed files that trigger immediate indexing).
Quick recovery: systemctl --user restart clawmem-watcher.service — clears accumulated state, resets memory. Safe to do at any time; the watcher re-discovers its watch targets on startup.
"Stop hook error: Failed with non-blocking status code: No stderr output"
Caused by shell
timeoutwrappers (e.g.,timeout 10 clawmem hook ...) killing the process with exit 124 before LLM inference completes. The Stop hooks (decision-extractor,handoff-generator,feedback-loop) call an LLM which routinely takes 8-15s with real transcripts.Fix: Remove shell
timeoutfrom hook commands and use Claude Code's nativetimeoutproperty instead. Runclawmem setup hooksto reinstall with correct config (v0.3.0+), or manually update~/.claude/settings.json— see setup-hooks.
Hooks hang or timeout
GPU services are unreachable, causing embedding/LLM calls to block until timeout.
Fix: Check GPU connectivity (
curl http://host:8088/health). Hook timeouts are 8s for context-surfacing, 5s for SessionStart/PreCompact hooks, 30s for Stop hooks. See setup-hooks for the full table.
Hooks slow or near timeout (4-6s per invocation)
Each hook spawns a fresh Bun process. If the hook path requires
node-llama-cpp(in-process models), the native addon import alone costs ~3.5s, leaving very little headroom in the 8s timeout for actual search and scoring.This only happens when no
llama-serveris running and the hook falls back to in-process inference. The MCP server (long-lived process) does not have this problem —node-llama-cpploads once at startup and stays warm.Who is affected:
| Setup | Hook latency | Notes |
|---|---|---|
llama-server running (local or remote) | ~200ms | Hooks use HTTP calls, never import node-llama-cpp. Recommended. |
| In-process Metal (Apple Silicon) | ~4-5s | node-llama-cpp addon import + model load. Under 8s but tight. |
| In-process Vulkan (discrete GPU) | ~4-5s | Same as Metal — addon import is the bottleneck, not inference. |
| In-process CPU-only (no Metal, no Vulkan) | >8s | Will timeout. Use speed profile or cloud embedding. |
Cloud embedding (CLAWMEM_EMBED_API_KEY set) | ~500ms | HTTP call to cloud provider, no node-llama-cpp needed. |
Fix by setup type:
Best: Run
llama-serverlocally — even on the same machine, a persistent server eliminates the per-invocation import. See the inference services guide for setup. This is what most users will do in practice.Quick: Set
CLAWMEM_PROFILE=speed— disables vector search in hooks entirely, pure BM25, never loadsnode-llama-cpp. Hooks complete in under 500ms.Cloud: Set
CLAWMEM_EMBED_API_KEY+CLAWMEM_EMBED_URL+CLAWMEM_EMBED_MODEL— query embedding via cloud API, no local models needed in the hook path.Fail-fast: Set
CLAWMEM_NO_LOCAL_MODELS=true— preventsnode-llama-cppfrom loading at all. Hooks degrade to BM25-only when GPU servers are unreachable, instead of blocking for 3.5s on a fallback import.
Why not keep models warm? Claude Code hooks spawn a fresh process per invocation (by design — hooks are shell commands). There is no persistent process between hook calls. The MCP server does keep models warm via a 5-minute inactivity timer, but that only benefits MCP tool calls, not hooks.
Tuning the context-surfacing hook timeout. Two knobs exist since v0.38.0: the hook's internal budget
CLAWMEM_HOOK_BUDGET_MS(default 6000ms, maximum 25000ms — larger values are refused by the hook, byclawmem setup hooks, and reported byclawmem doctor; the authoritative schedule every in-handler deadline derives from, on the MONOTONIC clock since O1, including the deep-escalation and rerank windows and the 500ms finalization reserve) and the hosttimeoutin~/.claude/settings.json(the outer kill switch — it must be ≥ 1.5s startup allowance + the internal budget;clawmem setup hookswrites both together and pins the budget into the installed command, andclawmem doctorchecks the inequality). The budget bounds the vector leg only when the watcher's vector daemon serves the vault (clawmem watch) — the sqlite-vec MATCH is synchronous and cannot be interrupted in-process, so a hook that overruns on a cold scan without the watcher running is the expected watcher-free behavior, not a budget defect (v0.38.0 also fixes a stale daemon socket left by a crashed watcher silently preventing the next watcher from binding its daemon).clawmem doctorreports the daemon's liveness for the vault by a real round trip, andclawmem vec-daemon-health(exit 0 only when live) is the scriptable form. If you're using in-process Metal/Vulkan and hooks are timing out intermittently, raise the host timeout in~/.claude/settings.json. Use the nativetimeoutproperty (in seconds), not a shelltimeoutwrapper:{ "type": "command", "command": "/path/to/clawmem hook context-surfacing", "timeout": 12 }Or re-run
clawmem setup hooks(v0.3.1+) which generates correct config automatically.Tradeoffs of longer timeouts:
Timeout Effect 8s (default) Good balance for llama-serversetups (~200ms) and Metal/Vulkan in-process (~4-5s). Tight for CPU-only.10-12s Accommodates in-process Metal/Vulkan with SQLite contention headroom. Adds a noticeable delay before Claude sees your prompt when the hook is slow — you'll see the spinner for up to 12s on cold starts. 15s+ Not recommended. Claude Code waits for the hook before processing the prompt. A 15s hook makes the agent feel unresponsive on every first prompt and after any Bun cache invalidation. If you need this, run llama-serverinstead.5s or less Only viable with llama-serverrunning orCLAWMEM_PROFILE=speed. In-process models will always timeout.The timeout applies per invocation. A slow first prompt (cold start) doesn't mean subsequent prompts will be slow — Bun caches modules after the first load, and
node-llama-cppmodel files are cached on disk after the first download. Subsequent prompts in the same session are typically faster.Exception — large vaults (intermittent, pre-v0.16.0): before v0.16.0 the hook could time out on certain turns (not just the first) because of an unbounded synchronous
sqlite-vecscan plus an init-time write-lock wait — see "UserPromptSubmit hook error" (intermittent) above. Upgrade to v0.16.0, which bounds the scan and the init path and prewarms the cache (v0.20.0 adds the vector-query daemon — a true hard cap on the cold scan when the watcher runs). Host RAM headroom + the watcher prewarm still help the genuine cold-call margin, but they were not the root cause.Stop hooks (
decision-extractor,handoff-generator,feedback-loop) default to 30s (v0.3.1+, was 10s prior) because they run LLM inference (observer model). These run at session end, so latency doesn't block the user.
"Stop hook error: Failed with non-blocking status code: No stderr output"
Claude Code expects all hooks (including Stop hooks) to output valid JSON to stdout. A hook that exits 0 but produces no stdout is treated as an error — "non-blocking status code" means exit 0, "no stderr output" means Claude Code has no error message to show.
This typically happens with custom Stop hooks (not ClawMem's built-in hooks, which always output
{"continue":true,"suppressOutput":false}). If you add your own Stop hook alongside ClawMem's, every code path must output JSON — including early returns, error handling, and default/fallback paths.Common pattern that causes this:
# BAD — exits 0 with no stdout on the early-return path if [[ -z "$some_var" ]]; then exit 0 fi # GOOD — always output JSON OK='{"continue":true,"suppressOutput":false}' if [[ -z "$some_var" ]]; then echo "$OK"; exit 0 fiIf you have a Stop hook that blocks the agent (outputs
{"continue":false}), use{"continue":false,"stopReason":"..."}to provide context.Diagnosis: Expand the Stop hooks output (ctrl+o) to see which hooks ran. Test each hook manually:
echo '{"transcriptPath":"/path/to/transcript.jsonl","sessionId":"test"}' | bash ~/.claude/scripts/your-hook.sh— verify it outputs JSON.
Hook fires but returns empty context
The context-surfacing hook filters aggressively. Common causes:
Prompt too short (< 20 chars; short memory-intent queries are exempt and force retrieval), starts with
/, or matches the heartbeat/greeting filterDuplicate prompt within the 600-second dedup window (SHA-256 hash match)
Vector search silently failed (dimension mismatch, server down), leaving a BM25-only candidate set that admission judged degenerate
Relevance admission abstained (v0.38.0): no candidate had current-turn support (
no-current-support), or no candidate had keyword-class agreement — FTS found nothing, the vector-only junk signature (degenerate-basis). The hook prefers emitting nothing over surfacing a weak or arbitrary list; on a gibberish or fully-off-vault prompt this is the designed outcome.Turn-alignment write failed under database contention (v0.38.0): the hook fails closed — no injection without its
context_usagealignment row. Transient; the next turn recovers.
Fix: Check
clawmem statusfor doc counts andclawmem embedfor embedding coverage. Verify the embedding server is reachable if using a remote GPU. TryCLAWMEM_PROFILE=deep, which widens recall with budget-aware query expansion + reranking. To see why a specific prompt surfaced nothing, setCLAWMEM_SURFACING_TRACE=1and read the newest row insurfacing_diagnostics— it records every retrieval leg, the fusion envelope, and the admission decision with its abstain reason.
Context-surfacing returns results on balanced but not speed
speedprofile disables vector search entirely, so documents that rank via the hybrid lanes (BM25 + vector agreement compounds fused mass) may not survive membership or admission on BM25 alone.Not a bug — this is the intended tradeoff. Use
balancedordeepfor richer retrieval.
Semantic matches vanished after an upgrade — surfacing looks keyword-only (v0.38.0)
Cause: the hook and the watcher run different ClawMem builds. The v0.38.0 vector wire refuses mixed versions in both directions. A v0.38 hook classifies an older watcher's answers
skewand prints once per process[clawmem] vector daemon on <socket> does not implement deadline-rel-v1 (a watcher on an older build) — vector legs degrade to FTS until 'clawmem watch' is restarted on this build. A v0.38 watcher refuses an older hook's absolute-deadline request asversion_skew, and that older hook falls back to FTS silently. Since v0.38.1 the watcher logs the first such refusal, once per run:[vec-daemon] refused a request from a pre-v0.38 client on <socket> (absolute deadlineMs → version_skew) — …. A v0.38.0 watcher logs nothing, so on that build this direction leaves no trace on either side. Surfacing keeps working either way; only the vector legs are lost.A common way to get here: the hook command in
~/.claude/settings.jsonand the watcher's service unit (itsExecStart, including any drop-in override) point at different installs, so upgrading one leaves the other behind.Which side is behind: a
version_skewline in the watcher's log (journalctl --user -u clawmem-watcher.service | grep version_skew, v0.38.1+) means the hook runs the older build; the hook'sdoes not implement deadline-rel-v1warning means the watcher does.Fix: run the hook and
clawmem watchfrom the same install, then restart the watcher (systemctl --user restart clawmem-watcher.service). Verify withclawmem vec-daemon-healthfrom that install: exit 0 meanslive, advertising bothhydrated-v1anddeadline-rel-v1;live-raworlive-legacymeans the watcher still runs an older build.
Recall attribution or injected-paths fill-in missing (recall_events empty for recent turns)
Since v0.38.0 injection bookkeeping is applied off-process: the hook parks a job, hands it to a detached
clawmem spool-ingestchild, and the child persists it under<db dir>/surfacing-spool/(next toindex.sqlite) then drains it into SQLite. The turn-alignmentcontext_usagerow is written in-hook and is never affected.Bookkeeping is best-effort by design: if the handoff loses its 250ms flush race (pathological pipe) or the hook's deadline passed before packaging, that turn's learning data is dropped — alignment, prior-turn lookback, and the injection itself are unaffected.
Check for stuck jobs:
ls ~/.cache/clawmem/surfacing-spool/. Plain.jsonfiles are unapplied jobs;.json.claim-<pid>files are claims (a dead drainer's claim is reclaimed automatically on the next drain). Runclawmem spool-drainto apply anything pending; jobs older than 24h are discarded as poison.A persistently growing set of retained files means a unit keeps failing (e.g. a secondary-vault DB is unwritable) — run
clawmem spool-drainin a terminal and read its stderr summary (applied= discarded= retained=).
Duplicate observations after every session
Since v0.41.0
decision-extractorkeeps a cursor per transcript, so a turn is extracted once; an item is dropped as a duplicate only when the same session emits it again with identical content. The same decision stated in other words is a second item, by design — the usual source of near-duplicates.Two documents for one session: a second transcript of the same session id (OpenClaw's base and topic transcripts) has its own documents, with a
-<tk6>suffix. So does a session whose canonical path a pre-upgrade document already held.A turn extracted twice: a transcript that was replaced, truncated or rewritten starts a new generation at its current turn, so that turn can be read again (its identical items are still dropped).
SELECT hook, anchor_epoch, byte_offset FROM stop_cursors WHERE session_id = '<id>'shows each hook's cursor and generation.An older ClawMem cannot add such duplicates: the fence skips its writes under
_clawmem/decisions/,antipatterns/,handoffs/andobservations/.clawmem doctornames it when it tries.Through v0.40.3 every Stop re-extracted the last 200 transcript entries, and
saveMemory()'s 30-minute hash window and the cross-session merge policies were what held the repeats back.
[decision-extractor] contradiction: N invalidation(s) suppressed by shadow mode
Not an error. Contradiction invalidation ships unarmed (v0.28.0+): the hook eroded a document's confidence to the
0.2floor, which is the point at which it would setinvalidated_atand drop the document out of FTS and vector retrieval. It logged the intent and wrote nothing.The preceding
WOULD invalidate "<collection>/<path>"lines name each affected document, and name only documents the armed writer could actually remove — candidates are selected by pathname but onlycontent_type='observation'is invalidation-eligible, so the two populations differ substantially — on a reference vault, roughly 3x more candidates than eligible rows. Confidence erosion still applied — that half is live, bounded, and reversible.A companion line reports documents that reached the floor but are not eligible. Those are informational: erosion has bottomed out there and arming the flag would not touch them.
To act on it: read the named documents and decide whether removing them from retrieval would have been correct, then arm with
CLAWMEM_CONTRADICTION_INVALIDATE=true. Exposure depends on your vault — see contradiction invalidation for the measurement queries and the full procedure.Stderr visibility no longer gates calibration (v0.29.0): every judge evaluation writes durable
judge_runs/judge_eventsrows in the vault database, so hosts that discard hook stderr (OpenClaw surfaces it only on non-zero exits) calibrate from the audit rows instead — see the queries in contradiction invalidation.If the proposals are frequent and look wrong, that is a judge-precision signal (check
CLAWMEM_JUDGE_MODELand thejudge_runsrows for that model), not a logging problem. The docs' recommended default isclaude-haiku-4-5; upgrading the judge is a one-variable change.
A memory stopped appearing in search but is still in the vault
invalidated_at IS NULLis a hard predicate on the FTS join and both vector joins, so an invalidated document is absent fromsearch,vsearch,query, and context-surfacing with no query-time signal.get/multi_getby path still return it, which is the usual way this gets noticed.Diagnose:
sqlite3 ~/.cache/clawmem/index.sqlite "SELECT id, path, content_type, invalidated_at, invalidated_by FROM documents WHERE invalidated_at IS NOT NULL ORDER BY invalidated_at DESC;"On the
documentstable, contradiction invalidation is the only writer of this column, and only when armed viaCLAWMEM_CONTRADICTION_INVALIDATE=true(and only oncontent_type='observation'). Grepping the source turns up a secondinvalidated_atwriter inconsolidation.ts— that one targets a different table,consolidated_observations, whose superseded rows are filtered bystatus='inactive'rather than by the joins above. The two are unrelated; do not diagnose one from the other.Restore one document by numeric
id, which the audit query above returns:sqlite3 ~/.cache/clawmem/index.sqlite "UPDATE documents SET invalidated_at=NULL, invalidated_by=NULL WHERE id=<id>;". Do not match on the logged path — the hook logscollection/pathwhile the table stores the barepath, so aWHERE path=clause usually matches nothing, and a bare path can collide across collections. Retrieval resumes immediately; the body and its vectors were never touched, so no re-index or re-embed is needed.The restore deliberately leaves
confidencealone — the document returns at whatever erosion left it (usually0.2), retrievable but ranking low. Raise it separately if you judge the erosion itself was wrong:UPDATE documents SET confidence=0.8 WHERE id=<id>;.If contradiction invalidation is the cause and you want it off, remove
CLAWMEM_CONTRADICTION_INVALIDATEfrom wherever the hook's environment is configured (a shellunsetwill not affect a value set in your hook config or plugin host); a bulk restore scopedWHERE invalidated_at IS NOT NULL AND content_type='observation'covers exactly what that path can have written. Full procedure: contradiction invalidation.
A memory is gone from the vault entirely — not merely absent from search (pre-v0.30.0 only)
Check this first, because the entry above will mislead you: if the row was deleted rather than invalidated, the
invalidated_atquery returns nothing and there is no document to restore. Confirm which case you are in:sqlite3 ~/.cache/clawmem/index.sqlite "SELECT id, active, archived_at FROM documents WHERE path LIKE '%<filename>%';"— no row at all means deletion, not invalidation.Cause, on v0.29.0 and earlier: a configured
lifecycle.purge_after_dayspermanently deleted every archived document past that window. It fired from a non-dry-runlifecycle_sweep(MCP) and from thestaleness-checkSessionStart hook, and neither reported it — the MCP dry-run preview listed only what would be archived, and the hook discarded the count inside a catch. Ifpurge_after_dayswas null (the default), this never happened to you.Fixed in v0.30.0: ClawMem physically deletes no document row on any code path, and
purge_after_daysis inert. Retention is archival, reversed bylifecycle_restore. Upgrading stops any ongoing loss.Already-deleted rows are unrecoverable from the vault — the row, not just its retrieval flag, is gone. Recover from a backup of
index.sqliteif you keep one, or re-index the source files: for file-backed collections the markdown on disk was never touched, soclawmem update --embedre-indexes it. Only vault-native content with no file behind it (mined conversations, synthesized facts,_clawmemobservations) is genuinely lost.Verify your current exposure:
grep -A6 '^lifecycle:' ~/.config/clawmem/config.yaml. On v0.30.0+ a sweep that seespurge_after_daysset says so explicitly and deletes nothing.
OpenClaw
MCP stdio server "dies" after the first call — every later call fails with "Connection closed" / "transport closed" until the client reconnects (gateway hosts)
Symptom: the first
tools/callon aclawmem mcpstdio server succeeds; every subsequent call in the same session fails client-side withMCP error -32000: Connection closedorbundle-mcp server "clawmem" is disconnected: mcp transport closed. Reported as yoloshii/ClawMem#22.What it is not: a one-shot server.
clawmem mcpis a long-lived stdio process (StdioServerTransportfrom the official MCP SDK) that exits only on stdin EOF or SIGINT/SIGTERM. Measured on v0.29.0 and v0.33.0 under scripted stdio sessions: multi-call sequences, calls returning real results and performing writes (memory_pin), 90s and 150s idle gaps between calls, and hostile input (garbage lines, truncated JSON, JSON-RPC batch arrays, repeatedinitialize, 1 MB requests). The process survives all of it and exits 0 only when the client closes stdin. The same sequences pass when the server is spawned exactly the way OpenClaw spawns it: through the/bin/shshim that setsoom_score_adj=1000before exec, detached, with the SDK's minimal inherited env, launchingbin/clawmem. The child ran atoom_score_adj=1000throughout those runs.What actually happened: the host killed the server process. Gateway clients (OpenClaw's
bundle-mcpsession layer) mark the session disconnected when the child process exits and surface the error above on every later call rather than respawning inside the live session, which makes a killed server look one-shot from the agent's side.Discriminate the killer from the gateway's stderr/journal:
[mcp] Received SIGTERM, shutting down...present: the host's own lifecycle tore the server down (OpenClaw's process teardown sends SIGTERM first). Investigate the gateway's session/catalog lifecycle, not ClawMem.Silence with the process gone: a SIGKILL-class death, most commonly the kernel OOM killer. OpenClaw spawns MCP servers with
oom_score_adj=1000, the maximum OOM preference, so they are the kernel's first victim under any memory pressure (openclaw/openclaw@cc9dcd3d69e, April 2026, present in current releases; the wrap protects the gateway by sacrificing child processes). Verify:cat /proc/$(pgrep -f "clawmem.ts mcp" | head -1)/oom_score_adjprints1000, anddmesg -T | grep -iE "oom|killed process"shows the kill. Mitigation: setOPENCLAW_CHILD_OOM_SCORE_ADJ=0in the gateway's environment (OpenClaw's own opt-out) and/or add memory headroom.A stack trace on stderr: a genuine server crash. Capture it and file it at yoloshii/ClawMem with the trace. This is the one case that is a ClawMem bug.
Note: the npm package's
clawmembin always execs bun (engines: bun >=1.0.0); Node is never the server runtime, so the host's Node version is not a variable here. When reporting, includebun --versionand the OpenClaw version.
clawmem setup openclaw installs into the wrong profile / ignores OPENCLAW_STATE_DIR (ClawMem v0.10.0–v0.10.3)
Symptom: running
OPENCLAW_STATE_DIR=~/.openclaw-dev clawmem setup openclaw(or running ClawMem setup while OpenClaw is configured for a non-default profile via--profile/OPENCLAW_STATE_DIR) installs the plugin into~/.openclaw/extensions/clawmeminstead of the profile-specific extensions directory. The default profile picks the plugin up; the active profile does not see it.Root cause: ClawMem v0.10.0 through v0.10.3 hardcoded the install destination to
~/.openclaw/extensions/clawmemand never consultedOPENCLAW_STATE_DIRor the OpenClaw CLI's profile resolution. Yoloshii/ClawMem#11.Fix: upgrade ClawMem to v0.10.4 or later. v0.10.4 delegates to
openclaw plugins installwhen the OpenClaw CLI is onPATH(which respectsOPENCLAW_STATE_DIR,OPENCLAW_CONFIG_PATH, and the--profileflag) and falls back to a direct-copy install honoringOPENCLAW_STATE_DIRwhen the CLI is absent. See docs/guides/openclaw-plugin.md for the full env-var contract.
clawmem setup openclaw --help runs setup instead of printing help (ClawMem ≤ v0.10.3)
Symptom:
clawmem setup openclaw --helpperforms the install instead of printing usage. Reported as part of yoloshii/ClawMem#11.Fix: upgrade to v0.10.4. The argv handler now short-circuits on
--help/-hbefore any spawn or filesystem work and prints the full flag and env-var reference.
"plugin not found: clawmem" / gateway ready line omits clawmem (OpenClaw v2026.4.11+)
Most common root cause on current OpenClaw releases: a symlinked plugin directory created by the CLI-absent fallback path or by a pre-v0.10.0 ClawMem install. OpenClaw v2026.4.11 tightened its discovery path to
readdirSync({ withFileTypes: true })withdirent.isDirectory(), and symlinks to directories reportisDirectory() === falseon that API shape. A symlinked<extensions>/clawmemis silently skipped during discovery. Pre-ClawMem-v0.10.0 setup always produced a symlink, which worked on OpenClaw v2026.3.x but started failing silently when OpenClaw released v2026.4.11. Note: from v0.10.4, the delegated path's--linkmode uses OpenClaw'splugins.load.paths(a load-path entry, not a filesystem symlink) and is not affected by this discovery skip.Fix: upgrade ClawMem to v0.10.0 or later and re-run
clawmem setup openclaw. v0.10.0 changed the default to recursive copy (cpSync(..., { recursive: true, dereference: true })); v0.10.4 added profile-aware delegation that further sidesteps the issue whenopenclawis onPATH. The result on disk is a real directory, not a link.Second cause: missing
package.json. OpenClaw v2026.4.11+ readspackage.jsonfor theopenclaw.extensions: ["./index.ts"]field as part of discovery.openclaw.plugin.jsonalone is not enough. v0.10.0 shipssrc/openclaw/package.jsonwith the required manifest, and setup refuses to install if it is missing. If you are on v0.10.0 and the file is there (verify withls ~/.openclaw/extensions/clawmem/package.json) but discovery still fails, see the next two entries.External report: yoloshii/ClawMem#5 — fresh install of OpenClaw v2026.4.11 reproduced this symptom on a machine that did not share any state with the ClawMem development environment. Resolved in ClawMem v0.10.0.
"blocked plugin candidate: suspicious ownership" (multi-user installs)
Gateway journal shows a line like
[plugins] clawmem: blocked plugin candidate: suspicious ownership (/home/<user>/.openclaw/extensions/clawmem, uid=1001, expected uid=997 or root). OpenClaw v2026.4.11+ enforces that plugin directories be owned by the current runtime user or root. This is a security feature that prevents a privileged gateway process from loading code that a less-privileged user dropped into its extensions directory.Common trigger: the gateway runs as a dedicated system user (e.g.
openclaw) that is different from the user who ranclawmem setup openclaw(e.g. your admin account). Setup copies the plugin as the installer user, so the new directory is owned by the installer and rejected by the gateway.Fix: after running setup, chown the plugin directory to the gateway user or root.
sudo chown -R <gateway-user>:<gateway-group> ~/.openclaw/extensions/clawmem. Then restart the gateway.sudo systemctl restart openclaw-gateway.service(or whatever your gateway unit is called).Single-user installs where you ARE the gateway user are not affected — your own user owns the plugin copy and the ownership check passes automatically.
The inverse situation also happens: if you later run
openclaw plugins inspect clawmemfrom a different shell user than the gateway, the CLI's own ownership check may reject the plugin (expected uid=<your uid> or root) even though the gateway is loading it fine at runtime. Trust the gateway journal over the CLI inspect output when they disagree — the journal is the authoritative runtime state.
Gateway fails to start with "Missing config. Run openclaw setup or set gateway.mode=local"
On system-service OpenClaw deployments where the gateway runs as a different user than the owner of
~/<gateway-user's-home>/.openclaw/, the gateway cannot traverse into its own config directory if the directory is 700 (drwx------). The error is misleading — the config file itself is readable (correctly chowned by the systemdExecStartPrestep), but the parent directory has no group-execute bit, so the gateway user cannot evencdinto it to open the file.Verify:
sudo stat /home/<installer>/.openclaw | grep Access— if it shows(0700/drwx------), this is the cause.Fix:
sudo chmod 750 /home/<installer>/.openclaw(owner rwx, group rx). The gateway user must be a member of the owning group — check withid <gateway-user>and confirm<installer-group>is listed. On Debian-family systems with anappuser:appuser-owned home directory and anopenclaw:openclawgateway that is also in theappusergroup,chmod 750is enough.Single-user installs are not affected — the gateway IS the home directory owner and has full access regardless of group perms.
"plugins.entries.clawmem: plugin not found (stale config entry ignored)"
OpenClaw saw a
plugins.entries.clawmem: { enabled: true }entry in its config but could not find a corresponding plugin directory under~/.openclaw/extensions/. This typically means the plugin directory was deleted or moved without runningopenclaw config unset plugins.entries.clawmem.Fix: re-run
clawmem setup openclawto restore the plugin directory, then the stale entry resolves. Or, if you intentionally uninstalled the plugin and want to keep it gone,openclaw config unset plugins.entries.clawmem+openclaw config unset plugins.slots.memory(which restores the defaultmemory-core).
"memory plugin not selected for the memory slot; skipping its indexing runtime and recall registration" (OpenClaw main from September 2026, #131779)
Symptom: the gateway ready line lists
clawmem,openclaw plugins inspect clawmemshowsStatus: enabled, hooks fire and the agent tools answer, but the startup journal carries the warning above. ClawMem loaded without its memory-capability runtime because another plugin ownsplugins.slots.memory, or the slot was cleared.What changed: on earlier OpenClaw releases an unselected
kind: memoryplugin was disabled outright and dropped from the ready line. From #131779 it stays loaded with its hooks and tools, and OpenClaw strips only the memory runtime. The failure moved from loud to quiet.Verify:
openclaw config get plugins.slots.memory. It must printclawmem. Anything else, or nothing, is the cause.Fix:
openclaw plugins enable clawmemre-applies slot selection and disables the competing memory plugin. Or set it directly:openclaw config set plugins.slots.memory clawmem. Restart the gateway and confirm the warning is gone.ClawMem's memory runtime is currently a stub (
getMemorySearchManagerreturns no manager; retrieval runs throughbefore_prompt_build), so you lose little today. Fix it anyway. The slot is the contract OpenClaw uses to decide which plugin owns memory, and a later ClawMem release may put real work behind that runtime.
Older OpenClaw version notes
v2026.4.10: fixed a config normalization bug where
plugins.slots.contextEnginewas silently dropped during config processing (openclaw/openclaw#64192). Only relevant on ClawMem < v0.10.0, which used thecontextEngineslot. ClawMem v0.10.0+ uses thememoryslot and is not affected by #64192.v2026.4.11: introduced the new plugin discovery contract (
readdirSync({ withFileTypes: true })+dirent.isDirectory()) and the plugin ownership check described above. Required for ClawMem v0.10.0+. Upgrade OpenClaw withsudo npm i -g openclaw@latest.
REST API tools return no results
The
clawmem serveprocess may not be running. The plugin auto-starts it, but it doesn't survive plugin crashes.Fix: Check with
curl http://localhost:7438/health. If unreachable, either restart OpenClaw or runclawmem serveas a systemd service for persistence.
Agent tools silently fail but hooks still work
Hooks use shell-out transport (independent of REST). Agent tools use REST. If the REST server is down, tools fail but hooks continue.
Fix: Verify REST server:
curl http://localhost:7438/health. Start it manually (./bin/clawmem serve) or via systemd.
Plugin registers but hooks don't fire
Verify ClawMem owns the memory slot:
openclaw config get plugins.slots.memorymust printclawmem. ClawMem v0.10.0+ uses thememoryslot, not the oldercontextEngineslot.On OpenClaw v2026.4.23 or newer, verify the conversation grant:
openclaw config get plugins.entries.clawmem.hooks.allowConversationAccessmust printtrue, or the gateway logstyped hook "before_prompt_build" blocked because non-bundled plugins must set plugins.entries.clawmem.hooks.allowConversationAccess=trueand neither injection nor extraction runs. On v2026.5.2 or newer,plugin must declare contracts.toolsin the journal means the installed manifest predates the tool contract; re-runclawmem setup openclaw.If using hybrid mode, OpenClaw's native memory may be intercepting.
hook context-surfacing failed: timeout after Nms (hook=context-surfacing, profile=..., hookBudgetMs=...) on every prompt
The plugin kills the hook
hookBudgetMs + 2000ms after start and registers it with OpenClaw 2 s later than that. If the message repeats on every prompt, either the hook cannot finish inside its budget or an operator hook-timeout policy is lower than the plugin's registration value (plugins.entries.clawmem.hooks.timeouts.before_prompt_buildorplugins.entries.clawmem.hooks.timeoutMswin over it).Fix: run
clawmem setup openclawagain, which reports a policy below the derived timeout with the exactopenclaw config setto run, or lowerplugins.entries.clawmem.config.hookBudgetMs. Atprofile: deepwith nogpuRerankorgpuLlmendpoint, ClawMem v0.37 and older loaded models in-process on every prompt and blew the budget; v0.38 degrades those legs inside it. Set the endpoints or usebalancedon older versions.
OpenClaw agent doesn't use ClawMem tools
The 5 agent tools (search, get, session_log, timeline, similar) require the REST API. Verify it's running and accessible from the OpenClaw process.
Check plugin config:
enableToolsmust betrueandservePortmust match the running server port (default 7438).
Indexing
clawmem update crashes with "Binding expected string, TypedArray, boolean, number, bigint or null"
YAML frontmatter values are auto-coerced by
gray-matter(viajs-yaml):title: 2023-09-27becomes a JSDateobject,title: truebecomes a boolean,title: nullstays null. Bun's SQLite driver rejectsDateobjects as bind parameters, crashing the indexer.Affects any field parsed from frontmatter:
title,domain,workstream,content_type,review_by.Common in Obsidian vaults where bare dates or booleans appear in YAML.
Fixed in v0.4.2:
parseDocument()runtime-checks all frontmatter string fields. Defense-in-depth guards ininsertDocument(),updateDocument(), andreactivateDocument().If on an older version: quote YAML values as strings (
title: "2023-09-27") as a workaround.
A file is indexed as plain text — no title, no tags — although it has frontmatter (v0.43.6 or later)
Only
yaml/yml(any case) andjsonfrontmatter is read. A first line of---js,---javascript,---tomlor---coffeemakes the whole file the body: before v0.43.6 thejsspellings RAN the block as code in the indexing process; now none of them is read as frontmatter.YAML that defines an anchor (
&name, so also every*alias), uses!!omap, nests deeper than 32 levels, has more than 4,096 nodes, or whose block exceeds 64 KiB or 1,024 lines (any line ending) is read as plain text. A<<merge key no longer merges: it is an ordinary key named<<.tagskeeps string, number and boolean entries only, each up to 256 characters, at most 64; a nested list or object entry is dropped.Fix the file (plain YAML, no anchors, under the caps) and save it; the watcher re-indexes it, or run
clawmem update.
clawmem doctor prints ✗ Frontmatter guard: self-test FAILED
The bounded YAML engine checks at its first parse that the installed YAML parser reports every node, in order, with its depth, and exposes anchors. A parser that does not would drop the limits silently, so the guard fails closed: every YAML frontmatter block reads as plain text, and one line went to stderr at that first parse (Hermes discards it; the doctor line is the signal there).
Cause: a dependency not at the pinned version (
gray-matter4.0.3,js-yaml3.14.x). Fix:bun install --frozen-lockfilein the ClawMem checkout, restart the long-lived processes, runclawmem doctoragain.
General
"Unknown vault" error
The vault name isn't configured in
config.yamlorCLAWMEM_VAULTS.Fix: Add the vault to
~/.config/clawmem/config.yamlor setCLAWMEM_VAULTSenv var.
Editing collections fails with "Cannot edit … in place"
Since v0.39.1, ClawMem reads back the text an edit is about to write to
config.yamland stops if anything outside the edited entry would change, or the edit would not come out as asked. The file is left untouched; the message names anything else the edit would have changed.The usual cause is a YAML merge key (
<<:), anchor or alias the edit cannot keep, such as a collection that exists only through a merge key.Fix: edit
~/.config/clawmem/config.yamlby hand (write a merged collection out as a plain entry), then runclawmem update.
Comments in config.yaml disappeared after clawmem collection add or remove
Before v0.39.1 every write re-serialised the whole file and dropped its comments and blank lines, with exit 0 and no warning.
Fix: upgrade to v0.39.1 or later, then restore the comments from a backup or version control. Later edits keep them.
Vault path with ~ doesn't resolve
Fixed in current version. Vault paths now support
~expansion.If using an older version, use absolute paths.
High memory usage in long-running MCP process
Named vault stores are cached in memory. Each vault holds one SQLite connection.
All stores are closed on SIGINT/SIGTERM. This is normal behavior, not a leak.
414 files · 399 not served here
- .env.example (not served here)
- .github/ISSUE_TEMPLATE/bug-report.yml (not served here)
- .github/ISSUE_TEMPLATE/config.yml (not served here)
- .github/ISSUE_TEMPLATE/feature-request.yml (not served here)
- .github/PULL_REQUEST_TEMPLATE.md (not served here)
- .github/social-preview.jpg (not served here)
- .gitignore (not served here)
- AGENTS.md
- ATTRIBUTION.md
- AUTOGINEER-RUNS.md
- CLAUDE.md
- CODE_OF_CONDUCT.md
- CONTRIBUTING.md
- LICENSE
- README.md
- RELEASE_NOTES.md
- SECURITY.md
- SKILL.md
- agents/clawmem-curator.md (not served here)
- bin/clawmem (not served here)
- bun.lock (not served here)
- bunfig.toml (not served here)
- docs/clawmem-architecture.excalidraw (not served here)
- docs/clawmem-architecture.png (not served here)
- docs/clawmem_hero.jpg (not served here)
- docs/concepts/architecture.md (not served here)
- docs/concepts/composite-scoring.md (not served here)
- docs/concepts/hooks-vs-mcp.md (not served here)
- docs/concepts/multi-vault.md (not served here)
- docs/contributing.md
- docs/guides/cloud-embedding.md (not served here)
- docs/guides/contradiction-invalidation.md (not served here)
- docs/guides/eval-harness.md (not served here)
- docs/guides/hermes-plugin.md (not served here)
- docs/guides/inference-services.md (not served here)
- docs/guides/multi-vault-config.md (not served here)
- docs/guides/openclaw-plugin.md (not served here)
- docs/guides/setup-hooks.md (not served here)
- docs/guides/setup-mcp.md (not served here)
- docs/guides/systemd-services.md (not served here)
- docs/guides/upgrading.md (not served here)
- docs/internals/entity-resolution.md (not served here)
- docs/internals/graph-traversal.md (not served here)
- docs/internals/intent-search-pipeline.md (not served here)
- docs/internals/query-pipeline.md (not served here)
- docs/introduction.md
- docs/quickstart.md
- docs/reference/cli.md (not served here)
- docs/reference/configuration.md (not served here)
- docs/reference/mcp-tools.md (not served here)
- docs/reference/rest-api.md (not served here)
- docs/troubleshooting.md
- eval-bundles/judge-override-2026-08-01/artifacts/haiku-claude-cli-run1.json (not served here)
- eval-bundles/judge-override-2026-08-01/artifacts/haiku-claude-cli-run2.json (not served here)
- eval-bundles/judge-override-2026-08-01/artifacts/sonnet5-claude-cli-run1.json (not served here)
- eval-bundles/judge-override-2026-08-01/tooling/capability-eval.ts (not served here)
- extras/rerankers/zerank-2-seq/.gitignore (not served here)
- extras/rerankers/zerank-2-seq/Dockerfile (not served here)
- extras/rerankers/zerank-2-seq/README.md (not served here)
- extras/rerankers/zerank-2-seq/build_and_verify.py (not served here)
- extras/rerankers/zerank-2-seq/docker-compose.yml (not served here)
- extras/rerankers/zerank-2-seq/server.py (not served here)
- extras/rerankers/zerank-2-seq/zr_common.py (not served here)
- googledd6f95190aef61f7.html (not served here)
- o1-clock-debt.json (not served here)
- o1-seam-debt.json (not served here)
- package.json (not served here)
- scripts/eval-acceptance.ts (not served here)
- scripts/eval-bundle-migrate-copy.ts (not served here)
- scripts/eval-bypass-ab.ts (not served here)
- scripts/eval-composite-ablation.ts (not served here)
- scripts/eval-hook-capture.ts (not served here)
- scripts/eval-hook-stamp-baseline.ts (not served here)
- scripts/eval-keyword-acceptance.ts (not served here)
- scripts/eval-query-template.ts (not served here)
- scripts/experiment-clock.sh (not served here)
- scripts/o1-clock-audit.ts (not served here)
- scripts/o1-seam-audit.ts (not served here)
- scripts/o1-tsconfig.ts (not served here)
- scripts/proximity.ts (not served here)
- scripts/test-enhanced.ts (not served here)
- src/amem.ts (not served here)
- src/beads.ts (not served here)
- src/busy-retry.ts (not served here)
- src/canary.ts (not served here)
- src/causal-reader.ts (not served here)
- src/causal-retrieval.ts (not served here)
- src/causal-writer.ts (not served here)
- src/clawmem.ts (not served here)
- src/clock.ts (not served here)
- src/collections.ts (not served here)
- src/compaction-state.ts (not served here)
- src/config.ts (not served here)
- src/consolidation.ts (not served here)
- src/conversation-synthesis.ts (not served here)
- src/deductive-guardrails.ts (not served here)
- src/directory-context.ts (not served here)
- src/embed-readiness.ts (not served here)
- src/entity-repair.ts (not served here)
- src/entity.ts (not served here)
- src/errors.ts (not served here)
- src/eval/gold.ts (not served here)
- src/eval/hook-gold.ts (not served here)
- src/eval/hook-invariants.ts (not served here)
- src/eval/hook-metrics.ts (not served here)
- src/eval/hook-run.ts (not served here)
- src/eval/hook-trace.ts (not served here)
- src/eval/metrics.ts (not served here)
- src/eval/pair-audit.ts (not served here)
- src/eval/replay.ts (not served here)
- src/eval/replicated.ts (not served here)
- src/eval/report.ts (not served here)
- src/eval/run-identity.ts (not served here)
- src/eval/run.ts (not served here)
- src/eval/types.ts (not served here)
- src/eval/vec-daemon-child.ts (not served here)
- src/formatter.ts (not served here)
- src/graph-traversal.ts (not served here)
- src/health/rerank-golden.json (not served here)
- src/health/rerank-health.ts (not served here)
- src/hermes/__init__.py (not served here)
- src/hermes/plugin.yaml (not served here)
- src/hook-settings.ts (not served here)
- src/hooks.ts (not served here)
- src/hooks/context-surfacing.ts (not served here)
- src/hooks/curator-nudge.ts (not served here)
- src/hooks/decision-extractor.ts (not served here)
- src/hooks/feedback-loop.ts (not served here)
- src/hooks/gate-tokens.ts (not served here)
- src/hooks/handoff-generator.ts (not served here)
- src/hooks/postcompact-inject.ts (not served here)
- src/hooks/precompact-extract.ts (not served here)
- src/hooks/pretool-inject.ts (not served here)
- src/hooks/session-bootstrap.ts (not served here)
- src/hooks/staleness-check.ts (not served here)
- src/hooks/surfacing-bookkeeping.ts (not served here)
- src/hooks/surfacing-fusion.ts (not served here)
- src/indexer.ts (not served here)
- src/intent.ts (not served here)
- src/js-yaml.d.ts (not served here)
- src/judge-audit.ts (not served here)
- src/judge.ts (not served here)
- src/limits.ts (not served here)
- src/llm-retry.ts (not served here)
- src/llm.ts (not served here)
- src/maintenance.ts (not served here)
- src/mcp.ts (not served here)
- src/memory.ts (not served here)
- src/merge-guards.ts (not served here)
- src/mmr.ts (not served here)
- src/normalize.ts (not served here)
- src/observer-reply.ts (not served here)
- src/observer.ts (not served here)
- src/openclaw-paths.ts (not served here)
- src/openclaw/compaction-threshold.ts (not served here)
- src/openclaw/engine.ts (not served here)
- src/openclaw/index.ts (not served here)
- src/openclaw/openclaw.plugin.json (not served here)
- src/openclaw/package.json (not served here)
- src/openclaw/prompt-clean.ts (not served here)
- src/openclaw/session-state.ts (not served here)
- src/openclaw/shell.ts (not served here)
- src/openclaw/tools.ts (not served here)
- src/openclaw/transcript-resolver.ts (not served here)
- src/profile.ts (not served here)
- src/promptguard.ts (not served here)
- src/recall-attribution.ts (not served here)
- src/recall-buffer.ts (not served here)
- src/relation-weight.ts (not served here)
- src/retrieval-gate.ts (not served here)
- src/schema-placeholder.ts (not served here)
- src/scoring-regime.ts (not served here)
- src/search-utils.ts (not served here)
- src/server-guard.ts (not served here)
- src/server.ts (not served here)
- src/session-focus.ts (not served here)
- src/splitter.ts (not served here)
- src/stop-causal.ts (not served here)
- src/stop-checkpoint.ts (not served here)
- src/stop-cursor.ts (not served here)
- src/stop-due.ts (not served here)
- src/stop-extract.ts (not served here)
- src/stop-feedback.ts (not served here)
- src/stop-handoff.ts (not served here)
- src/stop-health.ts (not served here)
- src/stop-hermes-scan.ts (not served here)
- src/stop-identity.ts (not served here)
- src/stop-judge.ts (not served here)
- src/stop-pairing.ts (not served here)
- src/stop-recover.ts (not served here)
- src/stop-repair.ts (not served here)
- src/stop-schema.ts (not served here)
- src/stop-session-docs.ts (not served here)
- src/stop-worker.ts (not served here)
- src/store.ts (not served here)
- src/text-similarity.ts (not served here)
- src/validation.ts (not served here)
- src/vault-facts.ts (not served here)
- src/vector-daemon.ts (not served here)
- src/vector-protocol.ts (not served here)
- src/watcher.ts (not served here)
- src/worker-lease.ts (not served here)
- tests/e2e/consolidate.test.ts (not served here)
- tests/e2e/index-search-score.test.ts (not served here)
- tests/e2e/mine-and-diary.test.ts (not served here)
- tests/e2e/reflect.test.ts (not served here)
- tests/helpers/alignment-driver.ts (not served here)
- tests/helpers/budget-guard-driver.ts (not served here)
- tests/helpers/concurrent-init-worker.ts (not served here)
- tests/helpers/degeneracy-gate-driver.ts (not served here)
- tests/helpers/embed-readiness-fixture.ts (not served here)
- tests/helpers/fake-budget-llm.ts (not served here)
- tests/helpers/fixtures.ts (not served here)
- tests/helpers/mock-llm.ts (not served here)
- tests/helpers/test-store.ts (not served here)
- tests/helpers/w0-guard-driver.ts (not served here)
- tests/hooks/context-surfacing.test.ts (not served here)
- tests/hooks/decision-extractor.test.ts (not served here)
- tests/hooks/doctor-llm-probe.integration.test.ts (not served here)
- tests/hooks/eval-vector-daemon.integration.test.ts (not served here)
- tests/hooks/hook-alignment.integration.test.ts (not served here)
- tests/hooks/hook-lanes.integration.test.ts (not served here)
- tests/hooks/hook-replay.integration.test.ts (not served here)
- tests/hooks/hydrated-projection.integration.test.ts (not served here)
- tests/hooks/o1-vector-leg-terminal.integration.test.ts (not served here)
- tests/hooks/o1-wall-jump.helpers.ts (not served here)
- tests/hooks/o1-wall-jump.integration.test.ts (not served here)
- tests/hooks/session-bootstrap.test.ts (not served here)
- tests/integration/cmdwatch-atomic-save.integration.test.ts (not served here)
- tests/integration/cmdwatch-new-dirs.integration.test.ts (not served here)
- tests/integration/cmdwatch-precheck.integration.test.ts (not served here)
- tests/integration/cmdwatch-workers.integration.test.ts (not served here)
- tests/integration/consolidation-contradictions.integration.test.ts (not served here)
- tests/integration/consolidation-name-guard.integration.test.ts (not served here)
- tests/integration/context-surfacing-multiturn.integration.test.ts (not served here)
- tests/integration/context-surfacing-topic-boost.integration.test.ts (not served here)
- tests/integration/conversation-synthesis-two-pass.integration.test.ts (not served here)
- tests/integration/deductive-guardrails.integration.test.ts (not served here)
- tests/integration/hook-blocking-write.integration.test.ts (not served here)
- tests/integration/intent-db.test.ts (not served here)
- tests/integration/judge-consolidation.integration.test.ts (not served here)
- tests/integration/maintenance-lane.integration.test.ts (not served here)
- tests/integration/rerank-live-model.integration.test.ts (not served here)
- tests/integration/secondary-vault-gate.integration.test.ts (not served here)
- tests/integration/setup-openclaw.integration.test.ts (not served here)
- tests/integration/store-concurrent-init.test.ts (not served here)
- tests/integration/store-search.test.ts (not served here)
- tests/integration/store-session.test.ts (not served here)
- tests/integration/store.test.ts (not served here)
- tests/preload.ts (not served here)
- tests/security/rest-transport.test.ts (not served here)
- tests/security/server-guard.test.ts (not served here)
- tests/smoke.test.ts (not served here)
- tests/unit/amem.test.ts (not served here)
- tests/unit/authored-at-cli.test.ts (not served here)
- tests/unit/authored-at.test.ts (not served here)
- tests/unit/basis-stratum.test.ts (not served here)
- tests/unit/canary-validation.test.ts (not served here)
- tests/unit/causal-boundary.test.ts (not served here)
- tests/unit/causal-migrate.test.ts (not served here)
- tests/unit/causal-reader.test.ts (not served here)
- tests/unit/causal-writer.test.ts (not served here)
- tests/unit/clock-type-negatives.ts (not served here)
- tests/unit/clock-types.test.ts (not served here)
- tests/unit/clock.test.ts (not served here)
- tests/unit/collections-config-comments.test.ts (not served here)
- tests/unit/compaction-cli.test.ts (not served here)
- tests/unit/compaction-doctor.test.ts (not served here)
- tests/unit/compaction-embed.test.ts (not served here)
- tests/unit/compaction-enrichment.test.ts (not served here)
- tests/unit/compaction-fixtures.ts (not served here)
- tests/unit/compaction-leak.test.ts (not served here)
- tests/unit/compaction-mcp.test.ts (not served here)
- tests/unit/compaction-openclaw.test.ts (not served here)
- tests/unit/compaction-setup-hooks.test.ts (not served here)
- tests/unit/compaction-transcript.test.ts (not served here)
- tests/unit/composite-scoring-seam.test.ts (not served here)
- tests/unit/config.test.ts (not served here)
- tests/unit/consolidation-fit-v0414.test.ts (not served here)
- tests/unit/consolidation-lease.test.ts (not served here)
- tests/unit/context-surfacing-6a.test.ts (not served here)
- tests/unit/context-surfacing-6b.test.ts (not served here)
- tests/unit/contradict-taxonomy.test.ts (not served here)
- tests/unit/conversation-synthesis.test.ts (not served here)
- tests/unit/decompose-query.test.ts (not served here)
- tests/unit/deductive-and-embed-state.test.ts (not served here)
- tests/unit/deductive-guardrails.test.ts (not served here)
- tests/unit/doctor-hook-budget.test.ts (not served here)
- tests/unit/doctor-observer-v0412.test.ts (not served here)
- tests/unit/doctor-observer-v0414.test.ts (not served here)
- tests/unit/embed-cooldown-cli.test.ts (not served here)
- tests/unit/embed-cooldown-probe.test.ts (not served here)
- tests/unit/embed-dimension-safety.test.ts (not served here)
- tests/unit/embed-taint-v0412.test.ts (not served here)
- tests/unit/entity-repair-cli.test.ts (not served here)
- tests/unit/entity-repair.test.ts (not served here)
- tests/unit/entity.test.ts (not served here)
- tests/unit/errors.contract.test.ts (not served here)
- tests/unit/errors.test.ts (not served here)
- tests/unit/eval-cli-pair-flags.test.ts (not served here)
- tests/unit/eval-harness.test.ts (not served here)
- tests/unit/experiment-clock.test.ts (not served here)
- tests/unit/frontmatter-engines.test.ts (not served here)
- tests/unit/fts-bypass-knob.test.ts (not served here)
- tests/unit/fts-score.test.ts (not served here)
- tests/unit/hermes-plugin.test.ts (not served here)
- tests/unit/hook-budget-config.test.ts (not served here)
- tests/unit/hook-contract-guards.test.ts (not served here)
- tests/unit/hook-eval-acceptance.test.ts (not served here)
- tests/unit/hook-eval-gold.test.ts (not served here)
- tests/unit/hook-eval-invariants.test.ts (not served here)
- tests/unit/hook-eval-metrics.test.ts (not served here)
- tests/unit/hook-eval-vault-boundary.test.ts (not served here)
- tests/unit/hook-timeout-fix.test.ts (not served here)
- tests/unit/hooks-io.test.ts (not served here)
- tests/unit/indexer-boundary.test.ts (not served here)
- tests/unit/indexer-write-lock.test.ts (not served here)
- tests/unit/indexer.test.ts (not served here)
- tests/unit/intent.test.ts (not served here)
- tests/unit/invalidation.test.ts (not served here)
- tests/unit/judge-audit.test.ts (not served here)
- tests/unit/judge-seam.test.ts (not served here)
- tests/unit/judge.test.ts (not served here)
- tests/unit/kg-query.test.ts (not served here)
- tests/unit/llm-budget-v0412.test.ts (not served here)
- tests/unit/llm-budget-v0414.test.ts (not served here)
- tests/unit/llm-endpoint-probe.test.ts (not served here)
- tests/unit/llm-fallback.test.ts (not served here)
- tests/unit/llm-interface-contract.test.ts (not served here)
- tests/unit/llm-remote-config.test.ts (not served here)
- tests/unit/llm-retry.test.ts (not served here)
- tests/unit/maintenance.test.ts (not served here)
- tests/unit/mcp-routes.test.ts (not served here)
- tests/unit/memory-rank-breakdown.test.ts (not served here)
- tests/unit/memory-stats-rank-tools.test.ts (not served here)
- tests/unit/memory.scoring.test.ts (not served here)
- tests/unit/memory.test.ts (not served here)
- tests/unit/merge-guards.test.ts (not served here)
- tests/unit/mixed-channel.test.ts (not served here)
- tests/unit/mmr.test.ts (not served here)
- tests/unit/mpfp.test.ts (not served here)
- tests/unit/no-hard-delete-tripwire.test.ts (not served here)
- tests/unit/no-hard-delete.test.ts (not served here)
- tests/unit/normalize.test.ts (not served here)
- tests/unit/nudge.test.ts (not served here)
- tests/unit/o1-clock-audit.test.ts (not served here)
- tests/unit/o1-seam-audit.test.ts (not served here)
- tests/unit/observer-budget-v0412.test.ts (not served here)
- tests/unit/observer-fit-69-13.test.ts (not served here)
- tests/unit/observer-format-v0414.test.ts (not served here)
- tests/unit/observer.test.ts (not served here)
- tests/unit/observer.xml-parse.test.ts (not served here)
- tests/unit/openclaw-handlers.test.ts (not served here)
- tests/unit/openclaw-hook-budget.test.ts (not served here)
- tests/unit/openclaw-paths.test.ts (not served here)
- tests/unit/openclaw-plugin.test.ts (not served here)
- tests/unit/openviking-enhancements.test.ts (not served here)
- tests/unit/origin-reconciliation.test.ts (not served here)
- tests/unit/pair-audit.test.ts (not served here)
- tests/unit/promptguard.test.ts (not served here)
- tests/unit/proximity.test.ts (not served here)
- tests/unit/recall-tracking.test.ts (not served here)
- tests/unit/replicated-aggregate.test.ts (not served here)
- tests/unit/rerank-health.test.ts (not served here)
- tests/unit/rerank-local-namespace.test.ts (not served here)
- tests/unit/rest-clients-token.test.ts (not served here)
- tests/unit/retrieval-gate.test.ts (not served here)
- tests/unit/review-t7-v0414.test.ts (not served here)
- tests/unit/schema-placeholder.test.ts (not served here)
- tests/unit/scoring-regime.test.ts (not served here)
- tests/unit/search-utils.blend.test.ts (not served here)
- tests/unit/search-utils.rrf.test.ts (not served here)
- tests/unit/search-utils.test.ts (not served here)
- tests/unit/server.test.ts (not served here)
- tests/unit/session-focus.test.ts (not served here)
- tests/unit/setup-hooks-timeout.test.ts (not served here)
- tests/unit/splitter.fragment-limits.test.ts (not served here)
- tests/unit/splitter.test.ts (not served here)
- tests/unit/spo-extraction.test.ts (not served here)
- tests/unit/spo-triples.test.ts (not served here)
- tests/unit/stop-causal.test.ts (not served here)
- tests/unit/stop-checkpoint-v0412.test.ts (not served here)
- tests/unit/stop-cursor.test.ts (not served here)
- tests/unit/stop-extract.test.ts (not served here)
- tests/unit/stop-feedback.test.ts (not served here)
- tests/unit/stop-fence.test.ts (not served here)
- tests/unit/stop-fixtures.ts (not served here)
- tests/unit/stop-handoff.test.ts (not served here)
- tests/unit/stop-hermes.test.ts (not served here)
- tests/unit/stop-hook-input.test.ts (not served here)
- tests/unit/stop-identity.test.ts (not served here)
- tests/unit/stop-judge.test.ts (not served here)
- tests/unit/stop-observer.test.ts (not served here)
- tests/unit/stop-relations.test.ts (not served here)
- tests/unit/stop-repair.test.ts (not served here)
- tests/unit/stop-replay.test.ts (not served here)
- tests/unit/stop-session-docs.test.ts (not served here)
- tests/unit/stop-t23.test.ts (not served here)
- tests/unit/stop-v0414.test.ts (not served here)
- tests/unit/stop-worker.test.ts (not served here)
- tests/unit/store.macos-sqlite.test.ts (not served here)
- tests/unit/surfacing-bookkeeping.test.ts (not served here)
- tests/unit/surfacing-fusion.test.ts (not served here)
- tests/unit/temporal-utc.test.ts (not served here)
- tests/unit/test-isolation.test.ts (not served here)
- tests/unit/text-similarity.test.ts (not served here)
- tests/unit/turn-starters.test.ts (not served here)
- tests/unit/validation.test.ts (not served here)
- tests/unit/vault-facts.test.ts (not served here)
- tests/unit/vec-exclusion.test.ts (not served here)
- tests/unit/vector-daemon.test.ts (not served here)
- tests/unit/watcher.test.ts (not served here)
- tests/unit/worker-lease.test.ts (not served here)
- tsconfig.json (not served here)
Advantages
- Operates entirely on-device with no API keys or cloud dependencies. evidence: README.md
- Provides seamless cross-runtime memory sharing for different agent types. evidence: README.md
Limitations
- Native Windows support is not recommended; WSL2 is required for full functionality. evidence: README.md
- Requires manual configuration and model management for optimal performance. evidence: README.md
Security
Risk level: Medium risk
This brain runs
Agent instructions that run or fetch something (26)
AGENTS.md:**Always run via `bin/clawmem`** — it sets the endpoints.AGENTS.md:| | `lifecycle_status` / `lifecycle_sweep` / `lifecycle_restore` | Lifecycle stats / archive stale (dry-run default, archives only — ClawMem never deletes rows) / restore.AGENTS.md:**v0.38.0:** the context-surfacing hook is no longer a composite ordering surface — its injected order and admission run on the channel-aware fusion key;AGENTS.md:Through v0.29.0 it permanently deleted archived rows from a non-dry-run sweep and from the SessionStart hook, unreported.AGENTS.md:Re-run `clawmem setup hooks` for the SessionEnd flush;AGENTS.md:Queues older than 24 h → `clawmem repair stop-queue --run`.AGENTS.md:`clawmem repair stop-queue --retry-now held --run` retries held ranges now;AGENTS.md:Run `clawmem embed`.AGENTS.md:Run `build_graphs`.AGENTS.md:**Index-run summary shows a `✎ notes` gap (or `[amem] LLM returned null` per doc)** → the LLM endpoint is dead, squatted by another service, or misconfigured.AGENTS.md:Run `clawmem doctor` — it POSTs a real completion to `CLAWMEM_LLM_URL` and validates the response shape.AGENTS.md:**v0.20.0** closes the residual with an opt-in vector-query daemon (run `clawmem watch`): it runs the blocking sqlite-vec scan off the hook's event loop, so a cold scan times out fast and falls back to FTS instead of blocking the turn — a true hard cap, not just a probability reduction;AGENTS.md:a cold hydrate can no longer run the leg past its deadline after the scan answered.AGENTS.md:❌ Run `status` routinely → ✅ only when retrieval feels broken or after large ingestion.AGENTS.md:Install: `clawmem setup curator`.AGENTS.md:Invoke: **"curate memory" / "run curator" / "memory maintenance"**.SKILL.md:| | `lifecycle_status` / `lifecycle_sweep` / `lifecycle_restore` | Lifecycle stats / archive stale (dry-run default, archives only — ClawMem never deletes rows) / restore auto-archived.SKILL.md:**v0.38.0:** the context-surfacing hook is no longer a composite ordering surface — its injected order and admission run on the channel-aware fusion key;SKILL.md:Through v0.29.0 it permanently deleted archived rows from a non-dry-run sweep and from the SessionStart hook, unreported.SKILL.md:Run `clawmem embed` or wait for the embed timer.SKILL.md:Run `build_graphs` (temporal backbone + semantic edges).SKILL.md:**Index-run summary shows a `✎ notes` gap (or `[amem] LLM returned null` per doc)** → the LLM endpoint is dead, squatted, or misconfigured — `clawmem doctor` shape-probes `CLAWMEM_LLM_URL` with a real completion (v0.37.0).SKILL.md:**v0.20.0** adds the hard cap (run `clawmem watch` — the vector daemon runs the blocking scan off the hook's event loop, so a cold scan falls back to FTS instead of blocking the turn);SKILL.md:Retry held ranges now with `clawmem repair stop-queue --retry-now held --run`;SKILL.md:❌ Run `status` routinely → ✅ only when retrieval feels broken or after large ingestion.SKILL.md:Invoke: **"curate memory" / "run curator" / "memory maintenance"**.
MCP servers (1)
README.md(clawmem):/absolute/path/to/clawmem/bin/clawmem mcp
Install scripts (1)
README.md:- [Bun](https://bun.sh) v1.0+ — runtime for ClawMem. On Linux, install via `curl -fsSL https://bun.sh/install | bash` (not snap — snap Bun cannot read stdin, which breaks hooks).· uses the network
- Medium risk: runs-install-script-remote-exec (README.md:79)
- Low risk: network-instructions (AGENTS.md:33)
- Low risk: scripts-present (src/amem.ts)
- Low risk: scripts-present (src/beads.ts)
- Low risk: scripts-present (src/busy-retry.ts)
- Low risk: scripts-present (src/canary.ts)
- Low risk: scripts-present (src/causal-reader.ts)
- Low risk: scripts-present (src/causal-retrieval.ts)
- Low risk: scripts-present (src/causal-writer.ts)
- Low risk: scripts-present (src/clawmem.ts)
- Low risk: scripts-present (src/clock.ts)
- Low risk: scripts-present (src/collections.ts)
- Low risk: scripts-present (src/compaction-state.ts)
- Low risk: scripts-present (src/config.ts)
- Low risk: scripts-present (src/consolidation.ts)
- Low risk: scripts-present (src/conversation-synthesis.ts)
- Low risk: scripts-present (src/deductive-guardrails.ts)
- Low risk: scripts-present (src/directory-context.ts)
- Low risk: scripts-present (src/embed-readiness.ts)
- Low risk: scripts-present (src/entity-repair.ts)
- Low risk: scripts-present (src/entity.ts)
- Low risk: scripts-present (src/eval/gold.ts)
- Low risk: scripts-present (src/eval/hook-gold.ts)
- Low risk: scripts-present (src/eval/hook-invariants.ts)
- Low risk: scripts-present (src/eval/hook-metrics.ts)
- Low risk: scripts-present (src/eval/hook-run.ts)
- Low risk: scripts-present (src/eval/hook-trace.ts)
- Low risk: scripts-present (src/eval/metrics.ts)
- Low risk: scripts-present (src/eval/pair-audit.ts)
- Low risk: scripts-present (src/eval/replay.ts)
- Low risk: scripts-present (src/eval/replicated.ts)
- Low risk: scripts-present (src/eval/report.ts)
- Low risk: scripts-present (src/eval/run-identity.ts)
- Low risk: scripts-present (src/eval/run.ts)
- Low risk: scripts-present (src/eval/types.ts)
- Low risk: scripts-present (src/eval/vec-daemon-child.ts)
- Low risk: scripts-present (src/formatter.ts)
- Low risk: scripts-present (src/graph-traversal.ts)
- Low risk: scripts-present (src/health/rerank-health.ts)
- Low risk: scripts-present (src/hook-settings.ts)
- Low risk: scripts-present (src/hooks.ts)
- Low risk: scripts-present (src/hooks/context-surfacing.ts)
- Low risk: scripts-present (src/hooks/curator-nudge.ts)
- Low risk: scripts-present (src/hooks/decision-extractor.ts)
- Low risk: scripts-present (src/hooks/feedback-loop.ts)
- Low risk: scripts-present (src/hooks/gate-tokens.ts)
- Low risk: scripts-present (src/hooks/handoff-generator.ts)
- Low risk: scripts-present (src/hooks/postcompact-inject.ts)
- Low risk: scripts-present (src/hooks/precompact-extract.ts)
- Low risk: scripts-present (src/hooks/pretool-inject.ts)
Attribution and licence
- First committed by
yoloshii
- Declared authors
- yoloshii (declared in package.json)
- Publisher
- Yoloshi Nomotomoro? (Community)
- Source
- yoloshii/ClawMem · commit 284b55a
- Licence
- MIT License (files served here)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
- Contributors
- yoloshii, cymkd, DrJsPBs, Oliverbot26, inire
AutoGineer is not affiliated with or endorsed by yoloshii.
Install from source
399 of its files are not served here, so there is no ZIP. yoloshii/ClawMem at 284b55a