Memory LanceDB Plugin: Configure External Vector Memory
Learn how to install and configure the official LanceDB memory plugin for OpenClaw, including local Ollama-compatible embeddings. Ideal for users needing a local vector database or external memory store.
Read this when
- You are configuring the memory-lancedb plugin
- You want LanceDB-backed long-term memory with auto-recall or auto-capture
- You are using local OpenAI-compatible embeddings such as Ollama
memory-lancedb is an official external plugin that keeps long-term memory in LanceDB using vector search. Before a model turn it can automatically pull up relevant memories, and after a response it can automatically record important facts.
It suits a local vector database, an OpenAI-compatible embedding endpoint, or a memory store outside the default built-in memory backend.
Installation
openclaw plugins install @openclaw/memory-lancedb
The plugin is available on npm but is not included in the OpenClaw runtime image. Installing it writes the plugin entry, enables it, and changes plugins.slots.memory to memory-lancedb. If another plugin already holds the memory slot, that plugin gets disabled with a warning.
Note
Companion plugins such as
memory-wikican work alongsidememory-lancedb, but only one plugin holds the active memory slot at a time.
Note
LanceDB's
memory_recalldoes not get the protected private transcript authorization thatmemory.search.rememberAcrossConversationsuses. Instead, use LanceDB'sautoRecallor itsmemory_recalltool through advanced Active Memory.openclaw doctorreports when Remember across conversations is unavailable with the current memory provider.
Quick start
{
plugins: {
slots: {
memory: "memory-lancedb",
},
entries: {
"memory-lancedb": {
enabled: true,
config: {
embedding: {
provider: "openai",
model: "text-embedding-3-small",
},
autoRecall: true,
autoCapture: false,
},
},
},
},
}
After installation, restart the Gateway and confirm it loaded:
openclaw gateway restart
openclaw plugins list
Embedding config
embedding is mandatory and needs at least one field. provider defaults to openai; model defaults to text-embedding-3-small.
| Field | Type | Notes |
|---|---|---|
embedding.provider | string | Adapter id, e.g. openai, github-copilot, ollama. Default openai. |
embedding.model | string | Default text-embedding-3-small. |
embedding.apiKey | string | Optional; supports ${ENV_VAR} expansion and live credential rotation. |
embedding.baseUrl | string | Optional; supports ${ENV_VAR} expansion and live endpoint rotation. |
embedding.dimensions | integer (>=1) | Required for models not in the built-in table (see below). |
There are two request paths:
- Provider adapter path (default): set
embedding.providerand leave outembedding.apiKey/embedding.baseUrl. The plugin resolves the provider's configured auth profile, environment variable, ormodels.providers.<provider>.apiKeythrough the same memory embedding adaptersmemory-coreuses. This path works forgithub-copilot,ollama, and any other bundled provider with embedding support. - Direct OpenAI-compatible client path: leave
embedding.providerunset (or"openai") and setembedding.apiKeyplusembedding.baseUrl. Use this for a raw OpenAI-compatible embeddings endpoint that has no bundled provider adapter.
embedding.apiKey and embedding.baseUrl are pulled again from live plugin config for the next memory operation, as long as provider, model, and dimensions stay unchanged.
Warning
embedding.provider,embedding.model, andembedding.dimensionsdefine the persisted LanceDB index identity and do not change live. Before restarting with a new identity, plan a LanceDB re-embedding or rebuild so every stored row uses the new vector space and dimensions. The plugin does not re-embed existing rows automatically.
OpenAI Codex / ChatGPT OAuth is not an OpenAI Platform embeddings credential. For OpenAI embeddings use an OpenAI API key auth profile, OPENAI_API_KEY, or models.providers.openai.apiKey. OAuth-only users should pick another embedding-capable provider such as github-copilot or ollama.
{
plugins: {
entries: {
"memory-lancedb": {
enabled: true,
config: {
embedding: {
provider: "github-copilot",
model: "text-embedding-3-small",
},
},
},
},
},
}
Some OpenAI-compatible embedding endpoints reject the encoding_format
parameter; others ignore it and always return number[]. memory-lancedb
omits encoding_format on requests and accepts either float-array or
base64-encoded float32 responses, so both response shapes work without config.
Dimensions
OpenClaw has a built-in dimension for text-embedding-3-small (1536) and
text-embedding-3-large (3072) only. Any other model needs an explicit
embedding.dimensions so LanceDB can create the vector column, for example
ZhiPu embedding-3 at 2048 dimensions:
{
plugins: {
entries: {
"memory-lancedb": {
enabled: true,
config: {
embedding: {
apiKey: "${ZHIPU_API_KEY}",
baseUrl: "https://open.bigmodel.cn/api/paas/v4",
model: "embedding-3",
dimensions: 2048,
},
},
},
},
},
}
Ollama embeddings
Use the bundled Ollama provider adapter path (embedding.provider: "ollama").
It calls Ollama's native /api/embed endpoint and follows the same auth/base
URL rules as the Ollama provider.
{
plugins: {
slots: {
memory: "memory-lancedb",
},
entries: {
"memory-lancedb": {
enabled: true,
config: {
embedding: {
provider: "ollama",
baseUrl: "http://127.0.0.1:11434",
model: "mxbai-embed-large",
dimensions: 1024,
},
recallMaxChars: 400,
autoRecall: true,
autoCapture: false,
},
},
},
},
}
mxbai-embed-large is not in the built-in dimension table, so dimensions is
required. For small local embedding models, lower recallMaxChars if the
local server returns context-length errors.
Recall and capture limits
| Setting | Default | Range | Applies to |
|---|---|---|---|
recallMaxChars | 1000 | 100-10000 | Recall query length and each escaped model-visible recalled item. |
captureMaxChars | 500 | 100-10000 | memory_store input limit and auto-capture eligibility. |
customTriggers | [] | 0-50 items, each ≤100 chars | Literal phrases that make auto-capture consider a message. |
recallMaxChars bounds the before_prompt_build auto-recall query, the
memory_recall tool, the memory_forget query path, and openclaw ltm search.
Auto-recall embeds the latest user message from the turn and falls back to the
full prompt only when no user message is present, keeping channel metadata and
large prompt blocks out of the embedding request. It also bounds each recalled
item after prompt escaping before that text reaches the model.
captureMaxChars gates whether a user message from the turn's agent_end
event is short enough to be considered for auto-capture. memory_store rejects
longer text before embedding or storage; the setting does not affect recall
queries.
customTriggers adds literal auto-capture phrases without regex. Built-in
triggers cover common English, Czech, Chinese, Japanese, and Korean memory
phrases (remember, prefer, 记住, 覚えて, 기억해, and similar).
Auto-capture also rejects text that looks like envelope/transport metadata,
prompt-injection payloads, or already-injected <relevant-memories> context,
and caps at 3 captured memories per agent turn.
Every memory is owned by one agent. Recall, duplicate detection, capture,
listing, raw queries, and deletion all enforce that owner before returning or
mutating rows. An agent with memory.search.enabled: false in its agents.entries.*
entry, or one inheriting a disabled top-level search, also gets none of the memory_recall, memory_store,
or memory_forget tools and does not participate in automatic recall or
capture, even when the plugin-level autoRecall/autoCapture flags are on.
Commands
memory-lancedb registers the ltm CLI namespace whenever it is installed
(not only when it owns the active memory slot):
openclaw ltm list [--agent <id>] [--limit <n>] [--order-by-created-at]
openclaw ltm search <query> [--agent <id>] [--limit <n>]
openclaw ltm stats [--agent <id>]
ltm query runs a non-vector query directly against the LanceDB table:
openclaw ltm query --agent research --cols id,text,createdAt --limit 20
openclaw ltm query --filter "category = 'preference'" --order-by createdAt:desc
| Flag | Default | Notes |
|---|---|---|
--agent <id> | configured default agent | Chooses the private agent namespace. Supported on list, search, query, and stats. |
--cols <columns> | id,text,importance,category,createdAt | A comma-separated allowlist of columns. |
--filter <condition> | none | A single comparison against an output column, for instance category = 'preference' or importance >= 0.8. String values need quotes. |
--limit <n> | 10 | Must be a positive integer. |
--order-by <column>:<asc|desc> | none | Sorting happens in memory after filtering; the sort column is added to the projection automatically and removed from the result if it wasn't requested. |
The active memory plugin supplies agents with three tools:
memory_recall: performs vector search across stored memories.memory_store: records a fact, preference, decision, or entity (rejects text resembling a prompt-injection payload; skips near-duplicate stores).memory_forget: removes bymemoryId, or byquery(auto-deletes a single match above 90% score, otherwise lists candidate IDs to disambiguate).
Storage
LanceDB data defaults to ~/.openclaw/memory/lancedb. Use dbPath to override:
{
plugins: {
entries: {
"memory-lancedb": {
enabled: true,
config: {
dbPath: "~/.openclaw/memory/lancedb",
embedding: {
apiKey: "${OPENAI_API_KEY}",
model: "text-embedding-3-small",
},
},
},
},
},
}
The plugin maintains a single LanceDB table, with a normalized agent owner on each
row. This acts as a storage boundary, not a post-search filter: agent ownership
is enforced before vector ranking and appears in list, query, count, and delete
predicates. ltm query --filter accepts one validated comparison over the
public output columns. The store builds that comparison separately from the
mandatory owner predicate, so a filter cannot widen the query to another
agent.
Databases created before per-agent ownership lack reliable row provenance.
On upgrade, openclaw doctor --fix assigns those legacy rows once to the
configured default agent. Runtime access fails closed until that migration has
completed; other agents never inherit the old shared rows.
storageOptions accepts string key/value pairs for LanceDB storage backends
(e.g. S3-compatible object storage) and supports ${ENV_VAR} expansion:
{
plugins: {
entries: {
"memory-lancedb": {
enabled: true,
config: {
dbPath: "s3://memory-bucket/openclaw",
storageOptions: {
access_key: "${AWS_ACCESS_KEY_ID}",
secret_key: "${AWS_SECRET_ACCESS_KEY}",
endpoint: "${AWS_ENDPOINT_URL}",
},
embedding: {
apiKey: "${OPENAI_API_KEY}",
model: "text-embedding-3-small",
},
},
},
},
},
}
Runtime dependencies and platform support
memory-lancedb depends on the native @lancedb/lancedb package, owned by the
plugin package (not the OpenClaw core dist). Gateway startup does not repair
plugin dependencies; if the native dependency is missing or fails to load,
reinstall or update the plugin package and restart the Gateway.
@lancedb/lancedb does not publish a native build for darwin-x64 (Intel
Mac). On that platform the plugin logs that LanceDB is unavailable at load
time; use the default memory backend, run the Gateway on a supported
platform/architecture, or disable memory-lancedb.
Troubleshooting
Input length exceeds the context length
The embedding model rejected the recall query:
memory-lancedb: recall failed: Error: 400 the input length exceeds the context length
Lower recallMaxChars; the new limit applies to the next memory operation:
{
plugins: {
entries: {
"memory-lancedb": {
config: {
recallMaxChars: 400,
},
},
},
},
}
For Ollama, also verify the embedding server is reachable from the Gateway host using its native embed endpoint:
curl http://127.0.0.1:11434/api/embed \
-H "Content-Type: application/json" \
-d '{"model":"mxbai-embed-large","input":"hello"}'
Unsupported embedding model
Without embedding.dimensions, only the built-in OpenAI embedding dimensions
are known (text-embedding-3-small, text-embedding-3-large). For any other
model, set embedding.dimensions to the vector size that model reports.
Plugin loads but no memories appear
Confirm plugins.slots.memory points at memory-lancedb, then run:
openclaw ltm stats
openclaw ltm search "recent preference"
If autoCapture is disabled, the plugin still recalls existing memories but
does not store new ones automatically. Use the memory_store tool, or enable
autoCapture.