Enhanced Long-Term Memory Plugin for OpenClaw
Hybrid Retrieval (Vector + BM25) ยท Cross-Encoder Rerank ยท Multi-Scope Isolation ยท Management CLI
English | ็ฎไฝไธญๆ
Watch the full walkthrough โ covers installation, configuration, and how hybrid retrieval works under the hood.
๐ https://youtu.be/MtukF1C8epQ
๐ https://www.bilibili.com/video/BV1zUf2BGEgn/
The built-in memory-lancedb plugin in OpenClaw provides basic vector search. memory-lancedb-pro takes it much further:
| Feature | Built-in memory-lancedb |
memory-lancedb-pro |
|---|---|---|
| Vector search | โ | โ |
| BM25 full-text search | โ | โ |
| Hybrid fusion (Vector + BM25) | โ | โ |
| Cross-encoder rerank (Jina / custom endpoint) | โ | โ |
| Recency boost | โ | โ |
| Time decay | โ | โ |
| Length normalization | โ | โ |
| MMR diversity | โ | โ |
| Multi-scope isolation | โ | โ |
| Noise filtering | โ | โ |
| Adaptive retrieval | โ | โ |
| Management CLI | โ | โ |
| Session memory | โ | โ |
| Task-aware embeddings | โ | โ |
| Any OpenAI-compatible embedding | Limited | โ (OpenAI, Gemini, Jina, Ollama, etc.) |
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ index.ts (Entry Point) โ
โ Plugin Registration ยท Config Parsing ยท Lifecycle Hooks โ
โโโโโโโโโโฌโโโโโโโโโโโฌโโโโโโโโโโโฌโโโโโโโโโโโฌโโโโโโโโโโโโโโโโ
โ โ โ โ
โโโโโโผโโโโ โโโโโโผโโโโ โโโโโผโโโโโ โโโโผโโโโโโโโโโโ
โ store โ โembedderโ โretrieverโ โ scopes โ
โ .ts โ โ .ts โ โ .ts โ โ .ts โ
โโโโโโโโโโ โโโโโโโโโโ โโโโโโโโโโ โโโโโโโโโโโโโโโ
โ โ
โโโโโโผโโโโ โโโโโโโผโโโโโโโโโโโ
โmigrate โ โnoise-filter.ts โ
โ .ts โ โadaptive- โ
โโโโโโโโโโ โretrieval.ts โ
โโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโ โโโโโโโโโโโโ
โ tools.ts โ โ cli.ts โ
โ (Agent API) โ โ (CLI) โ
โโโโโโโโโโโโโโโ โโโโโโโโโโโโ
| File | Purpose |
|---|---|
index.ts |
Plugin entry point. Registers with OpenClaw Plugin API, parses config, mounts before_agent_start (auto-recall), agent_end (auto-capture), and command:new (session memory) hooks |
openclaw.plugin.json |
Plugin metadata + full JSON Schema config declaration (with uiHints) |
package.json |
NPM package info. Depends on @lancedb/lancedb, openai, @sinclair/typebox |
cli.ts |
CLI commands: memory list/search/stats/delete/delete-bulk/export/import/reembed/migrate |
src/store.ts |
LanceDB storage layer. Table creation / FTS indexing / Vector search / BM25 search / CRUD / bulk delete / stats |
src/embedder.ts |
Embedding abstraction. Compatible with any OpenAI-API provider (OpenAI, Gemini, Jina, Ollama, etc.). Supports task-aware embedding (taskQuery/taskPassage) |
src/retriever.ts |
Hybrid retrieval engine. Vector + BM25 โ RRF fusion โ Jina Cross-Encoder Rerank โ Recency Boost โ Importance Weight โ Length Norm โ Time Decay โ Hard Min Score โ Noise Filter โ MMR Diversity |
src/scopes.ts |
Multi-scope access control. Supports global, agent:<id>, custom:<name>, project:<id>, user:<id> |
src/tools.ts |
Agent tool definitions: memory_recall, memory_store, memory_forget (core) + memory_stats, memory_list (management) |
src/noise-filter.ts |
Noise filter. Filters out agent refusals, meta-questions, greetings, and low-quality content |
src/adaptive-retrieval.ts |
Adaptive retrieval. Determines whether a query needs memory retrieval (skips greetings, slash commands, simple confirmations, emoji) |
src/migrate.ts |
Migration tool. Migrates data from the built-in memory-lancedb plugin to Pro |
Query โ embedQuery() โโ
โโโ RRF Fusion โ Rerank โ Recency Boost โ Importance Weight โ Filter
Query โ BM25 FTS โโโโโโ
vectorWeight, bm25Weight, minScore| Stage | Formula | Effect |
|---|---|---|
| Recency Boost | exp(-ageDays / halfLife) * weight |
Newer memories score higher (default: 14-day half-life, 0.10 weight) |
| Importance Weight | score *= (0.7 + 0.3 * importance) |
importance=1.0 โ ร1.0, importance=0.5 โ ร0.85 |
| Length Normalization | score *= 1 / (1 + 0.5 * log2(len/anchor)) |
Prevents long entries from dominating (anchor: 500 chars) |
| Time Decay | score *= 0.5 + 0.5 * exp(-ageDays / halfLife) |
Old entries gradually lose weight, floor at 0.5ร (60-day half-life) |
| Hard Min Score | Discard if score < threshold |
Removes irrelevant results (default: 0.35) |
| MMR Diversity | Cosine similarity > 0.85 โ demoted | Prevents near-duplicate results |
global, agent:<id>, custom:<name>, project:<id>, user:<id>scopes.agentAccessglobal + its own agent:<id> scopeFilters out low-quality content at both auto-capture and tool-store stages:
/new command โ saves previous session summary to LanceDB.jsonl session persistence)agent_end hook): Extracts preference/fact/decision/entity from conversations, deduplicates, stores up to 3 per turnbefore_agent_start hook): Injects <relevant-memories> context (up to 3 entries)In OpenClaw, the agent workspace is the agentโs working directory (default: ~/.openclaw/workspace).
According to the docs, the workspace is the default cwd, and relative paths are resolved against the workspace (unless you use an absolute path).
Note: OpenClaw configuration typically lives under
~/.openclaw/openclaw.json(separate from the workspace).
Common mistake: cloning the plugin somewhere else, while keeping plugins.load.paths: ["plugins/memory-lancedb-pro"] (a relative path). In that case OpenClaw will look for plugins/memory-lancedb-pro under your workspace and fail to load it.
plugins/ under your workspace# 1) Go to your OpenClaw workspace (default: ~/.openclaw/workspace)
# (You can override it via agents.defaults.workspace.)
cd /path/to/your/openclaw/workspace
# 2) Clone the plugin into workspace/plugins/
git clone https://github.com/win4r/memory-lancedb-pro.git plugins/memory-lancedb-pro
# 3) Install dependencies
cd plugins/memory-lancedb-pro
npm install
Then reference it with a relative path in your OpenClaw config:
{
"plugins": {
"load": {
"paths": ["plugins/memory-lancedb-pro"]
},
"entries": {
"memory-lancedb-pro": {
"enabled": true,
"config": {
"embedding": {
"apiKey": "${JINA_API_KEY}",
"model": "jina-embeddings-v5-text-small",
"baseURL": "https://api.jina.ai/v1",
"dimensions": 1024,
"taskQuery": "retrieval.query",
"taskPassage": "retrieval.passage",
"normalized": true
}
}
}
},
"slots": {
"memory": "memory-lancedb-pro"
}
}
}
{
"plugins": {
"load": {
"paths": ["/absolute/path/to/memory-lancedb-pro"]
}
}
}
openclaw gateway restart
Note: If you previously used the built-in
memory-lancedb, disable it when enabling this plugin. Only one memory plugin can be active at a time.
openclaw plugins list
openclaw plugins info memory-lancedb-pro
openclaw plugins doctor
# Look for: plugins.slots.memory = "memory-lancedb-pro"
openclaw config get plugins.slots.memory
{
"embedding": {
"apiKey": "${JINA_API_KEY}",
"model": "jina-embeddings-v5-text-small",
"baseURL": "https://api.jina.ai/v1",
"dimensions": 1024,
"taskQuery": "retrieval.query",
"taskPassage": "retrieval.passage",
"normalized": true
},
"dbPath": "~/.openclaw/memory/lancedb-pro",
"autoCapture": true,
"autoRecall": true,
"retrieval": {
"mode": "hybrid",
"vectorWeight": 0.7,
"bm25Weight": 0.3,
"minScore": 0.3,
"rerank": "cross-encoder",
"rerankApiKey": "jina_xxx",
"rerankModel": "jina-reranker-v2-base-multilingual",
"rerankEndpoint": "https://api.jina.ai/v1/rerank",
"rerankProvider": "jina",
"candidatePoolSize": 20,
"recencyHalfLifeDays": 14,
"recencyWeight": 0.1,
"filterNoise": true,
"lengthNormAnchor": 500,
"hardMinScore": 0.35,
"timeDecayHalfLifeDays": 60
},
"enableManagementTools": false,
"scopes": {
"default": "global",
"definitions": {
"global": { "description": "Shared knowledge" },
"agent:discord-bot": { "description": "Discord bot private" }
},
"agentAccess": {
"discord-bot": ["global", "agent:discord-bot"]
}
},
"sessionMemory": {
"enabled": false,
"messageCount": 15
}
}
This plugin works with any OpenAI-compatible embedding API:
| Provider | Model | Base URL | Dimensions |
|---|---|---|---|
| Jina (recommended) | jina-embeddings-v5-text-small |
https://api.jina.ai/v1 |
1024 |
| OpenAI | text-embedding-3-small |
https://api.openai.com/v1 |
1536 |
| Google Gemini | gemini-embedding-001 |
https://generativelanguage.googleapis.com/v1beta/openai/ |
3072 |
| Ollama (local) | nomic-embed-text |
http://localhost:11434/v1 |
768 |
Cross-encoder reranking supports multiple providers via rerankProvider:
| Provider | rerankProvider |
Endpoint | Example Model |
|---|---|---|---|
| Jina (default) | jina |
https://api.jina.ai/v1/rerank |
jina-reranker-v2-base-multilingual |
| SiliconFlow (free tier available) | siliconflow |
https://api.siliconflow.com/v1/rerank |
BAAI/bge-reranker-v2-m3, Qwen/Qwen3-Reranker-8B |
| Pinecone | pinecone |
https://api.pinecone.io/rerank |
bge-reranker-v2-m3 |
{
"retrieval": {
"rerank": "cross-encoder",
"rerankProvider": "siliconflow",
"rerankEndpoint": "https://api.siliconflow.com/v1/rerank",
"rerankApiKey": "sk-xxx",
"rerankModel": "BAAI/bge-reranker-v2-m3"
}
}
{
"retrieval": {
"rerank": "cross-encoder",
"rerankProvider": "pinecone",
"rerankEndpoint": "https://api.pinecone.io/rerank",
"rerankApiKey": "pcsk_xxx",
"rerankModel": "bge-reranker-v2-m3"
}
}
# List memories
openclaw memory-pro list [--scope global] [--category fact] [--limit 20] [--json]
# Search memories
openclaw memory-pro search "query" [--scope global] [--limit 10] [--json]
# View statistics
openclaw memory-pro stats [--scope global] [--json]
# Delete a memory by ID (supports 8+ char prefix)
openclaw memory-pro delete <id>
# Bulk delete with filters
openclaw memory-pro delete-bulk --scope global [--before 2025-01-01] [--dry-run]
# Export / Import
openclaw memory-pro export [--scope global] [--output memories.json]
openclaw memory-pro import memories.json [--scope global] [--dry-run]
# Re-embed all entries with a new model
openclaw memory-pro reembed --source-db /path/to/old-db [--batch-size 32] [--skip-existing]
# Migrate from built-in memory-lancedb
openclaw memory-pro migrate check [--source /path]
openclaw memory-pro migrate run [--source /path] [--dry-run] [--skip-existing]
openclaw memory-pro migrate verify [--source /path]
/lesson)This plugin provides the core memory tools (memory_store, memory_recall, memory_forget, memory_update). You can define custom slash commands in your Agent's system prompt to create convenient shortcuts.
/lesson commandAdd this to your CLAUDE.md, AGENTS.md, or system prompt:
## /lesson command
When the user sends `/lesson <content>`:
1. Use memory_store to save as category=fact (the raw knowledge)
2. Use memory_store to save as category=decision (actionable takeaway)
3. Confirm what was saved
/remember command## /remember command
When the user sends `/remember <content>`:
1. Use memory_store to save with appropriate category and importance
2. Confirm with the stored memory ID
| Tool | Description |
|---|---|
memory_store |
Store a memory (supports category, importance, scope) |
memory_recall |
Search memories (hybrid vector + BM25 retrieval) |
memory_forget |
Delete a memory by ID or search query |
memory_update |
Update an existing memory in-place |
Note: These tools are registered automatically when the plugin loads. Custom commands like
/lessonare not built into the plugin โ they are defined at the Agent/system-prompt level and simply call these tools.
LanceDB table memories:
| Field | Type | Description |
|---|---|---|
id |
string (UUID) | Primary key |
text |
string | Memory text (FTS indexed) |
vector |
float[] | Embedding vector |
category |
string | preference / fact / decision / entity / other |
scope |
string | Scope identifier (e.g., global, agent:main) |
importance |
float | Importance score 0โ1 |
timestamp |
int64 | Creation timestamp (ms) |
metadata |
string (JSON) | Extended metadata |
| Package | Purpose |
|---|---|
@lancedb/lancedb โฅ0.26.2 |
Vector database (ANN + FTS) |
openai โฅ6.21.0 |
OpenAI-compatible Embedding API client |
@sinclair/typebox 0.34.48 |
JSON Schema type definitions (tool parameters) |
MIT