memory-lancedb-pro Documentation

Enhanced LanceDB memory plugin for OpenClaw — Hybrid Retrieval (Vector + BM25), Cross-Encoder Rerank, Multi-Scope Isolation, Management CLI

4,453 stars JavaScript JavaScript 11 files · ~30,417 tokens #lancedb#memory#openclaw#openclaw-agent#openclaw-plugin#rag
RAW Doc

Technical Documentation: CortexReach/memory-lancedb-pro

ℹ️ Provenance: Multi-Tier Ingestion · CodeWiki Reference

Overview (`README.md`)


Why memory-lancedb-pro?

Most AI agents have amnesia. They forget everything the moment you start a new chat.

memory-lancedb-pro is a production-grade long-term memory plugin for OpenClaw that turns your agent into an AI Memory Assistant — it automatically captures what matters, lets noise naturally fade, and retrieves the right memory at the right time. No manual tagging, no configuration headaches.

Your AI Memory Assistant in Action

Without memory — every session starts from zero:

You: "Use tabs for indentation, always add error handling."
(next session)
You: "I already told you — tabs, not spaces!" 😤
(next session)
You: "...seriously, tabs. And error handling. Again."

With memory-lancedb-pro — your agent learns and remembers:

You: "Use tabs for indentation, always add error handling."
(next session — agent auto-recalls your preferences)
Agent: (silently applies tabs + error handling) ✅
You: "Why did we pick PostgreSQL over MongoDB last month?"
Agent: "Based on our discussion on Feb 12, the main reasons were..." ✅

That's the difference an AI Memory Assistant makes — it learns your style, recalls past decisions, and delivers personalized responses without you repeating yourself.

What else can it do?

What you get
Auto-Capture Your agent learns from every conversation — no manual memory_store needed
Smart Extraction LLM-powered 6-category classification: profiles, preferences, entities, events, cases, patterns
Intelligent Forgetting Weibull decay model — important memories stay, noise naturally fades away
Hybrid Retrieval Vector + BM25 full-text search, fused with cross-encoder reranking
Context Injection Relevant memories automatically surface before each reply
Multi-Scope Isolation Per-agent, per-user, per-project memory boundaries
Any Provider OpenAI, Jina, Gemini, Ollama, or any OpenAI-compatible API
Full Toolkit CLI, backup, migration, upgrade, export/import — production-ready

Quick Start

CPU Requirement: Your CPU must support AVX instructions. LanceDB native vector search may require AVX2 on some Linux x64 builds and can crash AVX-only CPUs with SIGILL; set retrieval.disableNativeCosine: true or MEMORY_LANCEDB_DISABLE_NATIVE_COSINE=1 to use a scoped row scan plus JavaScript cosine ranking. Check CPU flags with: grep -o 'avx[^ ]*' /proc/cpuinfo | head -1 (no output = not supported). See #419 and #644 for details.

The community-maintained setup script handles install, upgrade, and repair in one command:

bash
curl -fsSL https://raw.githubusercontent.com/CortexReach/toolbox/main/memory-lancedb-pro-setup/setup-memory.sh -o setup-memory.sh
bash setup-memory.sh

See Ecosystem below for the full list of scenarios the script covers and other community tools.

Option B: Manual Install

Via OpenClaw CLI (recommended):

bash
openclaw plugins install memory-lancedb-pro@beta

Or via npm:

bash
npm i memory-lancedb-pro@beta

If using npm, you will also need to add the plugin's install directory as an absolute path in plugins.load.paths in your openclaw.json. This is the most common setup issue.

Add to your openclaw.json:

json
{
  "plugins": {
    "slots": { "memory": "memory-lancedb-pro" },
    "entries": {
      "memory-lancedb-pro": {
        "enabled": true,
        "config": {
          "embedding": {
            "provider": "openai-compatible",
            "apiKey": "${OPENAI_API_KEY}",
            "model": "text-embedding-3-small"
          },
          "autoCapture": true,
          "autoRecall": true,
          "smartExtraction": true,
          "canonicalCorpus": {
            "enabled": true,
            "syncOnSearch": true
          },
          "dreaming": {
            "enabled": false
          },
          "extractMinMessages": 2,
          "extractMaxChars": 8000,
          "sessionMemory": { "enabled": false }
        }
      }
    }
  }
}

Why these defaults?

  • autoCapture + smartExtraction → your agent learns from every conversation automatically
  • autoRecall → relevant memories are injected before each reply
  • extractMinMessages: 2 → extraction triggers in normal two-turn chats
  • sessionMemory.enabled: false → avoids polluting retrieval with session summaries on day one

⚠️ Memory Architecture (Important)

When memory-lancedb-pro owns the OpenClaw memory slot, it now exposes one memory capability with two coordinated stores:

Memory Layer Storage What it's for Recallable?
Plugin Memory LanceDB (vector store) Semantic recall via memory_recall / auto-recall ✅ Yes
Canonical Corpus MEMORY.md, memory/**/*.md, recent session transcripts, memory/dreaming/**/*.md Source-of-truth files and public artifacts ✅ Via LanceDB semantic index when canonicalCorpus.enabled is true

Key principle:

Canonical files remain the source of truth. LanceDB is the semantic index used to retrieve them with grounded paths, line spans, snippets, and citations.

What this means for you:

  • Need semantic recall? → Use memory_store or let auto-capture do it
  • memory/YYYY-MM-DD.md → treat as a daily journal / log that can also be indexed for semantic lookup
  • MEMORY.md → curated human-readable reference that can be indexed as canonical context
  • memory/dreaming/**/*.md → dream reports exposed as public artifacts and indexed as reflection context
  • Session JSONL transcripts → indexed as source: "sessions" when canonicalCorpus.includeSessionTranscripts is enabled
  • Plugin memory → primary write path for durable facts, preferences, decisions, and auto-captured memories

OpenClaw hosts receive:

  • api.registerMemoryCapability({ runtime, promptBuilder, flushPlanResolver, publicArtifacts })
  • runtime search results shaped as path, startLine, endLine, snippet, source, and citation
  • public artifacts for MEMORY.md, memory/**/*.md, dream reports, and the dreaming event log at memory/.dreams/events.jsonl

Dreaming compatibility is configured under the same plugin entry. If dreaming.enabled is true while this plugin owns plugins.slots.memory, OpenClaw can use the memory-core dreaming sidecar against this plugin's memory capability and public artifacts.

On hosts exposing openclaw/plugin-sdk/memory-recall, interactive memory_recall
(including the memory_search/memory_get aliases) and successful auto-recall
injections also report surfaced canonical-file excerpts to native dreaming.
This requires canonical-corpus metadata for the current workspace, matching
content hashes, and the host's live tool/hook run context. The host validates the
excerpt against the source file, applies its existing dreaming eligibility rules,
and deduplicates repeated recalls within the same run. Only literal displayed
primary text counts; generated abstracts, neighbor text, virtual LanceDB IDs,
session transcripts, and late/failed injections do not become file evidence.
Auto-context markup transformations are conservatively excluded. Daily corpus
ingestion does not produce interactive signals. Older hosts without the API or
invocation context continue normal retrieval without this additional recording.
No native dreaming thresholds, promotion budgets, or provenance labels are
changed by this bridge; it does not write native state directly.

Validate & restart:

bash
openclaw config validate
openclaw gateway restart
openclaw logs --follow --plain | grep "memory-lancedb-pro"

You should see:

  • memory-lancedb-pro: smart extraction enabled
  • memory-lancedb-pro@...: plugin registered

Done! Your agent now has long-term memory.

More installation paths (existing users, upgrades)

Already using OpenClaw?

  1. Add the plugin with an absolute plugins.load.paths entry
  2. Bind the memory slot: plugins.slots.memory = "memory-lancedb-pro"
  3. Verify: openclaw plugins info memory-lancedb-pro && openclaw memory-pro stats

Upgrading from pre-v1.1.0?

bash
# 1) Backup
openclaw memory-pro export --scope global --output memories-backup.json
# 2) Dry run
openclaw memory-pro upgrade --dry-run
# 3) Run upgrade
openclaw memory-pro upgrade
# 4) Verify
openclaw memory-pro stats

See CHANGELOG-v1.1.0.md for behavior changes and upgrade rationale.

Turning on Jina task hints on an existing database?

Task hints are two config keys under the plugin's embedding block:

jsonc
"memory-lancedb-pro": {
  "config": {
    "embedding": {
      "model": "jina-embeddings-v5-text-small",
      "taskQuery": "retrieval.query",
      "taskPassage": "retrieval.passage"
    }
  }
}

They only affect vectors written after you set them. Rows already in your store
were embedded without a task hint, so a query embedded with retrieval.query is
compared against passages that live in a different vector space — you get roughly
half the benefit, silently.

To fix existing rows, re-embed into a fresh database and cut over to it. Do
not re-embed in place: reembed writes each row with table.add() (append by
id, not replace), so an in-place run — which is exactly what --force unlocks —
leaves the old vector beside the new one and doubles every row; retries pile on
more. reembed refuses same-path runs unless you force it, for this reason.

bash
# 0) Stop the gateway so nothing writes mid-migration.

# 1) Back up the whole store — a real filesystem copy of the LanceDB directory.
#    (Do NOT rely on `memory-pro export`: it defaults to --limit 1000 and a single
#    --scope, so it silently drops rows past 1000 and every non-global scope.)
cp -r <your dbPath> <your dbPath>.bak

# 2) In the plugin config, set the task hints AND point `dbPath` at a new, empty
#    target (e.g. "<your dbPath>-v2"). A fresh target is also what lets you change
#    `embedding.dimensions`: a new vector width can only go into a new table.

# 3) Dry run — reads the source, prints the row count, writes nothing.
openclaw memory-pro reembed --source-db <old dbPath> --dry-run

# 4) Re-embed old -> new with the now-current task hints. Source != target, so each
#    id lands exactly once. Safe to re-run with --skip-existing if interrupted.
openclaw memory-pro reembed --source-db <old dbPath>

# 5) Verify before trusting the cutover: the "imported" count and
#    `memory-pro stats` on the new dbPath must equal the dry-run row count.
openclaw memory-pro stats

# 6) Start the gateway; it now opens the new dbPath.

The same cutover applies whenever you change embedding.model or
embedding.dimensions — always re-embed into a fresh dbPath, never in place.

Telegram Bot Quick Import (click to expand)

If you are using OpenClaw's Telegram integration, the easiest way is to send an import command directly to the main Bot instead of manually editing config.

Send this message:

text
Help me connect this memory plugin with the most user-friendly configuration: https://github.com/CortexReach/memory-lancedb-pro

Requirements:
1. Set it as the only active memory plugin
2. Use Jina for embedding, and set embedding.taskQuery=retrieval.query and embedding.taskPassage=retrieval.passage
3. Use Jina for reranker
4. Use gpt-4o-mini for the smart-extraction LLM
5. Enable autoCapture, autoRecall, smartExtraction
6. extractMinMessages=2
7. sessionMemory.enabled=false
8. captureAssistant=false
9. retrieval mode=hybrid, vectorWeight=0.7, bm25Weight=0.3
10. rerank=cross-encoder, candidatePoolSize=12, minScore=0.6, hardMinScore=0.62
11. Generate the final openclaw.json config directly, not just an explanation

Ecosystem

memory-lancedb-pro is the core plugin. The community has built tools around it to make setup and daily use even smoother:

Setup Script — One-Click Install, Upgrade & Repair

CortexReach/toolbox/memory-lancedb-pro-setup

Not just a simple installer — the script intelligently handles a wide range of real-world scenarios:

Your situation What the script does
Never installed Fresh download → install deps → pick config → write to openclaw.json → restart
Installed via git clone, stuck on old commit Auto git fetch + checkout to latest → reinstall deps → verify
Config has invalid fields Auto-detect via schema filter, remove unsupported fields
Installed via npm Skips git update, reminds you to run npm update yourself
openclaw CLI broken due to invalid config Fallback: read workspace path directly from openclaw.json file
extensions/ instead of plugins/ Auto-detect plugin location from config or filesystem
Already up to date Run health checks only, no changes
bash
bash setup-memory.sh                    # Install or upgrade
bash setup-memory.sh --dry-run          # Preview only
bash setup-memory.sh --beta             # Include pre-release versions
bash setup-memory.sh --uninstall        # Revert config and remove plugin

Built-in provider presets: Jina / DashScope / SiliconFlow / OpenAI / Ollama, or bring your own OpenAI-compatible API. For full usage (including --ref, --selfcheck-only, and more), see the setup script README.

Claude Code / OpenClaw Skill — AI-Guided Configuration

CortexReach/memory-lancedb-pro-skill

Install this skill and your AI agent (Claude Code or OpenClaw) gains deep knowledge of every feature in memory-lancedb-pro. Just say "help me enable the best config" and get:

  • Guided 7-step configuration workflow with 4 deployment plans:
    • Full Power (Jina + OpenAI) / Budget (free SiliconFlow reranker) / Simple (OpenAI only) / Fully Local (Ollama, zero API cost)
  • All 9 MCP tools used correctly: memory_recall, memory_store, memory_forget, memory_update, memory_stats, memory_list, self_improvement_log, self_improvement_extract_skill, self_improvement_review (full toolset requires enableManagementTools: true — the default Quick Start config exposes the 4 core tools)
  • Common pitfall avoidance: workspace plugin enablement, autoRecall default-false, jiti cache, env vars, scope isolation, and more

Install for Claude Code:

bash
git clone https://github.com/CortexReach/memory-lancedb-pro-skill.git ~/.claude/skills/memory-lancedb-pro

Install for OpenClaw:

bash
git clone https://github.com/CortexReach/memory-lancedb-pro-skill.git ~/.openclaw/workspace/skills/memory-lancedb-pro-skill

Video Tutorial

Full walkthrough: installation, configuration, and hybrid retrieval internals.


https://youtu.be/MtukF1C8epQ


https://www.bilibili.com/video/BV1zUf2BGEgn/


Architecture

text
┌─────────────────────────────────────────────────────────┐
│                   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)    │
    └─────────────┘   └──────────┘

For a deep-dive into the full architecture, see docs/memory_architecture_analysis.md.

File Reference (click to expand)

File Purpose
index.ts Plugin entry point. Registers with OpenClaw Plugin API, parses config, mounts lifecycle hooks via api.on() and command hooks via api.registerHook()
openclaw.plugin.json Plugin metadata + full JSON Schema config declaration
cli.ts CLI commands: memory-pro list/search/stats/delete/delete-bulk/export/import/reembed/upgrade/migrate
src/store.ts LanceDB storage layer. Table creation / FTS indexing / Vector search / BM25 search / CRUD
src/embedder.ts Embedding abstraction. Compatible with any OpenAI-compatible API provider
src/retriever.ts Hybrid retrieval engine. Vector + BM25 → Hybrid Fusion → Rerank → Lifecycle Decay → Filter
src/scopes.ts Multi-scope access control
src/tools.ts Agent tool definitions: memory_recall, memory_store, memory_forget, memory_update + management tools
src/noise-filter.ts Filters out agent refusals, meta-questions, greetings, and low-quality content
src/adaptive-retrieval.ts Determines whether a query needs memory retrieval
src/migrate.ts Migration from built-in memory-lancedb to Pro
src/smart-extractor.ts LLM-powered 6-category extraction with L0/L1/L2 layered storage and two-stage dedup
src/decay-engine.ts Weibull stretched-exponential decay model
src/tier-manager.ts Three-tier promotion/demotion: Peripheral ↔ Working ↔ Core

Core Features

Hybrid Retrieval

text
Query → embedQuery() ─┐
                       ├─→ Hybrid Fusion → Rerank → Lifecycle Decay Boost → Length Norm → Filter
Query → BM25 FTS ─────┘
  • Vector Search — semantic similarity via LanceDB ANN (cosine distance)
  • BM25 Full-Text Search — exact keyword matching via LanceDB FTS index
  • Hybrid Fusion — vector score as base, BM25 hits receive a weighted boost (not standard RRF — tuned for real-world recall quality)
  • Configurable Weights — vectorWeight, bm25Weight, minScore

Cross-Encoder Reranking

  • Built-in adapters for Jina, SiliconFlow, Voyage AI, and Pinecone
  • Compatible with any Jina-compatible endpoint (e.g., Hugging Face TEI, DashScope)
  • Hybrid scoring: 60% cross-encoder + 40% original fused score
  • Graceful degradation: falls back to cosine similarity on API failure

Multi-Stage Scoring Pipeline

Stage Effect
Hybrid Fusion Combines semantic and exact-match recall
Cross-Encoder Rerank Promotes semantically precise hits
Lifecycle Decay Boost Weibull freshness + access frequency + importance × confidence
Length Normalization Prevents long entries from dominating (anchor: 500 chars)
Hard Min Score Removes irrelevant results (default: 0.35)
MMR Diversity Cosine similarity > 0.85 → demoted

Smart Memory Extraction (v1.1.0)

  • LLM-Powered 6-Category Extraction: profile, preferences, entities, events, cases, patterns
  • L0/L1/L2 Layered Storage: L0 (one-sentence index) → L1 (structured summary) → L2 (full narrative)
  • Two-Stage Dedup: vector similarity pre-filter (≥0.7) → LLM semantic decision (CREATE/MERGE/SKIP)
  • Category-Aware Merge: profile always merges, events/cases are append-only

Memory Lifecycle Management (v1.1.0)

  • Weibull Decay Engine: composite score = recency + frequency + intrinsic value
  • Three-Tier Promotion: Peripheral ↔ Working ↔ Core with configurable thresholds
  • Access Reinforcement: frequently recalled memories decay slower (spaced-repetition style)
  • Importance-Modulated Half-Life: important memories decay slower

Multi-Scope Isolation

  • Built-in scopes: global, agent:, custom:<name>, project:, user:
  • Agent-level access control via scopes.agentAccess
  • Default: each agent accesses global + its own agent: scope
  • Read-only tools such as memory_recall, memory_search, memory_list, and memory_debug fail soft when a requested scope is inaccessible: they search the caller's accessible scopes instead and return ignoredScope plus accessibleScopes in details. Write and mutation tools still return scope_access_denied for inaccessible scopes.

Auto-Capture & Auto-Recall

  • Auto-Capture (agent_end): extracts preference/fact/decision/entity from conversations, deduplicates, stores up to 3 per turn
  • Auto-Recall (before_prompt_build): injects <relevant-memories> context (up to 3 entries)

Note (v1.1.0-beta.9+): Auto-recall now uses the before_prompt_build hook instead of the deprecated before_agent_start. See Hook Adaptation below for details.

Noise Filtering & Adaptive Retrieval

  • Filters low-quality content: agent refusals, meta-questions, greetings
  • Skips retrieval for greetings, slash commands, simple confirmations, emoji
  • Forces retrieval for memory keywords ("remember", "previously", "last time")
  • CJK-aware thresholds (Chinese: 6 chars vs English: 15 chars)

Compared to Built-in memory-lancedb (click to expand)

Feature Built-in memory-lancedb memory-lancedb-pro
Vector search Yes Yes
BM25 full-text search - Yes
Hybrid fusion (Vector + BM25) - Yes
Cross-encoder rerank (multi-provider) - Yes
Recency boost & time decay - Yes
Length normalization - Yes
MMR diversity - Yes
Multi-scope isolation - Yes
Noise filtering - Yes
Adaptive retrieval - Yes
Management CLI - Yes
Session memory - Yes
Task-aware embeddings - Yes
LLM Smart Extraction (6-category) - Yes (v1.1.0)
Weibull Decay + Tier Promotion - Yes (v1.1.0)
Any OpenAI-compatible embedding Limited Yes

Configuration

API-key fields (embedding.apiKey, retrieval.rerankApiKey, and llm.apiKey) accept plain strings, ${ENV_VAR} placeholders, or SecretRef objects. This plugin supports the env and file SecretRef sources:

json
{
  "embedding": {
    "apiKey": { "source": "env", "id": "JINA_API_KEY" }
  },
  "retrieval": {
    "rerankApiKey": { "source": "file", "id": "~/.openclaw/secrets/jina-rerank" }
  }
}

For source: "file", id is resolved through OpenClaw's api.resolvePath() and then read as a UTF-8 file. The optional provider field is accepted for SecretRef object-shape compatibility but is not used for provider dispatch. exec and other SecretRef sources are rejected by runtime config validation.

Full Configuration Example

text
/* Detailed source-code truncated for AI context efficiency. */

OpenClaw Hook Permissions

The published plugin manifest declares hooks.allowConversationAccess so the agent_end auto-capture hook can read conversation context. If you maintain a custom plugin entry or non-bundled install that overrides manifest hook metadata, keep conversation access enabled:

json
{
  "plugins": {
    "entries": {
      "memory-lancedb-pro": {
        "hooks": {
          "allowConversationAccess": true
        }
      }
    }
  }
}

Without conversation access, recall can still load but auto-capture may be blocked.

Embedding Providers

Works with OpenAI-compatible embedding APIs, including provider-specific payload adapters for services such as Jina and Voyage:

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
Voyage voyage-4-lite / voyage-4 https://api.voyageai.com/v1 1024 / 1024
Google Gemini gemini-embedding-001 https://generativelanguage.googleapis.com/v1beta/openai/ 3072
Ollama (local) nomic-embed-text http://localhost:11434/v1 provider-specific

Voyage embedding requests use Voyage's model + input payload shape. When requestDimensions is configured it is sent as output_dimension; OpenAI-only fields such as encoding_format are omitted.

Set embedding.maxInputChars for local embedding servers with small context or batch limits. The plugin applies a conservative default for nomic-embed-text; with automatic chunking enabled, longer documents are split before the cap is applied to each provider request.

Rerank Providers

Cross-encoder reranking supports multiple providers via rerankProvider:

Provider rerankProvider Example Model
Jina (default) jina jina-reranker-v3
SiliconFlow (free tier available) siliconflow BAAI/bge-reranker-v2-m3
Voyage AI voyage rerank-2.5
Pinecone pinecone bge-reranker-v2-m3

Any Jina-compatible rerank endpoint also works — set rerankProvider: "jina" and point rerankEndpoint to your service (e.g., Hugging Face TEI, DashScope qwen3-rerank).

Smart Extraction (LLM) — v1.1.0

When smartExtraction is enabled (default: true), the plugin uses an LLM to intelligently extract and classify memories instead of regex-based triggers.

Field Type Default Description
smartExtraction boolean true Enable/disable LLM-powered 6-category extraction
llm.auth string api-key api-key uses llm.apiKey / embedding.apiKey; oauth uses a plugin-scoped OAuth token file by default
llm.apiKey string (falls back to embedding.apiKey) API key for the LLM provider
llm.model string openai/gpt-oss-120b LLM model name
llm.baseURL string (falls back to embedding.baseURL) LLM API endpoint
llm.oauthProvider string openai-codex OAuth provider id used when llm.auth is oauth
llm.oauthPath string ~/.openclaw/.memory-lancedb-pro/oauth.json OAuth token file used when llm.auth is oauth
llm.timeoutMs number 30000 LLM request timeout in milliseconds
extractMinMessages number 2 Minimum messages before extraction triggers
extractMaxChars number 8000 Maximum characters sent to the LLM

OAuth llm config (use existing Codex / ChatGPT login cache for LLM calls):

json
{
  "llm": {
    "auth": "oauth",
    "oauthProvider": "openai-codex",
    "model": "gpt-5.4",
    "oauthPath": "${HOME}/.openclaw/.memory-lancedb-pro/oauth.json",
    "timeoutMs": 30000
  }
}

Notes for llm.auth: "oauth":

  • llm.oauthProvider is currently openai-codex.
  • OAuth tokens default to ~/.openclaw/.memory-lancedb-pro/oauth.json.
  • You can set llm.oauthPath if you want to store that file somewhere else.
  • auth login snapshots the previous api-key llm config next to the OAuth file, and auth logout restores that snapshot when available.
  • Switching from api-key to oauth does not automatically carry over llm.baseURL. Set it manually in OAuth mode only when you intentionally want a custom ChatGPT/Codex-compatible backend.

Legacy CPU Fallback

If an AVX-only Linux x64 host crashes inside LanceDB native vector search with SIGILL, disable native cosine and let memory-lancedb-pro scan scoped rows and rank them in JavaScript:

json
{
  "retrieval": {
    "disableNativeCosine": true
  }
}

You can also set MEMORY_LANCEDB_DISABLE_NATIVE_COSINE=1 for the same behavior.

Lifecycle Configuration (Decay + Tier)

Field Default Description
decay.recencyHalfLifeDays 30 Base half-life for Weibull recency decay
decay.frequencyWeight 0.3 Weight of access frequency in composite score
decay.intrinsicWeight 0.3 Weight of importance × confidence
decay.betaCore 0.8 Weibull beta for core memories
decay.betaWorking 1.0 Weibull beta for working memories
decay.betaPeripheral 1.3 Weibull beta for peripheral memories
tier.coreAccessThreshold 10 Min recall count before promoting to core
tier.peripheralAgeDays 60 Age threshold for demoting stale memories

Access Reinforcement

Frequently recalled memories decay more slowly (spaced-repetition style).

Config keys (under retrieval):

  • reinforcementFactor (0-2, default: 0.5) — set 0 to disable
  • maxHalfLifeMultiplier (1-10, default: 3) — hard cap on effective half-life

CLI Commands

bash
openclaw memory-pro list [--scope global] [--category fact] [--limit 20] [--json]
openclaw memory-pro search "query" [--scope global] [--limit 10] [--json]
openclaw memory-pro stats [--scope global] [--json]
openclaw memory-pro auth login [--provider openai-codex] [--model gpt-5.4] [--oauth-path /abs/path/oauth.json]
openclaw memory-pro auth status
openclaw memory-pro auth logout
openclaw memory-pro delete <id>
openclaw memory-pro delete-bulk --scope global [--before 2025-01-01] [--dry-run]
openclaw memory-pro export [--scope global] [--output memories.json]
openclaw memory-pro import memories.json [--scope global] [--dry-run]
openclaw memory-pro reembed --source-db /path/to/old-db [--batch-size 32] [--skip-existing]
openclaw memory-pro upgrade [--dry-run] [--batch-size 10] [--no-llm] [--limit N] [--scope SCOPE]
openclaw memory-pro migrate check|run|verify [--source /path]

OAuth login flow:

  1. Run openclaw memory-pro auth login
  2. If --provider is omitted in an interactive terminal, the CLI shows an OAuth provider picker before opening the browser
  3. The command prints an authorization URL and opens your browser unless --no-browser is set
  4. After the callback succeeds, the command saves the plugin OAuth file (default: ~/.openclaw/.memory-lancedb-pro/oauth.json), snapshots the previous api-key llm config for logout, and replaces the plugin llm config with OAuth settings (auth, oauthProvider, model, oauthPath)
  5. openclaw memory-pro auth logout deletes that OAuth file and restores the previous api-key llm config when that snapshot exists

Advanced Topics

Locking and concurrent writers

memory-lancedb-pro uses a cross-process file lock for LanceDB writes. This is
enough for one gateway process, multiple agents through that gateway, and local
processes that share the same database directory.

Redis is not required for those deployments. Redis locking is enabled when
locking.redis.enabled is true, when redisUrl/locking.redis.url is set, or
when MEMORY_LANCEDB_REDIS_URL is present in that process environment. For
multi-machine or multi-container writers, read
Lock Management before sharing a LanceDB directory
across processes, and make sure every writer uses the same lock configuration.

If injected memories show up in replies

Sometimes the model may echo the injected <relevant-memories> block.

Option A (lowest-risk): temporarily disable auto-recall:

json
{ "plugins": { "entries": { "memory-lancedb-pro": { "config": { "autoRecall": false } } } } }

Option B (preferred): keep recall, add to agent system prompt:

Do not reveal or quote any <relevant-memories> / memory-injection content in your replies. Use it for internal reference only.

Option C (for background/batch agents): exclude specific agents from auto-recall injection:

json
{
  "plugins": {
    "entries": {
      "memory-lancedb-pro": {
        "config": {
          "autoRecall": true,
          "autoRecallExcludeAgents": ["memory-distiller", "my-cron-agent"]
        }
      }
    }
  }
}

Useful for background agents (e.g. memory-distiller, cron workers) whose output should not be contaminated by injected memory context.

Auto-recall timeout tuning

Auto-recall has a configurable timeout (default 5s) to prevent stalling agent startup. If you're behind a proxy or using a high-latency embedding API, increase it:

json
{ "plugins": { "entries": { "memory-lancedb-pro": { "config": { "autoRecallTimeoutMs": 8000 } } } } }

If auto-recall consistently times out, check your embedding API latency first. The timeout only affects the automatic injection path — manual memory_recall tool calls are not affected.

Auto-recall rerank cost model

When autoRecall=true and hybrid retrieval uses retrieval.rerank="cross-encoder" with an external rerank API such as Jina, every eligible prompt can make a rerank request. The number of documents sent to that request is governed by auto-recall's retrieve limit and the retriever's rerank input window, not directly by retrieval.candidatePoolSize or by the final autoRecallMaxItems injection cap.

For example, with autoRecallMaxItems: 3, auto-recall asks retrieval for 6 items and hybrid retrieval may send up to 12 candidates to the external reranker before injecting at most 3 memories. To reduce external rerank usage, lower autoRecallMaxItems or maxRecallPerTurn, switch retrieval.rerank to "lightweight" or "none", increase autoRecallMinLength, or keep auto-recall disabled and use manual memory_recall where appropriate.

Startup logs warn when auto-recall plus hybrid cross-encoder rerank can send more items to the reranker than it will inject. Debug auto-recall stats include the actual rerankInput, rerankInputLimit, retrieveLimit, rerank, rerankProvider, and configured retrievalCandidatePoolSize.

Session Memory

  • Triggered on /new command — saves previous session summary to LanceDB
  • Disabled by default (OpenClaw already has native .jsonl session persistence)
  • Configurable message count (default: 15)

See docs/openclaw-integration-playbook.md for deployment modes and /new verification.

Custom Slash Commands (e.g. /lesson)

Add to your CLAUDE.md, AGENTS.md, or system prompt:

markdown
## /lesson command
When the user sends `/lesson <content>`:
1. Use memory_store to save as category=fact (raw knowledge)
2. Use memory_store to save as category=decision (actionable takeaway)
3. Confirm what was saved

## /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

Iron Rules for AI Agents

Copy the block below into your AGENTS.md so your agent enforces these rules automatically.

markdown
## Rule 1 — Dual-layer memory storage
Every pitfall/lesson learned → IMMEDIATELY store TWO memories:
- Technical layer: Pitfall: [symptom]. Cause: [root cause]. Fix: [solution]. Prevention: [how to avoid]
  (category: fact, importance >= 0.8)
- Principle layer: Decision principle ([tag]): [behavioral rule]. Trigger: [when]. Action: [what to do]
  (category: decision, importance >= 0.85)

## Rule 2 — LanceDB hygiene
Entries must be short and atomic (< 500 chars). No raw conversation summaries or duplicates.

## Rule 3 — Recall before retry
On ANY tool failure, ALWAYS memory_recall with relevant keywords BEFORE retrying.

## Rule 4 — Confirm target codebase
Confirm you are editing memory-lancedb-pro vs built-in memory-lancedb before changes.

## Rule 5 — Clear jiti cache after plugin code changes
After modifying .ts files under plugins/, MUST run rm -rf /tmp/jiti/ BEFORE openclaw gateway restart.

Database Schema

LanceDB table memories:

Field Type Description
id string (UUID) Primary key
text string Memory text (FTS indexed)
vector float[] Embedding vector
category string Storage category: preference / fact / decision / entity / reflection / 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

Common metadata keys in v1.1.0: l0_abstract, l1_overview, l2_content, memory_category, tier, access_count, confidence, last_accessed_at

Note on categories: The top-level category field uses 6 storage categories. The 6-category semantic labels from Smart Extraction (profile / preferences / entities / events / cases / patterns) are stored in metadata.memory_category.

Troubleshooting

"Cannot mix BigInt and other types" (LanceDB / Apache Arrow)

On LanceDB 0.26+, some numeric columns may be returned as BigInt. Upgrade to memory-lancedb-pro >= 1.0.14 — this plugin now coerces values using Number(...) before arithmetic.


Hook Adaptation (OpenClaw 2026.3+)

Starting with v1.1.0-beta.9, the plugin's lifecycle hooks have been updated for compatibility with the refactored OpenClaw plugin system.

What changed

Hook Before After Why
Auto-recall before_agent_start before_prompt_build (priority 10) before_agent_start is deprecated; before_prompt_build is the recommended hook for prompt mutation
Reflection invariants before_agent_start before_prompt_build (priority 12) Same reason as above
Reflection derived focus before_prompt_build before_prompt_build (priority 15) Unchanged event, added explicit priority
All other lifecycle hooks unchanged unchanged agent_end, after_tool_call, session_end, message_received, before_message_write

Hook API distinction

OpenClaw exposes two hook registration methods. They write to different registries:

Method Registry Dispatch Use for
api.on(event, handler, opts) registry.typedHooks Dispatched by the lifecycle hook runner Lifecycle events: before_prompt_build, agent_end, after_tool_call, session_end, message_received, before_message_write
api.registerHook(event, handler, opts) registry.hooks Dispatched by the internal hook system Command/bootstrap events: command:new, command:reset, agent:bootstrap

Using the wrong method causes hooks to register silently without firing. This plugin uses api.on() for all lifecycle hooks and api.registerHook() for command hooks.

Verifying hooks after install

bash
openclaw plugins info memory-lancedb-pro

You should see:

text
Legacy before_agent_start: no

Typed hooks:
  agent_end
  before_message_write
  before_prompt_build (priority 10)
  message_received

Custom hooks:
  memory-lancedb-pro-session-memory: command:new

If Legacy before_agent_start: yes appears, you are running an older version of the plugin.

Migration from older versions

If you are upgrading from v1.1.0-beta.8 or earlier:

  1. Replace the plugin files (copy or openclaw plugins install)
  2. Clear the jiti cache: rm -rf /tmp/jiti/
  3. Restart the gateway: openclaw gateway restart
  4. Verify: openclaw plugins info memory-lancedb-pro should show Legacy before_agent_start: no

No config changes or data migration required. All existing memories, scopes, and settings are preserved.

OpenClaw version requirements

  • Minimum: OpenClaw 2026.3.22
  • Recommended: OpenClaw latest (2026.3.23+)

This version uses before_prompt_build hooks (replacing the deprecated before_agent_start), which requires OpenClaw 2026.3.22 or later. Running openclaw doctor --fix after upgrading will automatically migrate plugin config (e.g. minimax-portal-auth → minimax, Brave search as a standalone plugin).

To upgrade OpenClaw:

bash
npm update -g openclaw
openclaw --version    # verify >= 2026.3.22
openclaw doctor --fix # resolve any stale config after upgrade

Documentation

Document Description
OpenClaw Integration Playbook Deployment modes, verification, regression matrix
Memory Architecture Analysis Full architecture deep-dive
CHANGELOG v1.1.0 v1.1.0 behavior changes and upgrade rationale
Release Checklist Package preflight, publish dry run, and post-publish smoke checks
Long-Context Chunking Chunking strategy for long documents

Beta: Smart Memory v1.1.0

Status: Beta — available via npm i memory-lancedb-pro@beta. Stable users on latest are not affected.

Feature Description
Smart Extraction LLM-powered 6-category extraction with L0/L1/L2 metadata. Falls back to regex when disabled.
Lifecycle Scoring Weibull decay integrated into retrieval — high-frequency and high-importance memories rank higher.
Tier Management Three-tier system (Core → Working → Peripheral) with automatic promotion/demotion.

Feedback: GitHub Issues · Revert: npm i memory-lancedb-pro@latest


Dependencies

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

Contributors









Full list: Contributors

Star History

License

MIT


My WeChat QR Code


Overview (`examples/new-session-distill/README.md`)

This example shows a non-blocking /new distillation pipeline:

  • Trigger: command:new (when you type /new)
  • Hook: enqueue a small JSON task file (fast, no LLM calls)
  • Worker: a user-level systemd service watches the inbox and runs Gemini Map-Reduce over the session JSONL transcript
  • Storage: write high-signal, atomic lessons into LanceDB Pro via openclaw memory-pro import
  • Notify: send a notification message (optional)

Files included:

  • hook/enqueue-lesson-extract/ — OpenClaw workspace hook
  • worker/lesson-extract-worker.mjs — Map-Reduce extractor + importer + notifier
  • worker/systemd/lesson-extract-worker.service — user systemd unit

You must provide:

  • GEMINI_API_KEY in an env file loaded by systemd

Install steps are documented in the main repo README.


CHANGELOG V1.1.0 (`docs/CHANGELOG-v1.1.0.md`)

memory-lancedb-pro v1.1.0 — 智能记忆增强

日期: 2026-03-06
作者: CJY
概述: 基于对 AI Agent 记忆系统的深入理解,对记忆的写入质量、生命周期管理和去重能力进行了全面改进与完善


一、改进动机

原有记忆系统在检索侧表现优异(Vector+BM25 混合检索、cross-encoder 重排序、多维评分),但在以下方面存在提升空间:

  • 记忆写入质量:依赖正则表达式触发捕获,容易漏捕有价值信息或误捕噪声
  • 记忆结构层次:扁平文本存储,缺乏分层索引能力
  • 记忆生命周期:简单时间衰减,无法模拟人类记忆的遗忘与强化规律
  • 去重能力:仅基于向量相似度的粗粒度去重,缺乏语义级判断

本次改进针对这三个维度进行了系统性增强。


二、变更摘要

改进维度 核心变更 效果
智能提取 LLM 驱动的 6 类别提取 + L0/L1/L2 分层存储 记忆写入更精准、结构更丰富
生命周期管理 Weibull 衰减模型 + 三层晋升/降级 重要记忆持久保留,过时记忆自然淡化
智能去重 向量预过滤 + LLM 语义决策 避免冗余记忆,支持信息演化合并

当前落地状态(2026-03-06)

以下能力已接入运行主路径,而不再只是"模块存在":

  • SmartExtractor 已挂到 agent_end,新写入默认产出 memory_category、tier、l0_abstract、l1_overview、l2_content
  • before_agent_start 自动召回后会回写 access_count 与 last_accessed_at
  • src/retriever.ts 已接入 decayEngine.applySearchBoost(),检索结果按生命周期分数重排
  • tierManager 已接入 recall 后维护流程,根据 recall 计数和 lifecycle score 回写 tier 变更
  • memory_store、regex fallback、迁移、session memory、upgrade 都统一写入 smart metadata
  • openclaw.plugin.json 已暴露 decay / tier 配置项
  • 生命周期回归测试已加入 npm test

仍保留的兼容路径:

  • 当 lifecycle decay 未启用或不可用时,retriever 仍可回退到旧的 Recency Boost → Importance Weight → Time Decay 排序链
  • 旧格式数据仍可读取,并可通过 openclaw memory-pro upgrade 统一补齐 metadata

三、新增文件

1. `src/memory-categories.ts` — 6 类别分类系统

设计了语义明确的记忆分类体系,将记忆分为两大类六小类:

  • 用户记忆:profile(身份属性)、preferences(偏好习惯)、entities(持续存在的实体)、events(发生的事件)
  • Agent 记忆:cases(问题-解决方案对)、patterns(可复用的处理流程)

每个类别有不同的合并策略:

  • profile → 始终合并(用户身份信息持续累积)
  • preferences / entities / patterns → 支持智能合并
  • events / cases → 仅新增或跳过(独立记录,保留历史完整性)

2. `src/llm-client.ts` — LLM 客户端

封装了 LLM 调用接口,专注于结构化 JSON 输出:

  • 复用现有 OpenAI SDK 依赖,零新增包
  • 内置 JSON 容错解析:支持 markdown 代码块包裹和平衡大括号提取
  • 低温度 (0.1) 保证输出一致性
  • 30 秒超时保护,失败时优雅降级

3. `src/extraction-prompts.ts` — 记忆提取提示模板

精心设计了 3 个提示模板:

函数 用途
buildExtractionPrompt() 从对话中提取 6 类别 L0/L1/L2 记忆,含 few-shot 示例
buildDedupPrompt() CREATE / MERGE / SKIP 去重决策
buildMergePrompt() 将新旧记忆合并为三层结构

提取提示包含完整的记忆价值判断标准、类别决策逻辑表、常见混淆澄清规则和 6 个 few-shot 示例。


4. `src/smart-extractor.ts` — 智能提取管线

实现了完整的 LLM 驱动提取流水线:

text
对话文本 → LLM 提取 → 候选记忆 → 向量去重 → LLM 决策 → 持久化

核心设计:

  • 两阶段去重:先用向量相似度(阈值 0.7)快速筛选候选,再用 LLM 进行语义级判断
  • 类别感知合并:不同类别应用不同合并策略
  • L0/L1/L2 三层存储:L0 一句话索引用于检索注入,L1 结构化摘要用于精读,L2 完整叙述用于深度回顾
  • 向后兼容:新增的 6 类别自动映射到已有的 5 类别存储,L0/L1/L2 存储在 metadata JSON 中
  • 按类别设定重要度:profile (0.9) > patterns (0.85) > cases/preferences (0.8) > entities (0.7) > events (0.6)

5. `src/decay-engine.ts` — Weibull 衰减引擎

基于认知心理学中的记忆遗忘曲线研究,实现了复合衰减模型:

复合分数 = 时效权重 × 时效 + 频率权重 × 频率 + 内在权重 × 内在价值

三个分量:

分量 机制 含义
时效 (recency) Weibull 拉伸指数衰减 exp(-λt^β) 越久远的记忆衰减越快
频率 (frequency) 对数饱和曲线 + 时间加权 越常被访问的记忆越活跃
内在价值 (intrinsic) importance × confidence 高价值记忆天然抵抗遗忘

层级特定的衰减形状 (β 参数):

  • Core (β=0.8):亚指数衰减 → 遗忘极慢,衰减地板 0.9
  • Working (β=1.0):标准指数衰减,衰减地板 0.7
  • Peripheral (β=1.3):超指数衰减 → 遗忘加速,衰减地板 0.5

关键特性:

  • 重要性调制半衰期:effectiveHL = halfLife × exp(μ × importance),重要记忆持续更久
  • 搜索结果加权:检索时自动应用衰减加权,让活跃记忆排名更高
  • 过期识别:识别 composite < 0.3 的过期记忆

6. `src/tier-manager.ts` — 三层晋升/降级管理器

模拟人类记忆的多级存储模型:

text
Peripheral(外围) ⟷ Working(工作) ⟷ Core(核心)

晋升条件:

方向 条件
Peripheral → Working 访问次数 ≥ 3 且 衰减分数 ≥ 0.4
Working → Core 访问次数 ≥ 10 且 衰减分数 ≥ 0.7 且 重要度 ≥ 0.8

降级条件:

方向 条件
Working → Peripheral 衰减分数 < 0.15 或(年龄 > 60 天且访问次数 < 3)
Core → Working 衰减分数 < 0.15 且 访问次数 < 3(极少触发)

7. `src/smart-metadata.ts` — Smart metadata 归一化辅助模块

统一新老写入入口的生命周期字段,确保所有记忆路径产出一致的 metadata 结构:

  • 统一补齐 memory_category、tier、l0_abstract、l1_overview、l2_content
  • 统一处理 access_count、confidence、last_accessed_at
  • 将存储记录转换为 lifecycle scoring 所需的 DecayableMemory
  • 为迁移、upgrade、tool-store、regex fallback 提供同一套默认值与兼容逻辑

8. `src/memory-upgrader.ts` — 旧记忆升级器

将旧格式记忆(无 L0/L1/L2 / 5 类别)批量升级为新智能记忆格式,统一生命周期管理:

  • 反向类别映射:fact→profile/cases(含启发式+LLM 判断)、preference→preferences、entity→entities、decision→events、other→patterns
  • L0/L1/L2 生成:LLM 模式(推荐)或 无 LLM 模式(首句截取+原文保留)
  • 元数据补全:自动填充 tier: "working"、access_count: 0、confidence: 0.7
  • 批量处理:支持 --batch-size、--limit、--dry-run 控制
  • 启动检测:插件启动 5 秒后自动检测旧记忆数量,日志提示升级

四、修改文件

`index.ts` — 插件入口

新增导入

typescript
import { SmartExtractor } from "./src/smart-extractor.js";
import { createLlmClient } from "./src/llm-client.js";
import { createDecayEngine, DEFAULT_DECAY_CONFIG } from "./src/decay-engine.js";
import { createTierManager, DEFAULT_TIER_CONFIG } from "./src/tier-manager.js";

新增配置项

typescript
smartExtraction?: boolean;    // 是否启用 LLM 智能提取(默认 true)
llm?: {
  apiKey?: string;            // LLM API Key(默认复用 embedding.apiKey)
  model?: string;             // LLM 模型(默认 gpt-4o-mini)
  baseURL?: string;           // LLM API 端点
};
extractMinMessages?: number;  // 最少消息数才触发提取(默认 2)
extractMaxChars?: number;     // 送入 LLM 的最大字符数(默认 8000)

`agent_end` 钩子改进

  • 当 smartExtraction 启用时,优先使用 SmartExtractor 进行 LLM 6 类别提取
  • 当消息数不足或 SmartExtractor 未初始化时,降级回原有正则触发逻辑
  • 提取完成后输出统计日志:smart-extracted N created, M merged, K skipped

`before_agent_start` 钩子改进

  • 注入的记忆上下文现在显示 L0 摘要而非原始文本
  • 新增 6 类别标签(如 [preferences:global])
  • 新增层级标记([C]ore / [W]orking / [P]eripheral)
  • 自动召回后回写 access_count 与 last_accessed_at

启动时旧记忆检测

  • 插件启动 5 秒后异步扫描旧格式记忆数量
  • 如发现旧格式记忆,在日志中输出提示:Run 'openclaw memory-pro upgrade' to convert them.

`src/retriever.ts` — 检索器

  • 接入 decayEngine.applySearchBoost(),检索结果按生命周期分数重排
  • 当 lifecycle decay 未启用或不可用时,可回退到旧的 Recency Boost → Importance Weight → Time Decay 排序链

`openclaw.plugin.json` — 插件配置清单

  • 暴露 decay / tier 配置项,允许用户自定义衰减参数和晋升阈值

`cli.ts` — CLI 命令

新增 `memory-pro upgrade` 命令

bash
openclaw memory-pro upgrade [--dry-run] [--batch-size N] [--no-llm] [--limit N] [--scope SCOPE]
  • --dry-run:仅统计旧记忆数量,不修改数据
  • --batch-size:每批处理数量(默认 10)
  • --no-llm:不调用 LLM,使用简单规则生成 L0/L1/L2
  • --limit:最大升级数量
  • --scope:仅升级指定 scope 的记忆

五、配置指南

最简配置(复用已有 API Key)

json
{
  "embedding": {
    "apiKey": "${OPENAI_API_KEY}",
    "model": "text-embedding-3-small"
  },
  "smartExtraction": true
}

完整配置

json
{
  "embedding": {
    "apiKey": "${OPENAI_API_KEY}",
    "model": "text-embedding-3-small"
  },
  "smartExtraction": true,
  "llm": {
    "apiKey": "${OPENAI_API_KEY}",
    "model": "gpt-4o-mini",
    "baseURL": "https://api.openai.com/v1"
  },
  "extractMinMessages": 2,
  "extractMaxChars": 8000
}

禁用智能提取

json
{
  "smartExtraction": false
}

六、向后兼容性

方面 兼容方式
LanceDB Schema 新字段存储在 metadata JSON 中,不修改表结构
记忆类别 新 6 类别自动映射到原有 5 类别
混合检索 Vector+BM25 检索管线完全保留
去重逻辑 仅在 smartExtraction: true 时生效
已有数据 旧记忆正常读取,新记忆额外携带 L0/L1/L2 元数据
配置 全部新增配置项均有默认值,零配置即可使用
旧记忆升级 memory-pro upgrade 命令一键升级为新格式

Lock Management (`docs/lock-management.md`)

Lock Management

memory-lancedb-pro protects LanceDB writes with a cross-process file lock based on
proper-lockfile. The lock target is .memory-write.lock inside the configured
database directory, and the transient lock artifact is .memory-write.lock.lock.

When The Built-In File Lock Is Enough

Use the default file lock for:

  • a single OpenClaw gateway process
  • multiple agents writing through the same gateway process
  • multiple local processes that share the same local filesystem path

The store also batches concurrent bulkStore() calls before taking the write
lock, so high-throughput auto-capture paths avoid one lock acquisition per
memory item.

Multi-Machine Or Container Deployments

The file lock only coordinates processes that can see the same lock target on a
filesystem with reliable lock-directory semantics. For multi-machine,
multi-container, or network-filesystem deployments, verify this before relying on
the default lock:

bash
openclaw memory-pro stats --json
ls -la "$(dirname "$MEMORY_LANCEDB_PRO_DB_PATH")"

If each process has its own local database directory, no lock can protect writes
across those processes because they are not writing to the same LanceDB store.

Redis Status

Redis is not required for single-gateway or same-filesystem deployments. The
plugin enables Redis locking when locking.redis.enabled is true, when
redisUrl/locking.redis.url is set, or when MEMORY_LANCEDB_REDIS_URL is
present in that process environment. Every writer that shares a LanceDB store
must use the same Redis lock configuration; mixing Redis-locked writers with
writers that only use the local file lock creates separate lock domains.

When Redis locking is enabled, every LanceDB write and index-maintenance
mutation uses the Redis lock domain. Redis connection or lock-client
availability failures fail writes closed instead of falling back to a local file
lock.

If you operate multiple independent writers, prefer one of these approaches:

  • route writes through one OpenClaw gateway
  • place the LanceDB directory on a filesystem whose lock-directory behavior is
    known to work with proper-lockfile
  • add an explicit external write coordinator before enabling multiple writers

Do not use a no-op lock fallback for write paths. If an external coordinator is
required but unavailable, fail the write and retry after the coordinator is
healthy rather than switching that writer into a separate local lock domain.

Troubleshooting Lock Contention

Symptoms of lock contention include slow memory writes, delayed auto-capture, or
warnings about stale .memory-write.lock.lock artifacts.

Checklist:

  1. Confirm all writers use the same dbPath.
  2. Confirm old .memory-write.lock.lock artifacts are cleaned up by the store.
  3. Prefer bulkStore() for batch writes instead of repeated store() calls.
  4. Avoid multiple independent gateway processes writing to separate copies of the
    same intended memory corpus.

Long Context Chunking (`docs/long-context-chunking.md`)

Long Context Chunking

Overview

The long context chunking system automatically handles documents that exceed embedding model context limits by splitting them into manageable chunks and computing averaged embeddings.

Problem Solved

When embedding very long documents or messages, you might encounter errors like:

text
Input length exceeds context length: 12453 tokens. Maximum length: 8192 tokens.

This plugin now handles such cases gracefully by:

  1. Detecting context length errors before they cause failures
  2. Automatically splitting the document into overlapping chunks
  3. Embedding each chunk separately
  4. Computing an averaged embedding that preserves semantic meaning

How It Works

Chunking Strategy

The chunker uses a semantic-aware approach:

  • Splits at sentence boundaries when possible (better for preserving meaning)
  • Configurable overlap (default: 200 characters) to maintain context across chunks
  • Adapts to model context limits based on the embedding model
  • Forced splits at hard limits if sentence boundaries are not found

Chunking Flow

text
Long Document
    │
    ├── 8192+ characters ──┐
                            │
                            ▼
                ┌─────────────────┐
                │  Detect Overflow │
                └────────┬────────┘
                         │
                         ▼
                ┌─────────────────┐
                │  Split into     │
                │  Overlapping     │
                │  Chunks          │
                └────────┬────────┘
                         │
    ┌────────────────────┼────────────────────┐
    │                    │                    │
    ▼                    ▼                    ▼
┌────────┐         ┌────────┐         ┌────────┐
│ Chunk 1│         │ Chunk 2│         │ Chunk 3│
│  [1-2k]│         │[1.8k-3.8k]│    │[3.6k-5.6k]│
└───┬────┘         └───┬────┘         └───┬────┘
    │                  │                  │
    ▼                  ▼                  ▼
Embedding          Embedding          Embedding
    │                  │                  │
    └──────────────────┼──────────────────┘
                       │
                       ▼
              Compute Average
                       │
                       ▼
              Final Embedding

Configuration

Default Settings

The chunker automatically adapts to your embedding model:

  • maxChunkSize: 70% of model context limit (e.g., 5734 for 8192-token model)
  • overlapSize: 5% of model context limit
  • minChunkSize: 10% of model context limit
  • semanticSplit: true (prefer sentence boundaries)
  • maxLinesPerChunk: 50 lines

Disabling Auto-Chunking

If you prefer to handle chunking manually or want the model to fail on long documents:

json
{
  "plugins": {
    "entries": {
      "memory-lancedb-pro": {
        "enabled": true,
        "config": {
          "embedding": {
            "apiKey": "${JINA_API_KEY}",
            "model": "jina-embeddings-v5-text-small",
            "chunking": false  // Disable auto-chunking
          }
        }
      }
    }
  }
}

Custom Chunking Parameters

For advanced users who want to tune chunking behavior:

json
{
  "plugins": {
    "entries": {
      "memory-lancedb-pro": {
        "enabled": true,
        "config": {
          "embedding": {
            "autoChunk": {
              "maxChunkSize": 2000,      // Characters per chunk
              "overlapSize": 500,          // Overlap between chunks
              "minChunkSize": 500,         // Minimum acceptable chunk size
              "semanticSplit": true,       // Prefer sentence boundaries
              "maxLinesPerChunk": 100      // Max lines before forced split
            }
          }
        }
      }
    }
  }
}

Supported Models

The chunker automatically adapts to these embedding models:

Model Context Limit Chunk Size Overlap
Jina jina-embeddings-v5-text-small 8192 5734 409
OpenAI text-embedding-3-small 8192 5734 409
OpenAI text-embedding-3-large 8192 5734 409
Gemini gemini-embedding-001 2048 1433 102

Performance Considerations

Token Savings

  • Without chunking: 1 failed embedding (retries required)
  • With chunking: 3-4 chunk embeddings (1 avg result)
  • Net cost increase: ~3x for long documents (>8k tokens)
  • Trade-off: Gracefully handling vs. processing smaller documents

Caching

Chunked embeddings are cached by their original document hash, so:

  • Subsequent requests for the same document get the cached averaged embedding
  • Cache hit rate improves as long documents are processed repeatedly

Processing Time

  • Small documents (<4k chars): No chunking, same as before
  • Medium documents (4k-8k chars): No chunking, same as before
  • Long documents (>8k chars): ~100-200ms additional chunking overhead

Logging & Debugging

Enable Debug Logging

To see chunking in action, you can check the logs:

text
Document exceeded context limit (...), attempting chunking...
Split document into 3 chunks for embedding
Successfully embedded long document as 3 averaged chunks

Common Scenarios

Scenario 1: Long memory text

  • When a user's message or system prompt is very long
  • Automatically chunked before embedding
  • No error thrown, memory is still stored and retrievable

Scenario 2: Batch embedding long documents

  • If some documents in a batch exceed limits
  • Only the long ones are chunked
  • Successful documents processed normally

Troubleshooting

Chunking Still Fails

If you still see context length errors:

  1. Verify model: Check which embedding model you're using
  2. Increase minChunkSize: May need smaller chunks for some models
  3. Disable autoChunk: Handle chunking manually with explicit split

Too Many Small Chunks

If chunking creates many tiny fragments:

  1. Increase minChunkSize: Larger minimum chunk size
  2. Reduce overlap: Less overlap between chunks means more efficient chunks

Embedding Quality Degradation

If chunked embeddings seem less accurate:

  1. Increase overlap: More context between chunks preserves relationships
  2. Use smaller maxChunkSize: Split into more, smaller overlapping pieces
  3. Consider hierarchical approach: Use a two-pass retrieval (chunk → document → full text)

Future Enhancements

Planned improvements:

  • Hierarchical chunking: Chunk → document-level embedding
  • Sliding window: Different overlap strategies per document complexity
  • Smart summarization: Summarize chunks before averaging for better quality
  • Context-aware overlap: Dynamic overlap based on document complexity
  • Async chunking: Process chunks in parallel for batch operations

Technical Details

Algorithm

  1. Detect overflow: Check if document exceeds maxChunkSize
  2. Split semantically: Find sentence boundaries within target range
  3. Create overlap: Include overlap with previous chunk's end
  4. Embed in parallel: Process all chunks simultaneously
  5. Average the result: Compute mean embedding across all chunks

Complexity

  • Time: O(n × k) where n = number of chunks, k = average chunk processing time
  • Space: O(n × d) where d = embedding dimension

Edge Cases

Case Handling
Empty document Returns empty embedding immediately
Very small documents No chunking, normal processing
Perfect boundaries Split at sentence ends, no truncation
No boundaries found Hard split at max position
Single oversized chunk Process as-is, let provider error
All chunks too small Last chunk takes remaining text

References


This feature was added to handle long-context documents gracefully without losing memory quality.


Memory Architecture Analysis (`docs/memory_architecture_analysis.md`)

`memory-lancedb-pro` 记忆架构分析

更新时间:2026-03-09
基准:当前仓库中的 README.md、openclaw.plugin.json、index.ts、src/*、cli.ts
结论:当前版本已经形成完整的“写入 -> 存储 -> 检索 -> 生命周期维护 -> 运维工具”闭环;智能提取、嵌入噪声检测、生命周期衰减、Tier 晋升/降级、迁移升级、CLI 与 Agent Tools 都已纳入同一主架构。


一、架构判断摘要

1.1 当前真实主路径

当前版本不是“在旧向量记忆插件上补了几个实验模块”,而是一个完整的 OpenClaw Memory Plugin:

  • index.ts 负责插件注册、配置解析、Hook 装配、CLI 装配、后台服务装配
  • src/store.ts 负责 LanceDB 表初始化、CRUD、向量检索、FTS/BM25、metadata 局部回写
  • src/embedder.ts 负责统一 Embedding Provider 适配、任务感知 embedding、长文本 chunking、缓存
  • src/retriever.ts 负责混合检索、rerank、长度归一化、生命周期重排、噪声过滤、去重多样性
  • src/smart-extractor.ts 负责 LLM 智能提取、嵌入噪声预过滤、两阶段去重、语义合并、新格式写入
  • src/noise-prototypes.ts 负责嵌入噪声原型库(语言无关噪声检测 + LLM 反馈学习闭环)
  • src/decay-engine.ts + src/tier-manager.ts 负责 recall 后的生命周期评分与 tier 演化
  • src/tools.ts 和 cli.ts 分别提供 Agent Tool 面与运维 CLI 面

1.2 当前版本最重要的架构特征

  • 智能提取已经进入默认写入主路径,regex 仅作为兜底
  • 生命周期衰减已经进入默认检索主路径,不再是“代码里有对象但没接上”
  • smart metadata 已成为全系统的统一中间层
  • 旧 5 类 store category 与新 6 类 memory category 处于“双层兼容模型”
  • auto-recall、tool recall、CLI、迁移、升级、session memory 都共享同一份 LanceDB 数据平面

1.3 仍保留的兼容层

  • 无 FTS 时自动回退到 vector-only / lexical fallback
  • 无 lifecycle decay 时回退到旧的 recency boost + importance weight + time decay
  • legacy memory 仍能读;可通过 memory-pro upgrade 补齐 smart metadata
  • 存储表 schema 未拆分成多张新表,而是保留单表 + metadata JSON 扩展

二、总体架构图

text
/* Detailed source-code truncated for AI context efficiency. */

三、入口层:`index.ts` 是总装配器

index.ts 不是简单导出插件对象,而是整个系统的总装配器,负责把各模块接入 OpenClaw:

  • 解析配置并做 env var 展开
  • 创建 MemoryStore、Embedder、MemoryRetriever、ScopeManager
  • 可选初始化 SmartExtractor
  • 注册 Agent Tools
  • 注册 memory-pro CLI
  • 注册 before_agent_start、agent_end、command:new
  • 注册后台 service:启动检查、legacy upgrade 提示、自动备份

3.1 运行时默认值

按当前实现,关键默认行为如下:

  • smartExtraction: 默认开启
  • extractMinMessages: 默认 2
  • autoCapture: 默认开启
  • autoRecall: 默认关闭
  • captureAssistant: 默认关闭
  • enableManagementTools: 默认关闭
  • sessionMemory: 只有显式 sessionMemory.enabled === true 才注册 Hook,运行时默认关闭

3.2 服务层职责

插件 registerService().start() 不是业务核心链路,但它负责运维闭环:

  • 异步执行 embedder.test() 与 retriever.test(),避免阻塞 Gateway 启动
  • 启动后约 5 秒检查 legacy memory 数量并输出 upgrade 提示
  • 启动后 1 分钟做一次 JSONL 备份,此后每 24 小时做一次
  • 停止时清理定时器

这意味着该插件不仅有“读写能力”,也有“自检 + 自提示 + 备份”的运维能力。


四、写入架构:从对话到长期记忆

4.1 写入入口清单

当前写入来源不止一条:

  • agent_end 自动捕获
  • memory_store Agent Tool 手工写入
  • memory_update Agent Tool 原地更新
  • command:new 的 session summary 写入
  • memory-pro import
  • memory-pro migrate run
  • memory-pro upgrade
  • memory-pro reembed

其中自动捕获是最核心的在线写入链路。

4.2 自动捕获写入主路径

当前自动捕获的真实入口已经不是“裸 agent_end.messages 直读”,而是一个轻量的运行时适配层:

text
message_received
  -> 归一化实时入站文本(去 addressing / 去 OpenClaw 注入前缀)
  -> 按 conversationKey 暂存最近少量原始用户文本

agent_end
  -> 从 event.messages 提取 user/assistant 文本
  -> 再做同一套归一化(去 recall block / inbound metadata / session reset prompt / addressing)
  -> 优先消费 pending ingress texts
  -> 若无 pending ingress,则退回到 session snapshot 的“新增文本增量”
  -> 若只有显式 remember 指令,则可补上一条最近真实文本形成最小上下文
  -> 进入 smart extraction / regex fallback 主链

进入写入主链后的执行顺序是:

text
抽取并归一化文本(默认仅 `user`;当 `captureAssistant === true` 时也包含 `assistant`)
  -> 若 smartExtractor 可用:
       嵌入噪声预过滤 filterNoiseByEmbedding(texts)
       若所有文本被过滤 -> return(纯噪声输入)
       若清洗后消息数 >= extractMinMessages:
            SmartExtractor.extractAndPersist()
            若 created > 0 或 merged > 0,则直接 return
            否则继续走 regex fallback
  -> shouldCapture() + detectCategory() + regex fallback
  -> buildSmartMetadata()
  -> store.store()

几个关键点:

  • 当前实现增加了一层“OpenClaw runtime 适配层”,用来消解 prependContext、inbound metadata、addressing、session snapshot 粒度等上游差异
  • 智能提取只有在产出持久化结果时,才会接管整个自动捕获路径
  • regex fallback 仍存在,但已经不再输出“半旧格式数据”
  • fallback 写入前仍做噪声过滤与重复检查
  • 每轮对话最多写入 3 条 fallback memory
  • 当前插件不会主动回读 session JSONL 或 LanceDB 历史来拼装捕获输入;运行时上下文只来自:
    • message_received 的短暂内存队列
    • agent_end.event.messages
    • 当前进程内的极小 recent-text 缓存
  • 这层适配是 OpenClaw runtime 通用策略,不绑定 Discord/Telegram 等具体渠道协议字段

4.3 SmartExtractor 主链

src/smart-extractor.ts 的核心流程是:

text
texts
  -> filterNoiseByEmbedding() 嵌入噪声预过滤
  -> conversationText
  -> LLM 抽取 CandidateMemory[]
  -> 逐条向量预筛
  -> LLM 判定 CREATE / MERGE / SKIP
  -> buildSmartMetadata()
  -> store.store() / store.update()
  -> 若 zero candidates -> learnAsNoise() 反馈到噪声库

当前特征:

  • 候选记忆最多处理 5 条
  • 第一阶段去重使用 vectorSearch(..., threshold=0.7)
  • 第二阶段去重交给 LLM 做语义决策
  • profile 类记忆永远优先走 merge
  • events / cases 更偏 append-only

4.4 6 类智能分类与 5 类存储分类并存

这是当前架构最重要的兼容设计之一。

智能分类

定义在 src/memory-categories.ts:

  • profile
  • preferences
  • entities
  • events
  • cases
  • patterns

存储分类

底层 LanceDB 主字段 category 仍保留旧 5 类:

  • preference
  • fact
  • decision
  • entity
  • other

映射关系

SmartExtractor 写入时会做兼容映射:

智能分类 存储分类
profile fact
preferences preference
entities entity
events decision
cases fact
patterns other

因此:

  • 结构化语义分类保存在 metadata.memory_category
  • 向后兼容的粗粒度分类保存在 entry.category

也正因为如此,CLI / Tool 里的 category 过滤目前仍以旧 5 类为准。

4.5 `memory_update` 的定位

memory_update 是新版里值得单独强调的能力:

  • 支持按完整 UUID 或 8+ 前缀定位 memory
  • 文本更新时自动重新 embedding
  • 保留原始 timestamp
  • 适合修正陈旧事实,而不是“删旧建新”

这意味着系统现在支持“记忆更正”而不只是“记忆追加”。

4.6 嵌入噪声检测:NoisePrototypeBank

src/noise-prototypes.ts 提供了语言无关的噪声检测能力,替代基于正则的方式:

  • 内置 ~15 条多语言噪声原型(回忆查询、agent 否认、问候语)
  • 插件启动时嵌入所有原型并缓存向量(异步非阻塞)
  • auto-capture 管道中,SmartExtractor 的 filterNoiseByEmbedding() 在 LLM 提取前执行
  • 文本长度分层策略:<=8 字符跳过(防误判)、8-300 字符做嵌入检查、>300 字符跳过(长文本非噪声)
  • 默认相似度阈值 0.82

LLM 反馈闭环:

当 LLM 提取返回零候选时,learnAsNoise() 将该文本的嵌入向量加入噪声库:

text
文本 -> 嵌入检查 -> [未命中] -> LLM 提取 -> 返回 {memories: []} 
                                          |
                              将该文本向量加入噪声库
                                          |
                          下次类似文本直接被嵌入检查拦截
  • 去重:新向量与已有原型相似度 >= 0.95 则跳过
  • 容量上限:最多学习 200 条,超限淘汰最旧的学习原型(保留内置原型)
  • 仅在 smartExtraction !== false 时激活,不影响纯 regex 路径

五、统一元数据层:`smart-metadata.ts` 是系统中枢

src/smart-metadata.ts 是整套架构的真正收敛点。

它负责:

  • 解析 legacy metadata
  • 用 entry 本身补齐缺省字段
  • 将新旧 memory 归一化成统一 metadata 结构
  • 将 entry 转换为 lifecycle scoring 所需的 LifecycleMemory

5.1 当前 metadata 常见字段

字段 含义
memory_category 新 6 类语义分类
tier core / working / peripheral
l0_abstract 短句索引,默认也是主搜索文本
l1_overview 结构化摘要
l2_content 长叙述内容
access_count 被 recall 的次数
confidence 抽取/合并置信度
last_accessed_at 最近被 recall 时间
source_session 来源 session key
type 特殊类型,如 session-summary
tier_updated_at tier 最近更新时间
migratedFrom / originalId 迁移/升级来源信息

5.2 为什么 metadata 是核心设计

当前实现没有把 L0/L1/L2、tier、access_count 单独提升为 LanceDB 表字段,而是统一放进 metadata JSON。这样做带来四个结果:

  • 不需要重建 LanceDB 主表
  • legacy entry 能平滑升级
  • store 层的 CRUD 复杂度保持可控
  • lifecycle、smart extraction、迁移、session memory 可以共享同一格式

六、存储层:`MemoryStore` 不只是 CRUD

src/store.ts 的职责比 README 表里写的更重。

6.1 初始化阶段

MemoryStore 是 lazy-init 的:

  • 首次访问时连接 LanceDB
  • 若表不存在则创建 memories
  • 创建或检测 FTS index
  • 校验 vector dimension 是否匹配

因此 store 既是数据库访问层,也是 schema 守门层。

6.2 查询能力

它提供三种检索能力:

  • vectorSearch()
  • bm25Search()
  • lexicalFallbackSearch()

其中 BM25 路径是:

text
有 FTS index -> LanceDB search(query, "fts")
无 FTS / FTS 失败 -> lexicalFallbackSearch()

lexical fallback 不只匹配 entry.text,还会参考:

  • l0_abstract
  • l1_overview
  • l2_content

这意味着即使 FTS 不可用,smart metadata 仍然参与词法命中。

6.3 更新能力

当前 LanceDB 不支持真正的 in-place update,所以 store.update() 采用:

text
读旧行 -> 构造新 entry -> delete old -> add new

而 patchMetadata() 则是在这层之上封装的 metadata 局部更新入口,被以下链路复用:

  • recall 访问计数更新
  • tier 回写
  • 未来的 lifecycle 扩展字段更新

6.4 运维相关能力

store 层还承接了多项运维需求:

  • delete() 支持 UUID 与前缀删除
  • bulkDelete() 强制要求 filter,避免误删全库
  • importEntry() 保留源 id/timestamp,用于 reembed / migration
  • stats() 为 CLI 和管理工具提供聚合统计
  • hasId() 用于过滤 BM25 ghost entry

七、Embedding 层:Provider 适配 + Chunking + Cache

src/embedder.ts 在当前架构里不是简单的 OpenAI SDK 包装,而是完整的 embedding 抽象层。

7.1 主要能力

  • OpenAI-compatible provider 统一接入
  • taskQuery / taskPassage 任务感知 embedding
  • dimensions 透传
  • normalized 透传
  • LRU + TTL embedding cache
  • 长文本自动 chunking

7.2 长文本 chunking 的角色

src/chunker.ts 为 embedding 超长文本提供模型感知分块:

  • 超过上下文限制时触发
  • 按语义边界切块并带 overlap
  • 分块 embedding 后做平均向量聚合

这条能力对以下场景尤其重要:

  • session summary
  • 导入的长文档 memory
  • reembed/import 场景

从实现上看,embedder 当前默认开启 auto-chunking。


八、检索架构:混合检索已经是默认主线

src/retriever.ts 是当前系统的在线 recall 核心。

8.1 检索入口

当前有三类读取入口共用 retriever:

  • before_agent_start 自动召回
  • memory_recall Agent Tool
  • memory-pro search CLI

8.2 混合检索主链

在有 FTS 支持时,默认路径是:

text
embedQuery(query)
  -> vectorSearch
  -> bm25Search
  -> fusion
  -> rerank
  -> length normalization
  -> hard min score
  -> lifecycle decay boost / legacy time decay
  -> noise filter
  -> MMR diversity

更具体地说:

  1. 向量检索和 BM25 并行执行
  2. fuseResults() 以向量分数为主,BM25 命中提供确认性加权
  3. 可选 Cross-Encoder rerank,失败则降级为 cosine rerank
  4. 长文本进行长度惩罚
  5. 过低语义相关度结果直接硬过滤
  6. 生命周期分数再做最终重排
  7. 去噪与近重复打散

8.3 当前融合策略不是教科书式 RRF

README 把它描述为 hybrid fusion,但代码中的实际策略更偏“向量分数主导 + BM25 奖励”:

  • 命中向量时,以向量分数为主
  • BM25 命中可提供额外 boost
  • 纯 BM25 命中允许直接进入结果集
  • 对高 BM25 精确词法命中设置 preservation floor,避免被 reranker 错杀

这是为了照顾:

  • 配置项、ID、token、环境变量等符号型检索
  • 中英混合 query
  • reranker 对符号查询不稳定的现实问题

8.4 当前排序链上的关键实现细节

  • hardMinScore 发生在 decay/time-decay 之前
  • lifecycle decay 在有 decayEngine 时替代旧的 recency/importance/time-decay 路径
  • applyMMRDiversity() 不是删除相似项,而是把相似项延后
  • BM25-only 结果会先用 store.hasId() 检查,避免 FTS 残留 ghost entry

九、生命周期闭环:现在已经接入业务运行时

src/decay-engine.ts 与 src/tier-manager.ts 在当前版本里已经不再是离线概念模型,而是运行时逻辑。

9.1 Decay Engine

Decay 的复合分数公式是:

text
composite = recencyWeight * recency
          + frequencyWeight * frequency
          + intrinsicWeight * intrinsic

其中:

  • recency: Weibull 拉伸指数衰减,半衰期受 importance 调制
  • frequency: 访问次数的对数饱和 + 最近访问模式奖励
  • intrinsic: importance * confidence

Tier 还会影响衰减形状:

Tier beta floor 含义
core 0.8 0.9 衰减最慢,搜索最低保留高
working 1.0 0.7 中性
peripheral 1.3 0.5 衰减最快

9.2 Tier Manager

Tier 迁移规则大致如下:

mermaid
graph LR
    P["Peripheral"] -->|"access >= 3 且 composite >= 0.4"| W["Working"]
    W -->|"access >= 10 且 composite >= 0.7 且 importance >= 0.8"| C["Core"]
    W -->|"composite < 0.15 或 高龄低访问"| P
    C -->|"极低 composite 且低访问"| W

9.3 生命周期触发点

当前需要特别区分两个 recall 路径:

auto-recall 路径

before_agent_start 在拿到 recall 结果后会执行完整闭环:

  1. patchMetadata(access_count + 1, last_accessed_at = now)
  2. 读取同 scope 的近期记忆
  3. decayEngine.scoreAll()
  4. tierManager.evaluateAll()
  5. 将 tier / tier_updated_at 回写

`memory_recall` Tool 路径

memory_recall 当前会:

  • 更新 access_count
  • 更新 last_accessed_at

但不会调用 runRecallLifecycle(),也就是说:

  • Tool recall 会积累访问数据
  • 真正的 tier 迁移维护目前仍只挂在 auto-recall 主链上

这是当前架构里一个重要而容易被忽略的边界。

9.4 session-summary 的特殊处理

sessionMemory 写入的 memory 会带 metadata.type = "session-summary"。
在 auto-recall 生命周期维护中,这类 memory 会被排除在 tier 评估之外,避免会话摘要挤占核心长期记忆层级。


十、读取注入层:auto-recall 的上下文安全模型

当 autoRecall === true 时,before_agent_start 会把 recall 结果注入到:

xml
<relevant-memories>
...
</relevant-memories>

几个值得注意的设计点:

  • 默认关闭,避免模型直接回显 memory block
  • 注入前先走 shouldSkipRetrieval(),避免问候语、小确认、emoji、slash 命令触发检索
  • 注入文本带 [UNTRUSTED DATA] 提示,防止把 memory 当指令执行
  • 显示内容优先使用 l0_abstract
  • 显示时会附上 category、scope、tier、分数与来源标记

因此 auto-recall 实际上已经包含:

  • 召回判断
  • 召回结果格式化
  • prompt injection 安全隔离
  • recall 后 lifecycle 驱动

十一、Scope 隔离:这是多 Agent 记忆的边界层

src/scopes.ts 负责 scope 体系与访问控制。

支持的 scope 形态:

  • global
  • agent:
  • project:
  • user:
  • custom:<name>

运行时规则:

  • agent 默认可见 global + agent:
  • 可通过 scopes.agentAccess 细化访问范围
  • Tool 与 Hook 都会在运行时解析 agentId,再做 scope 过滤

这意味着该插件已经是“多租户记忆系统”,而不是单用户单库的简单记忆表。


十二、工具面与 CLI 面:这不是附属功能,而是第二操作平面

12.1 Agent Tools

核心工具现在是 4 个:

  • memory_recall
  • memory_store
  • memory_forget
  • memory_update

可选管理工具:

  • memory_stats
  • memory_list

注意:

  • 核心 4 个默认注册
  • 管理工具只有 enableManagementTools === true 才注册

12.2 CLI

memory-pro 当前已经具备完整运维面:

  • version
  • list
  • search
  • stats
  • delete
  • delete-bulk
  • export
  • import
  • reembed
  • upgrade
  • migrate check
  • migrate run
  • migrate verify

其中几条尤其关键:

  • upgrade: 把 legacy memory 升级成 smart format
  • migrate: 从旧 memory-lancedb 迁移
  • reembed: 用新 embedding 模型重建向量但保留 ID/时间
  • delete-bulk: 带 scope/before 保护条件的批量删除

从架构角度看,这些 CLI 不是外部脚本,而是插件运行面的一部分。


十三、兼容与演进:迁移、升级、备份已经内建

13.1 迁移

src/migrate.ts 负责从旧版 memory-lancedb 导入数据:

  • 自动搜索常见 legacy DB 路径
  • 读取旧 memories 表
  • 迁移到新库
  • 同时补 smart metadata,而不是简单复制旧字段

13.2 升级

src/memory-upgrader.ts 负责对“已经在 Pro 库里但仍是旧格式”的 memory 做升级:

  • 统计 legacy memory 数量
  • 支持 LLM 模式与 no-LLM 模式
  • 为旧数据补全 L0/L1/L2、category、tier、confidence 等

13.3 自动备份

当前 service 会定时导出 JSONL 备份:

  • 启动后 1 分钟首次执行
  • 后续每 24 小时执行
  • 默认保留最近 7 份

这份备份更像“内容与 metadata 快照”,不是完整向量副本,因为 store.list() 默认不带 vectors。


十四、会话记忆与批处理蒸馏:两条扩展型摄入链路

14.1 Session Memory

command:new Hook 在启用时会:

  • 查找上一段 session JSONL
  • 抽取最近 N 条消息
  • 生成 session summary memory
  • 写入 LanceDB,并打上 type = session-summary

但当前 README 与代码都明确表达了一个操作建议:

  • 这条能力默认不启用
  • 因为大段 session summary 容易污染高质量检索

14.2 `jsonl_distill.py`

README 新增的批处理方案是另一条非常值得记录的架构支线:

  • 通过 scripts/jsonl_distill.py 增量读取 session JSONL
  • 过滤噪声
  • 用专门 distiller agent 提炼高信号 lesson
  • 最终通过 memory_store 或 memory-pro import 回灌主库

这条链路说明本项目现在已经从“在线对话记忆插件”延伸到“离线记忆蒸馏平台”。


十五、测试覆盖说明

当前与新架构强相关的测试包括:

  • test/smart-memory-lifecycle.mjs
  • test/retriever-rerank-regression.mjs
  • test/smart-extractor-branches.mjs
  • test/cli-smoke.mjs

这些测试分别覆盖:

  • legacy metadata 归一化
  • decay-aware retrieval 排序正确性
  • tier promotion / demotion
  • rerank 对强词法命中的保护
  • smart extractor 的 merge / skip 分支
  • CLI 的基础闭环

说明这套新架构已经不只是 README 层叙事,而是被纳入回归验证。


十六、核心文件职责索引

文件 当前职责
index.ts 插件总装配器:配置解析、Hook、Tool、CLI、Service、生命周期闭环
src/store.ts LanceDB 存储层:初始化、FTS、vector/BM25、CRUD、metadata patch
src/embedder.ts Embedding 抽象层:provider 适配、task embedding、chunking、cache
src/chunker.ts 长文本分块器
src/retriever.ts 混合检索、rerank、length norm、decay boost、MMR
src/smart-extractor.ts LLM 提取、嵌入噪声预过滤、两阶段去重、merge/create/skip、持久化
src/smart-metadata.ts metadata 归一化、兼容映射、lifecycle 视图转换
src/decay-engine.ts Weibull 衰减模型、搜索分数 boost
src/tier-manager.ts 三层记忆晋升/降级
src/scopes.ts 多 scope 隔离与 agent 访问控制
src/tools.ts Agent Tools 平面
cli.ts 运维 CLI 平面
src/migrate.ts 从旧插件迁移
src/memory-upgrader.ts 同库旧格式升级
src/noise-filter.ts 写入/检索噪声过滤(regex 规则)
src/noise-prototypes.ts 嵌入噪声原型库:语言无关噪声检测 + LLM 反馈学习
src/adaptive-retrieval.ts auto-recall 检索守卫

十七、一句话总结

memory-lancedb-pro 当前的真实架构可以概括为:

用 smart-metadata 把新旧 memory 统一到一套数据平面,用 SmartExtractor 提升写入质量,用 Retriever + Decay + Tier 提升召回质量,再用 Tools / CLI / Migration / Backup 把它补成一个可运营的长期记忆子系统。


Openclaw Dream Retrofit Report (`docs/openclaw-dream-retrofit-report.md`)

OpenClaw Dream Retrofit Final Report

Date: 2026-05-23
Artifact path: docs/openclaw-dream-retrofit-report.md

No explicit output artifact path was present in the environment or repository metadata, so this report is written as a versioned repo artifact under docs/.

Phase Status

Phase Status Notes
Phase 0: memory capability bootstrap Complete Registered api.registerMemoryCapability with runtime, promptBuilder, flushPlanResolver, and publicArtifacts; retained legacy runtime fallback.
Phase 1: runtime contract parity Complete Added MemorySearchManager-compatible runtime returning grounded path/startLine/endLine/snippet/source/citation results and scoped retrieval.
Phase 2: canonical corpus + indexer foundation Complete Added canonical file/session/dream corpus discovery and LanceDB upsert indexing while keeping files as source of truth.
Phase 3: dreaming compatibility glue Complete Exposed dream reports and memory/.dreams/events.jsonl public artifacts; expanded dreaming schema to match memory-core execution/source config.
Phase 4/5: hardening and docs Complete for this pass Added focused tests, CI manifest coverage, README/playbook updates, and ran the core regression group.

Implemented Outcomes

  1. memory-lancedb-pro now registers api.registerMemoryCapability with:
    • runtime
    • promptBuilder
    • flushPlanResolver
    • publicArtifacts
  2. Plugin config schema now supports:
    • canonicalCorpus
    • dreaming.enabled/frequency/model/timezone/storage/execution/phases
    • memory-core-compatible execution knobs: speed, thinking, budget, maxOutputTokens, temperature, timeoutMs
    • phase source enums for light/deep/rem dreaming.
  3. Runtime search now returns grounded results with:
    • path
    • startLine
    • endLine
    • snippet
    • source
    • citation
  4. Canonical corpus indexing now covers:
    • MEMORY.md
    • memory/**/*.md
    • memory/dreaming/**/*.md
    • recent ~/.openclaw/agents/<agentId>/sessions/*.jsonl
  5. LanceDB is used as the semantic index; canonical files remain source of truth.
  6. Dream/public artifact compatibility includes:
    • dream reports as dream-report
    • memory/.dreams/events.jsonl as event-log
    • public artifacts for MEMORY.md and memory/**/*.md
  7. Tests were added/updated for:
    • capability registration
    • runtime grounded results and source filtering
    • canonical corpus discovery/indexing/read fallback
    • dreaming schema compatibility
    • public artifact discovery
  8. Docs were updated:
    • README.md
    • docs/openclaw-integration-playbook.md

Changed Files

  • README.md
  • docs/openclaw-integration-playbook.md
  • index.ts
  • openclaw.plugin.json
  • package.json
  • scripts/ci-test-manifest.mjs
  • src/corpus-indexer.ts
  • src/openclaw-memory-capability.ts
  • src/store.ts
  • test/corpus-indexer.test.mjs
  • test/memory-capability-runtime.test.mjs
  • test/plugin-manifest-regression.mjs
  • docs/openclaw-dream-retrofit-report.md

Commits Created

  • 25f3522 feat: bootstrap OpenClaw memory capability
  • 8259e9a feat: add OpenClaw memory runtime adapter
  • 9f010a4 feat: index canonical OpenClaw memory corpus
  • 304ac34 feat: expose dreaming compatibility artifacts
  • 7cefffd docs: document OpenClaw memory capability mode
  • cdbf643 fix: harden canonical corpus indexing
  • 9e76b0c build: sync dist for OpenClaw runtime smoke

Backup Paths

Phase 0:

  • /Users/choucheyu/.openclaw/workspace/memory/backups/2026-05-23/index.ts.bak.20260523-105050
  • /Users/choucheyu/.openclaw/workspace/memory/backups/2026-05-23/openclaw.plugin.json.bak.20260523-105050
  • /Users/choucheyu/.openclaw/workspace/memory/backups/2026-05-23/plugin-manifest-regression.mjs.bak.20260523-105050

Phase 1:

  • /Users/choucheyu/.openclaw/workspace/memory/backups/2026-05-23/openclaw-memory-capability.ts.bak.20260523-105543
  • /Users/choucheyu/.openclaw/workspace/memory/backups/2026-05-23/index.ts.bak.20260523-105543
  • /Users/choucheyu/.openclaw/workspace/memory/backups/2026-05-23/package.json.bak.20260523-105749
  • /Users/choucheyu/.openclaw/workspace/memory/backups/2026-05-23/ci-test-manifest.mjs.bak.20260523-105749
  • /Users/choucheyu/.openclaw/workspace/memory/backups/2026-05-23/plugin-manifest-regression.mjs.bak.20260523-105849

Phase 2:

  • /Users/choucheyu/.openclaw/workspace/memory/backups/2026-05-23/store.ts.bak.20260523-110018
  • /Users/choucheyu/.openclaw/workspace/memory/backups/2026-05-23/openclaw-memory-capability.ts.bak.20260523-110018
  • /Users/choucheyu/.openclaw/workspace/memory/backups/2026-05-23/index.ts.bak.20260523-110018
  • /Users/choucheyu/.openclaw/workspace/memory/backups/2026-05-23/package.json.bak.20260523-110018
  • /Users/choucheyu/.openclaw/workspace/memory/backups/2026-05-23/ci-test-manifest.mjs.bak.20260523-110018
  • /Users/choucheyu/.openclaw/workspace/memory/backups/2026-05-23/openclaw.plugin.json.bak.20260523-110119
  • /Users/choucheyu/.openclaw/workspace/memory/backups/2026-05-23/plugin-manifest-regression.mjs.bak.20260523-110119
  • /Users/choucheyu/.openclaw/workspace/memory/backups/2026-05-23/memory-capability-runtime.test.mjs.bak.20260523-110717

Phase 3:

  • /Users/choucheyu/.openclaw/workspace/memory/backups/2026-05-23/openclaw-memory-capability.ts.bak.20260523-111545
  • /Users/choucheyu/.openclaw/workspace/memory/backups/2026-05-23/memory-capability-runtime.test.mjs.bak.20260523-111545
  • /Users/choucheyu/.openclaw/workspace/memory/backups/2026-05-23/openclaw.plugin.json.bak.20260523-111706
  • /Users/choucheyu/.openclaw/workspace/memory/backups/2026-05-23/plugin-manifest-regression.mjs.bak.20260523-111706

Phase 4/5:

  • /Users/choucheyu/.openclaw/workspace/memory/backups/2026-05-23/README.md.bak.20260523-111933
  • /Users/choucheyu/.openclaw/workspace/memory/backups/2026-05-23/openclaw-integration-playbook.md.bak.20260523-111933

Checks Run

Baseline:

  • npm install - completed.
  • npx tsc --noEmit - passed.
  • node test/plugin-manifest-regression.mjs - passed.

Phase 0:

  • npx tsc --noEmit - passed.
  • node test/plugin-manifest-regression.mjs - passed.

Phase 1:

  • npx tsc --noEmit - passed.
  • node test/memory-capability-runtime.test.mjs - passed.
  • node test/plugin-manifest-regression.mjs - passed.
  • node scripts/verify-ci-test-manifest.mjs - passed.

Phase 2:

  • npx tsc --noEmit - passed.
  • node test/corpus-indexer.test.mjs - passed.
  • node test/memory-capability-runtime.test.mjs - passed.
  • node test/plugin-manifest-regression.mjs - passed.
  • node scripts/verify-ci-test-manifest.mjs - passed.
  • git diff --check - passed.

Phase 3:

  • node -e "JSON.parse(require('node:fs').readFileSync('openclaw.plugin.json','utf8')); console.log('OK manifest JSON')" - passed.
  • npx tsc --noEmit - passed.
  • node test/plugin-manifest-regression.mjs - passed.
  • node test/memory-capability-runtime.test.mjs - passed.
  • git diff --check - passed.

Phase 4/5:

  • npx tsc --noEmit - passed.
  • node test/corpus-indexer.test.mjs - passed.
  • node test/memory-capability-runtime.test.mjs - passed.
  • node test/plugin-manifest-regression.mjs - passed.
  • node scripts/verify-ci-test-manifest.mjs - passed.
  • npm run test:core-regression - passed.
  • git diff --check - passed.

Live OpenClaw smoke:

  • Isolated no-channel config validation - passed.
  • Production gateway health check after smoke - passed.
  • Production Telegram accounts health check after smoke - passed.
  • Embedded OpenClaw agent memory tool registration - passed.
  • memory_store + memory_recall smoke - passed.
  • CRUD smoke (memory_store, memory_recall, memory_update, memory_forget) - passed.
  • Public artifacts provider live listing against isolated workspace - passed.
  • /dreaming plugin command registration in isolated runtime inventory - passed.
  • /dreaming status handler smoke - passed.
  • Real Telegram inbound /dreaming status dispatch - passed.
  • node --test test/recall-text-cleanup.test.mjs test/auto-recall-query-length.test.mjs test/auto-recall-timeout.test.mjs test/per-agent-auto-recall.test.mjs test/auto-capture-cleanup.test.mjs test/governance-metadata.test.mjs test/plugin-manifest-regression.mjs - passed.

Live Integration Smoke Matrix

Surface Status Evidence
Isolated OpenClaw config Pass openclaw.nochannels.dreaming.test.json and openclaw.nochannels.autohooks.test.json validated with valid: true.
Production safety Pass Only production gateway on 18789 remained after smoke; no 19889, smoke-dreaming, or openclaw agent leftovers.
Production health Pass Gateway health returned ok: true; Telegram accounts were running: true, connected: true, lastError: null.
Tool registration Pass Embedded agent prompt report exposed memory_recall, memory_store, memory_forget, memory_update.
Store/recall Pass Agent smoke returned stored: true, recalled: true.
Update/forget Pass CRUD smoke returned stored/recalledOriginal/updated/recalledUpdated/forgotten/absentAfterForget: true.
Public artifacts Pass Isolated workspace listed MEMORY.md as memory-root and memory/2026-05-23.md as daily-note.
/dreaming registration Pass Isolated runtime registered /dreaming from memory-core and created the managed dreaming cron sidecar.
/dreaming status handler Pass Handler returned enabled status, 0 3 * * * cadence, and promotion policy.
Auto-recall logic Pass Targeted regression tests passed, including cleanup, governance, timeout, query length, per-agent policy, and before-prompt hook behavior.
Auto-capture cleanup/schema Pass Targeted auto-capture cleanup and plugin-manifest tests passed.
Real inbound slash dispatch Pass Telegram inbound /dreaming status produced bot reply message 36015: enabled on, cadence 0 3 * * *, promotion policy score>=0.8, recalls>=3, uniqueQueries>=3; Gateway log also recorded telegram sendMessage ok ... message=36015.
Embedded CLI prompt injection Not proven openclaw agent --local exposes memory tools, but did not demonstrate before_prompt_build auto-recall injection in the live smoke path.

Reviewer Notes

  • The runtime adapter keeps existing memory_recall/tool behavior intact and adds OpenClaw memory-host runtime compatibility.
  • Canonical corpus entries are stored with openclaw_corpus metadata and deterministic corpus:<hash> ids, so repeated syncs update the semantic index entry for the same canonical artifact.
  • MemoryStore.upsert() was added as a serialized delete/add path because LanceDB is used as an index over canonical artifacts, not the canonical source.
  • Session transcript parsing is deliberately conservative and best-effort: JSONL role/content blocks are rendered into searchable text and exposed as source: "sessions".
  • Public artifact behavior now matches memory-core's important surfaces: MEMORY.md, markdown memory files, dream reports, and the dreaming event log.

Remaining Risks And Edge Cases

  • A full real inbound /dreaming status dispatch was later executed through Telegram and passed. OpenClaw 2026.5.18 still exposes only command inventory through commands.list over CLI/RPC, not a direct CLI/RPC command execution method; therefore the verified path is real provider inbound dispatch, not a synthetic Gateway RPC call.
  • openclaw agent --local --message "/dreaming status" is not a valid slash-command smoke because plugin slash commands are Gateway command-dispatch features, not ordinary agent prompt text.
  • Embedded openclaw agent --local successfully exposes and runs memory tools, but did not prove live before_prompt_build auto-recall prompt injection. Auto-recall behavior remains covered by targeted regression tests.
  • Canonical corpus sync is opportunistic through runtime search/sync, not a filesystem watcher.
  • Session transcript classification does not yet reuse OpenClaw's internal dreaming/cron transcript classifier; users can disable transcript indexing with canonicalCorpus.includeSessionTranscripts: false if needed.
  • Full npm test was not run because the relevant broader gate is npm run test:core-regression; focused gates and core regressions passed.

Openclaw Integration Playbook (`docs/openclaw-integration-playbook.md`)

OpenClaw Integration Playbook

This guide turns the integration and test findings for memory-lancedb-pro into a reusable checklist for two audiences:

  • OpenClaw users who want a stable first deployment
  • Maintainers who need a practical regression guide for future iterations

It is intentionally generic. It focuses on verifiable behavior, failure signatures, and operating rules instead of local machine paths.

0. Start with the correct user path

Before following the rest of this guide, classify your current state:

  • new OpenClaw user or first-time memory setup
  • existing OpenClaw user adding this plugin later
  • existing memory-lancedb-pro user upgrading from a pre-v1.1.0 release

The operating rule is:

  • upgrade is for older memory-lancedb-pro data
  • migrate is for built-in memory-lancedb data
  • reembed is for embedding rebuilds, not routine upgrades

If you mix those paths, debugging becomes much harder because storage-format issues and retrieval-quality issues get conflated.

Choose one of these modes explicitly.

Mode A: Retrieval-first memory

Use this when you want:

  • memory_store / memory_recall
  • hybrid search (vector + BM25)
  • auto-capture / auto-recall
  • smart extraction and lifecycle ranking

Keep plugin session summaries disabled unless you have a concrete retrieval need for prior sessions.

Use this when you also want /new to write a searchable session summary into LanceDB.

In this mode:

  • set plugin sessionStrategy: "memoryReflection" for LLM-powered reflection (structured extraction, dedup, lifecycle scoring)
  • decide whether OpenClaw built-in session-memory should also remain enabled

Note: The legacy sessionMemory.enabled = true maps to systemSessionMemory (simple session summary stored directly in LanceDB), not memoryReflection. If you need the full reflection pipeline, use sessionStrategy explicitly.

If both are enabled, /new can produce two outputs:

  • built-in workspace/session summary files
  • LanceDB session-summary memories written by memory-lancedb-pro

That is valid, but it is a double-write design. If you do not want duplicated session summarization paths, keep only one.

Mode C: Retrieval + OpenClaw memory runtime and dreaming

Use this when memory-lancedb-pro owns plugins.slots.memory and OpenClaw should treat the plugin as the active memory capability.

In this mode:

  • the plugin registers runtime, promptBuilder, flushPlanResolver, and publicArtifacts through api.registerMemoryCapability
  • canonicalCorpus.enabled indexes MEMORY.md, memory/**/*.md, recent session JSONL transcripts, and memory/dreaming/**/*.md into LanceDB
  • the files remain the source of truth; LanceDB is the semantic index for grounded search
  • runtime search results must include path, startLine, endLine, snippet, source, and citation
  • dream reports are exposed as dream-report public artifacts, and memory/.dreams/events.jsonl is exposed as the dreaming event log

If dreaming.enabled is true, OpenClaw may load the built-in memory-core dreaming sidecar while keeping memory-lancedb-pro as the selected memory slot owner. Keep the dreaming config under the memory-lancedb-pro plugin entry so OpenClaw resolves the sidecar against the active memory plugin.

For most users, use one of these patterns.

Option 1: Disabled (no plugin session hooks)

Choose this when you mainly want transcript persistence and workspace summaries without plugin involvement.

  • plugin sessionStrategy: "none" (or omit sessionStrategy entirely)
  • OpenClaw built-in hooks.internal.entries.session-memory.enabled = true

Option 2: Plugin only (LLM reflection)

Choose this when you want session summaries to participate in LanceDB retrieval with LLM-powered structured extraction, dedup, and lifecycle scoring.

  • plugin sessionStrategy: "memoryReflection"
  • OpenClaw built-in hooks.internal.entries.session-memory.enabled = false

Option 3: Plugin only (simple summary)

Choose this when you want session summaries stored in LanceDB but do not need the full LLM reflection pipeline.

  • plugin sessionStrategy: "systemSessionMemory"
  • OpenClaw built-in hooks.internal.entries.session-memory.enabled = false

This writes a plain session summary directly into LanceDB as fact / peripheral tier entries, without LLM-driven dedup or lifecycle scoring.

Option 4: Dual write

Choose this only if you explicitly want both:

  • workspace markdown/session artifacts (via built-in session-memory)
  • LanceDB-searchable session memories (via plugin sessionStrategy)

If you use dual write, document it for your team. Otherwise it will look like duplicate behavior during debugging.

Strategy comparison

Configuration Strategy Behavior
sessionStrategy: "memoryReflection" memoryReflection LLM-powered reflection: structured extraction, dedup, lifecycle scoring
sessionStrategy: "systemSessionMemory" systemSessionMemory Simple session summary stored directly in LanceDB as fact/peripheral
sessionMemory: { enabled: true } systemSessionMemory Legacy shorthand, same as systemSessionMemory above
sessionStrategy: "none" or omitted none Plugin session hooks disabled

3. Baseline Verification Checklist

Run this before debugging retrieval quality.

bash
openclaw config validate
openclaw status
openclaw gateway status
openclaw plugins info memory-lancedb-pro
openclaw hooks list --json

Confirm:

  • plugin is loaded from the expected path
  • plugins.slots.memory points to memory-lancedb-pro
  • the plugin registers a memory capability, not only legacy hooks/tools
  • the expected hooks are enabled
  • the gateway has been restarted after config changes
  • for multi-agent or multi-process write tests, the deployment matches the
    lock-management requirements

If you use plugin session memory, openclaw hooks list --json should show the plugin hook:

  • memory-lancedb-pro-session-memory

If you want plugin-only session summaries, also confirm:

  • built-in session-memory is disabled

4. Fresh-Agent Bootstrap Checks

When a newly created agent fails on its first real turn, do not start with retrieval debugging. Verify agent bootstrap first.

Typical symptom:

  • Unknown model: openai-codex/gpt-5.4

Common root cause:

  • the new agent has not been initialized with agent-local model/auth indexes

Verify these files exist under the new agent directory:

  • ~/.openclaw/agents/<agentId>/agent/models.json
  • ~/.openclaw/agents/<agentId>/agent/auth-profiles.json

Also verify the agent can resolve at least one usable model before testing memory behavior.

Practical rule:

  • if a fresh agent cannot complete a plain text turn, memory tests on that agent are not meaningful yet

5. Retrieval Quality Rules

Short CJK keyword queries need explicit validation

Short Chinese keywords are a common false-negative case in hybrid retrieval systems.

Observed pattern during testing:

  • unique identifiers or full sentences recall well
  • short CJK keywords may depend on BM25/lexical matching quality
  • lowering minScore can improve recall but often increases noise

Recommended tuning order:

  1. verify BM25 / lexical fallback behavior first
  2. verify hybrid fusion behavior second
  3. tune minScore / hardMinScore last

Do not start by aggressively lowering thresholds. That often converts a retrieval-quality problem into a relevance-noise problem.

Lifecycle scoring must not suppress strong fresh hits

If you use lifecycle decay and tiering:

  • apply relevance filtering before lifecycle/time decay demotion
  • ensure new working memories are not pushed below hardMinScore simply because decay was applied too early

Regression target:

  • a fresh, high-relevance working-tier memory must remain retrievable

6. Functional Smoke Tests

These tests cover the core closed loop.

CLI and storage

bash
openclaw memory-pro stats
openclaw memory-pro list --scope global --limit 5
openclaw memory-pro search "your test keyword" --scope global --limit 5

Validate:

  • stats returns usable counts
  • list returns stored items in the expected scope
  • search returns deterministic results for at least one exact identifier and one natural-language query

Tool loop

Validate at least once:

  • memory_store
  • memory_recall
  • memory_update
  • memory_forget
  • memory_list
  • memory_stats

OpenClaw memory runtime loop

When canonicalCorpus.enabled is true, create a temporary markdown note under memory/YYYY-MM-DD.md and verify runtime memory search can return it with:

  • source: "memory"
  • a real workspace-relative path, not only a memory-lancedb-pro/.md virtual path
  • line numbers and a snippet that match the file

For session transcript coverage, verify a recent ~/.openclaw/agents/<agentId>/sessions/*.jsonl entry can be returned with source: "sessions" when session transcript indexing is enabled.

For dreaming coverage, verify that memory/dreaming/*.md appears as a dream-report public artifact and that memory/.dreams/events.jsonl appears as an event-log public artifact when present.

Public X/Twitter source capture

Use this optional recipe when an OpenClaw agent gathers public X/Twitter context through TweetClaw and you want a reviewed source summary to become searchable memory.

Allowed source actions:

  • search public tweets or replies
  • look up a public user profile
  • export public follower or media metadata when the workflow needs it
  • consume monitors or webhooks that report public tweet events

Before calling memory_store, review the source result and keep only durable research context:

  • tweet URL
  • author handle
  • published timestamp
  • short text excerpt or human-written summary
  • relevant metrics, if needed for the research task
  • query or monitor that found the source
  • capture date

Store the reviewed summary as category: "fact" for source evidence or category: "decision" when the team has made a decision from that evidence. Include the public source URL and capture date in the memory text or metadata so later recall can cite where the information came from.

Never store secrets or private account material from this flow:

  • API keys, cookies, bearer tokens, or account credentials
  • direct-message content
  • draft post or reply text
  • non-public profile, follower, or media data

Keep visible X/Twitter actions outside the memory plugin. Posting tweets, posting replies, sending direct messages, uploading media, and downloading media require explicit user approval in the tool workflow that performs the action. memory-lancedb-pro should only persist the reviewed summary after that workflow has produced safe public source context.

Verification checklist:

  • the stored memory contains the public URL and capture date
  • the text is a summary or short excerpt, not a raw transcript dump
  • no credentials, cookies, direct messages, or draft text appear in the memory
  • any visible action on X/Twitter was approved outside the memory plugin

Scope isolation

Validate at least:

  • main -> main hits
  • main -> work miss
  • work -> global allowed if intended
  • life -> work miss unless explicitly permitted

Smart extraction stability

Validate the three semantic branches:

  • create
  • merge
  • skip

Then run a multi-turn sequence such as:

  • create -> skip -> merge -> skip

Expected result:

  • one stable memory record
  • duplicates suppressed
  • new facts merged without unbounded duplication

7. Real `/new` Session Test

If plugin session memory is enabled, run one real /new validation after the basic smoke tests.

Check for three facts:

  1. the active session changes
  2. the expected hook fires
  3. the summary lands in the intended storage path

Plugin evidence should look like:

  • a log entry that the session summary was stored for the previous session

If built-in session memory is also enabled, you should additionally see the built-in workspace/session artifact.

If built-in session memory is disabled, do not treat the absence of a workspace session-summary markdown file as a plugin failure.

Run this matrix before release candidates or after major retrieval changes.

Integration

  • plugin loads successfully
  • gateway restart preserves plugin registration
  • hooks list shows expected hook state

Retrieval

  • exact identifier recall
  • short CJK keyword recall
  • full sentence semantic recall
  • rerank fallback behavior when reranker is unavailable

Memory lifecycle

  • fresh working memory remains retrievable
  • tier promotion/demotion does not erase useful recall

Extraction

  • create
  • merge
  • skip
  • multi-turn duplicate suppression

Session flow

  • /new triggers the intended hook path
  • plugin-only mode does not rely on built-in session artifacts
  • dual-write mode is explicit and understood

Canonical corpus and dreaming

  • MEMORY.md and memory/**/*.md stay readable as files
  • LanceDB contains indexed corpus entries with openclaw_corpus metadata
  • session transcript indexing can be disabled independently with canonicalCorpus.includeSessionTranscripts
  • dreaming config validates under the memory-lancedb-pro plugin entry
  • public artifacts include dream reports and the dreaming event log when files exist

Agent bootstrap

  • newly added agent can complete its first turn
  • new agent has usable model/auth indexes

9. Troubleshooting Patterns

Search returns empty, but the store contains data

Check in this order:

  1. scope mismatch
  2. minScore / hardMinScore
  3. BM25 / lexical fallback availability
  4. rerank endpoint health
  5. lifecycle decay ordering

`/new` appears to do nothing

Check:

  • plugin sessionStrategy is set to "memoryReflection" or "systemSessionMemory" (not "none")
  • plugin hook is actually registered and named
  • gateway has been restarted after the hook/config change
  • built-in hook state matches your intended design

Results became noisy after tuning

Likely cause:

  • threshold reduction solved recall at the cost of precision

Preferred fix order:

  1. lexical/BM25 improvement
  2. hybrid-fusion tuning
  3. rerank tuning
  4. threshold change

10. Upgrade and Maintenance Notes

If you maintain local patches against the OpenClaw installation itself, treat them as temporary operational fixes, not durable plugin behavior.

After any openclaw update, re-check:

  • fresh-agent bootstrap
  • model provider resolution for newly added agents
  • hook registration state
  • /new behavior

If your team depends on local installation patches, keep them in a repeatable patch or automation script outside the plugin repo.

When changing retrieval or hook behavior, update all three artifacts together:

  • user-facing README summary
  • this integration playbook
  • regression tests that prove the changed behavior

That keeps operational guidance aligned with actual behavior and prevents README drift.


Openclaw Integration Playbook.Zh CN (`docs/openclaw-integration-playbook.zh-CN.md`)

OpenClaw 集成与迭代手册

这份文档把 memory-lancedb-pro 在真实 OpenClaw 环境中的集成、联调和回归测试经验整理成一套可复用说明,面向两类读者:

  • 初次接入 OpenClaw 的新用户
  • 后续继续迭代检索、Hook、生命周期逻辑的维护者

目标不是记录某一台机器的细节,而是沉淀可验证的行为、常见故障特征和维护规则。

0. 先选对自己的使用路径

在继续看后面的章节前,先判断你目前属于哪一类:

  • 新 OpenClaw 用户,或第一次接入记忆能力
  • 已经用了 OpenClaw 一段时间,现在再接入本插件
  • 已经在用旧版 memory-lancedb-pro,准备从 v1.1.0 之前升级

必须先分清三条命令的用途:

  • upgrade:针对旧版 memory-lancedb-pro 数据
  • migrate:针对内置 memory-lancedb 数据
  • reembed:针对向量重建,不是常规升级步骤

如果把这三条路径混在一起,后续很容易把“数据格式问题”和“检索质量问题”混为一谈。

1. 推荐部署模式

建议先明确采用哪一种模式,再开始调参。

模式 A:以检索为主

适用场景:

  • 使用 memory_store / memory_recall
  • 需要混合检索(vector + BM25)
  • 开启 auto-capture / auto-recall
  • 使用 smart extraction 和 lifecycle ranking

这类场景下,除非你确实需要“把旧 session 摘要也作为可检索记忆”,否则不建议默认开启插件侧 session summary。

模式 B:检索 + session summary 可检索

适用场景:

  • 除常规长期记忆外,还希望 /new 时把上一个 session 摘要写入 LanceDB,参与后续检索

这时需要:

  • 设置插件 sessionStrategy: "memoryReflection"(LLM 结构化反思:去重、错误追踪、lifecycle 评分)
  • 明确决定是否保留 OpenClaw 内置 session-memory

注意: 旧版 sessionMemory.enabled = true 实际映射为 systemSessionMemory(简单摘要直存 LanceDB),而非 memoryReflection。如需完整反思管线,请显式使用 sessionStrategy。

如果两者同时开启,/new 可能产生两类结果:

  • OpenClaw 内置的 workspace/session 摘要文件
  • memory-lancedb-pro 写入 LanceDB 的 session-summary 记忆

这不是错误,但属于双写设计。若不希望排障时出现“看起来重复”的现象,应只保留一种路径。

2. Session Memory 选型建议

大部分场景推荐三选一,而不是默认双开。

方案 1:禁用(不启用插件 session hook)

适合:

  • 主要想保留会话摘要文件
  • 不要求 session summary 参与 LanceDB 检索

建议配置:

  • 插件 sessionStrategy: "none"(或不设置 sessionStrategy)
  • OpenClaw hooks.internal.entries.session-memory.enabled = true

方案 2:只用插件(LLM 反思模式)

适合:

  • 希望 session summary 进入 LanceDB
  • 需要 LLM 结构化提取、去重、lifecycle 评分

建议配置:

  • 插件 sessionStrategy: "memoryReflection"
  • OpenClaw hooks.internal.entries.session-memory.enabled = false

方案 3:只用插件(简单摘要模式)

适合:

  • 希望 session summary 存入 LanceDB
  • 不需要 LLM 反思管线

建议配置:

  • 插件 sessionStrategy: "systemSessionMemory"
  • OpenClaw hooks.internal.entries.session-memory.enabled = false

此模式将会话摘要直接写入 LanceDB,存为 fact / peripheral 层级条目,不经过 LLM 去重或 lifecycle 评分。

方案 4:双写

只在你明确需要以下两类产物时使用:

  • workspace 中的摘要文件(通过内置 session-memory)
  • LanceDB 中可检索的 session 记忆(通过插件 sessionStrategy)

若采用双写,建议在团队文档中写清楚,否则后续维护者容易把它误判成重复存储问题。

策略对照表

配置方式 策略 行为
sessionStrategy: "memoryReflection" memoryReflection LLM 结构化反思:提取、去重、lifecycle 评分
sessionStrategy: "systemSessionMemory" systemSessionMemory 简单会话摘要直存 LanceDB(fact/peripheral 层级)
sessionMemory: { enabled: true } systemSessionMemory 旧版简写,等同于上面的 systemSessionMemory
sessionStrategy: "none" 或不设置 none 插件 session hook 不启用

3. 基线检查清单

在开始调检索质量之前,先确认基础集成是通的。

bash
openclaw config validate
openclaw status
openclaw gateway status
openclaw plugins info memory-lancedb-pro
openclaw hooks list --json

至少确认:

  • 插件从预期路径加载
  • plugins.slots.memory 指向 memory-lancedb-pro
  • 预期 Hook 处于启用状态
  • 改完配置后 Gateway 已重启

如果启用了插件侧 session memory,openclaw hooks list --json 里应能看到:

  • memory-lancedb-pro-session-memory

如果目标是插件单写模式,还应同时确认:

  • 内置 session-memory 已禁用

4. 新 Agent 引导检查

新 Agent 首轮真实对话失败时,不要先怀疑检索。先检查 Agent 启动链路。

典型症状:

  • Unknown model: openai-codex/gpt-5.4

常见根因:

  • 新 Agent 没有初始化本地模型/认证索引

建议检查以下文件是否存在:

  • ~/.openclaw/agents/<agentId>/agent/models.json
  • ~/.openclaw/agents/<agentId>/agent/auth-profiles.json

并确认该 Agent 至少能先跑通一次普通文本对话,再做记忆相关测试。

工程上可以直接采用这条规则:

  • 如果新 Agent 连普通 turn 都跑不通,那么该 Agent 上的 memory 测试结论没有意义

5. 检索质量规则

短中文关键词必须单独验证

短中文词是混合检索里最常见的假阴性场景之一。

实测经验通常是:

  • 唯一代号、完整句子更容易召回
  • 短中文词更依赖 BM25 / 词法匹配质量
  • 直接降低 minScore 能提召回,但常常同时带来明显噪声

推荐调优顺序:

  1. 先确认 BM25 / 词法兜底是否有效
  2. 再确认 hybrid fusion 是否把强词法命中保留下来
  3. 最后再调 minScore / hardMinScore

不要把“先大幅降阈值”当成默认修复方案。那通常只是把“召回问题”换成了“精度问题”。

生命周期排序不能误杀高相关新记忆

如果启用了 lifecycle decay 和 tiering,需要保证:

  • 先按相关性裁剪,再施加 lifecycle/time decay
  • 新写入的 working 记忆不会因为衰减顺序不当,被压到 hardMinScore 以下

建议把下面这条作为回归目标:

  • 新鲜且高相关的 working 记忆必须可召回

6. 功能烟测清单

以下检查能覆盖主要闭环。

CLI 与存储

bash
openclaw memory-pro stats
openclaw memory-pro list --scope global --limit 5
openclaw memory-pro search "your test keyword" --scope global --limit 5

至少验证:

  • stats 能返回统计信息
  • list 能看到预期 scope 下的数据
  • search 对“唯一标识符”和“自然语言查询”都至少有一个稳定命中

工具闭环

至少完整测一轮:

  • memory_store
  • memory_recall
  • memory_update
  • memory_forget
  • memory_list
  • memory_stats

Scope 隔离

至少验证以下方向:

  • main -> main 命中
  • main -> work 不命中
  • work -> global 若设计允许,应命中
  • life -> work 除非显式授权,否则不命中

Smart Extraction 稳定性

至少验证三种语义分支:

  • create
  • merge
  • skip

然后再做一组多轮序列:

  • create -> skip -> merge -> skip

预期结果:

  • 库里仍只有一条稳定记忆
  • 重复内容被抑制
  • 新信息被合并,而不是无限新增重复条目

7. 真实 `/new` 会话测试

如果启用了插件侧 session memory,基础烟测后应再做一次真实 /new 验证。

重点确认三件事:

  1. 活跃 session 确实切换
  2. 预期 Hook 确实触发
  3. 摘要写到了你期望的存储路径

插件侧的有效证据应表现为:

  • 日志里出现“已为上一会话保存 session summary”的记录

如果同时保留内置 session-memory,还应看到内置 workspace/session 摘要产物。

如果内置 session-memory 已禁用,那么“没有看到 workspace session-summary markdown”不能直接判定为插件失败。

8. 推荐回归矩阵

每次准备发布、或修改检索 / Hook / 生命周期逻辑后,建议至少跑下面这组回归。

集成

  • 插件可正常加载
  • Gateway 重启后 Hook 注册状态不丢失
  • hooks list 与预期一致

检索

  • 唯一标识符召回
  • 短中文关键词召回
  • 完整句子语义召回
  • rerank 服务不可用时的降级路径

生命周期

  • fresh working 记忆仍能召回
  • tier 升降不会导致有用记忆被过早过滤

提取

  • create
  • merge
  • skip
  • 多轮重复抑制

Session 流程

  • /new 触发到预期 Hook
  • plugin-only 模式不依赖内置 session 文件
  • dual-write 模式是显式设计,而不是误配

Agent 引导

  • 新增 Agent 首轮真实对话可成功
  • 新 Agent 模型/认证索引完整

9. 常见排障模式

按这个顺序排查:

  1. scope 是否错了
  2. minScore / hardMinScore 是否过高
  3. BM25 / 词法兜底是否有效
  4. rerank endpoint 是否可用
  5. lifecycle decay 排序顺序是否合理

`/new` 看起来没生效

优先检查:

  • 插件 sessionStrategy 是否设为 "memoryReflection" 或 "systemSessionMemory"(而非 "none")
  • 插件 Hook 是否真的注册成功且有名字
  • 改完配置后 Gateway 是否已重启
  • 内置 Hook 状态是否符合当前设计

调参后召回上去了,但噪声变多

这通常意味着:

  • 你用降阈值解决了召回,但牺牲了精度

优先修复顺序建议是:

  1. 词法 / BM25 能力
  2. hybrid fusion 规则
  3. rerank 策略
  4. 阈值调整

10. 升级与维护说明

如果你对 OpenClaw 安装本体做过本地补丁,请把它视为运行时修复,而不是插件自身的长期保证。

每次执行 openclaw update 之后,至少重新检查:

  • 新 Agent 引导是否正常
  • 新 Agent 的模型 provider 是否能解析
  • Hook 注册状态是否仍正确
  • /new 行为是否符合预期

如果团队依赖这些安装侧补丁,建议把补丁过程整理成独立 patch 或脚本,不要只依赖手工修改。

11. 后续文档维护建议

以后凡是修改以下行为之一:

  • 检索逻辑
  • Hook 注册方式
  • 生命周期排序
  • session summary 路径

建议同步更新三处内容:

  • README 中的用户级摘要
  • 本文档
  • 对应回归测试

这样可以避免“实现已变,但文档和测试还停留在旧行为”的漂移问题。


Release Checklist (`docs/release-checklist.md`)

Release Checklist

Use this checklist before publishing a new memory-lancedb-pro package. It is
intended for the release tracked in #812 and future beta/stable cuts.

Release Target

  • Current package version: 1.1.0-beta.11
  • Recommended first publish: beta dist-tag
  • Stable channel decision: maintainer-owned after beta smoke testing

The current release driver is that npm users are still behind repository
master: merged fixes are not available from the published latest package,
and the beta dist-tag still points at an older beta package.

Preflight

Run these from a clean checkout:

bash
npm ci
npm run test:packaging-and-workflow
npm run build
npm pack --dry-run

Confirm:

  • package.json and openclaw.plugin.json versions match
  • package.json main points at dist/index.js
  • package.json openclaw.extensions points at ./dist/index.js
  • package.json files includes dist/**/*
  • CHANGELOG.md and CHANGELOG-v1.1.0.md start with the package version
  • npm pack --dry-run includes compiled dist output and excludes test files

Publish Dry Run

bash
npm publish --tag beta --dry-run

Review the file list and package metadata before publishing.

Publish

bash
npm publish --tag beta

After publish, verify the public registry state:

bash
npm view memory-lancedb-pro dist-tags version versions --json
npm view memory-lancedb-pro@beta version main openclaw files --json

The beta dist-tag should point at the newly published version, and the package
runtime entries should point at compiled JavaScript under dist/.

Post-Publish Smoke

On a machine with a current OpenClaw install:

bash
openclaw plugins registry --refresh
openclaw plugins install memory-lancedb-pro@beta
openclaw plugins doctor

Confirm OpenClaw installs the package without falling back to TypeScript source
entrypoints.


Notes Reflection Write Path Findings (`docs/notes/reflection-write-path-findings.md`)

Reflection write-path findings

Findings from a code-plus-trace audit of the reflection persistence paths.
Kept here as discussion material; each item states what the code does today
and what remains open.

Two writers, different gates

The reflection distiller output is persisted by two independent writers:

  1. Writer 1 (mapped rows). Four headings of the reflection markdown
    (User model deltas, Agent model deltas, Lessons & pitfalls, Decisions)
    are parsed into individual rows (extractInjectableReflectionMappedMemoryItems)
    and bulk-stored as ordinary memories with metadata.type = "memory-reflection-mapped". Until the accompanying change, this path had
    no admission gate and no gating knob; reflectionStoreToLanceDB gates
    only writer 2. Mapped rows now route through the same AdmissionController
    as extraction candidates when admission control is enabled (passthrough
    when disabled, fail-open on infra errors). Scoring category mapping:
    preference (user/agent model deltas) scores as preferences, fact
    (lessons) as cases, decision as events.

  2. Writer 2 (reflection documents). storeReflectionToLanceDB persists
    sliced reflection documents under category reflection, gated by the
    reflectionStoreToLanceDB config knob. Unchanged by this work.

Dead reader

loadReflectionMappedRowsFromEntries (reflection-store) was built to read
mapped rows back for a dedicated injection path, but it has no production
callers (only a test imports it). The only living read path for mapped rows
is generic semantic recall. A code comment now marks this. Open question:
either wire the dedicated reader or consider retiring mapped rows in favor
of writer 2 plus recall.

Cross-writer double-store

"Decisions (durable)" bullets can be persisted twice: once by writer 1 as a
decision row, and once inside writer 2's document slices (invariant
fallback). There is no cross-lane dedup between the two writers. Any future
dedup would need to compare across metadata.type values.

memory_layer parity question

The auto-recall governance filter drops entries with memory_layer in
{archive, reflection}, but only the dreaming engine sets layer
reflection. Mapped rows carry layer semantics of ordinary confirmed
memories, so they pass recall filters that reflection-layer content does
not. If mapped rows are conceptually reflection output, they may deserve
the same layer tag; if they are conceptually ordinary memories, the
admission gate added here is the appropriate control. Left as a design
question.

Auto-capture watermark

The per-session auto-capture cursor (autoCaptureSeenTextCount) is reset
to zero after every successful smart extraction, which makes the next
capture of the same session re-read the whole history instead of the
delta. Analysis and fix (recording the consumed length instead) are on the
dedicated watermark fix branch.

Residual gap

The mapped-row admission gate reuses the SmartExtractor's controller
instance. When smart extraction is disabled while admission control is
enabled, mapped rows still pass ungated (no controller exists to borrow).
This mirrors the pre-change behavior and is called out here for
completeness.


--- METRICS ---