Memory configuration reference
This page lists every configuration knob for OpenClaw memory search. For
conceptual overviews, see:
All memory search settings live under agents.defaults.memorySearch in
openclaw.json unless noted otherwise.
Provider selection
| Key | Type | Default | Description |
|---|
provider | string | auto-detected | Embedding adapter ID: openai, gemini, voyage, mistral, ollama, local |
model | string | provider default | Embedding model name |
fallback | string | "none" | Fallback adapter ID when the primary fails |
enabled | boolean | true | Enable or disable memory search |
Auto-detection order
When provider is not set, OpenClaw selects the first available:
local — if memorySearch.local.modelPath is configured and the file exists.
openai — if an OpenAI key can be resolved.
gemini — if a Gemini key can be resolved.
voyage — if a Voyage key can be resolved.
mistral — if a Mistral key can be resolved.
ollama is supported but not auto-detected (set it explicitly).
API key resolution
Remote embeddings require an API key. OpenClaw resolves from:
auth profiles, models.providers.*.apiKey, or environment variables.
| Provider | Env var | Config key |
|---|
| OpenAI | OPENAI_API_KEY | models.providers.openai.apiKey |
| Gemini | GEMINI_API_KEY | models.providers.google.apiKey |
| Voyage | VOYAGE_API_KEY | models.providers.voyage.apiKey |
| Mistral | MISTRAL_API_KEY | models.providers.mistral.apiKey |
| Ollama | OLLAMA_API_KEY (placeholder) | — |
Codex OAuth covers chat/completions only and does not satisfy embedding
requests.
Remote endpoint config
For custom OpenAI-compatible endpoints or overriding provider defaults:
| Key | Type | Description |
|---|
remote.baseUrl | string | Custom API base URL |
remote.apiKey | string | Override API key |
remote.headers | object | Extra HTTP headers (merged with provider defaults) |
{
agents: {
defaults: {
memorySearch: {
provider: "openai",
model: "text-embedding-3-small",
remote: {
baseUrl: "https://api.example.com/v1/",
apiKey: "YOUR_KEY",
},
},
},
},
}
Gemini-specific config
| Key | Type | Default | Description |
|---|
model | string | gemini-embedding-001 | Also supports gemini-embedding-2-preview |
outputDimensionality | number | 3072 | For Embedding 2: 768, 1536, or 3072 |
Changing model or outputDimensionality triggers an automatic full reindex.
Local embedding config
| Key | Type | Default | Description |
|---|
local.modelPath | string | auto-downloaded | Path to GGUF model file |
local.modelCacheDir | string | node-llama-cpp default | Cache dir for downloaded models |
Default model: embeddinggemma-300m-qat-Q8_0.gguf (~0.6 GB, auto-downloaded).
Requires native build: pnpm approve-builds then pnpm rebuild node-llama-cpp.
Hybrid search config
All under memorySearch.query.hybrid:
| Key | Type | Default | Description |
|---|
enabled | boolean | true | Enable hybrid BM25 + vector search |
vectorWeight | number | 0.7 | Weight for vector scores (0-1) |
textWeight | number | 0.3 | Weight for BM25 scores (0-1) |
candidateMultiplier | number | 4 | Candidate pool size multiplier |
MMR (diversity)
| Key | Type | Default | Description |
|---|
mmr.enabled | boolean | false | Enable MMR re-ranking |
mmr.lambda | number | 0.7 | 0 = max diversity, 1 = max relevance |
Temporal decay (recency)
| Key | Type | Default | Description |
|---|
temporalDecay.enabled | boolean | false | Enable recency boost |
temporalDecay.halfLifeDays | number | 30 | Score halves every N days |
Evergreen files (MEMORY.md, non-dated files in memory/) are never decayed.
Full example
{
agents: {
defaults: {
memorySearch: {
query: {
hybrid: {
vectorWeight: 0.7,
textWeight: 0.3,
mmr: { enabled: true, lambda: 0.7 },
temporalDecay: { enabled: true, halfLifeDays: 30 },
},
},
},
},
},
}
Additional memory paths
| Key | Type | Description |
|---|
extraPaths | string[] | Additional directories or files to index |
{
agents: {
defaults: {
memorySearch: {
extraPaths: ["../team-docs", "/srv/shared-notes"],
},
},
},
}
Paths can be absolute or workspace-relative. Directories are scanned
recursively for .md files. Symlinks are ignored.
Multimodal memory (Gemini)
Index images and audio alongside Markdown using Gemini Embedding 2:
| Key | Type | Default | Description |
|---|
multimodal.enabled | boolean | false | Enable multimodal indexing |
multimodal.modalities | string[] | — | ["image"], ["audio"], or ["all"] |
multimodal.maxFileBytes | number | 10000000 | Max file size for indexing |
Only applies to files in extraPaths. Default memory roots stay Markdown-only.
Requires gemini-embedding-2-preview. fallback must be "none".
Supported formats: .jpg, .jpeg, .png, .webp, .gif, .heic, .heif
(images); .mp3, .wav, .ogg, .opus, .m4a, .aac, .flac (audio).
Embedding cache
| Key | Type | Default | Description |
|---|
cache.enabled | boolean | false | Cache chunk embeddings in SQLite |
cache.maxEntries | number | 50000 | Max cached embeddings |
Prevents re-embedding unchanged text during reindex or transcript updates.
Batch indexing
| Key | Type | Default | Description |
|---|
remote.batch.enabled | boolean | false | Enable batch embedding API |
remote.batch.concurrency | number | 2 | Parallel batch jobs |
remote.batch.wait | boolean | true | Wait for batch completion |
remote.batch.pollIntervalMs | number | — | Poll interval |
remote.batch.timeoutMinutes | number | — | Batch timeout |
Available for openai, gemini, and voyage. OpenAI batch is typically
fastest and cheapest for large backfills.
Session memory search (experimental)
Index session transcripts and surface them via memory_search:
| Key | Type | Default | Description |
|---|
experimental.sessionMemory | boolean | false | Enable session indexing |
sources | string[] | ["memory"] | Add "sessions" to include transcripts |
sync.sessions.deltaBytes | number | 100000 | Byte threshold for reindex |
sync.sessions.deltaMessages | number | 50 | Message threshold for reindex |
Session indexing is opt-in and runs asynchronously. Results can be slightly
stale. Session logs live on disk, so treat filesystem access as the trust
boundary.
SQLite vector acceleration (sqlite-vec)
| Key | Type | Default | Description |
|---|
store.vector.enabled | boolean | true | Use sqlite-vec for vector queries |
store.vector.extensionPath | string | bundled | Override sqlite-vec path |
When sqlite-vec is unavailable, OpenClaw falls back to in-process cosine
similarity automatically.
Index storage
| Key | Type | Default | Description |
|---|
store.path | string | ~/.openclaw/memory/{agentId}.sqlite | Index location (supports {agentId} token) |
store.fts.tokenizer | string | unicode61 | FTS5 tokenizer (unicode61 or trigram) |
QMD backend config
Set memory.backend = "qmd" to enable. All QMD settings live under
memory.qmd:
| Key | Type | Default | Description |
|---|
command | string | qmd | QMD executable path |
searchMode | string | search | Search command: search, vsearch, query |
includeDefaultMemory | boolean | true | Auto-index MEMORY.md + memory/**/*.md |
paths[] | array | — | Extra paths: { name, path, pattern? } |
sessions.enabled | boolean | false | Index session transcripts |
sessions.retentionDays | number | — | Transcript retention |
sessions.exportDir | string | — | Export directory |
Update schedule
| Key | Type | Default | Description |
|---|
update.interval | string | 5m | Refresh interval |
update.debounceMs | number | 15000 | Debounce file changes |
update.onBoot | boolean | true | Refresh on startup |
update.waitForBootSync | boolean | false | Block startup until refresh completes |
update.embedInterval | string | — | Separate embed cadence |
update.commandTimeoutMs | number | — | Timeout for QMD commands |
Limits
| Key | Type | Default | Description |
|---|
limits.maxResults | number | 6 | Max search results |
limits.maxSnippetChars | number | — | Clamp snippet length |
limits.maxInjectedChars | number | — | Clamp total injected chars |
limits.timeoutMs | number | 4000 | Search timeout |
Scope
Controls which sessions can receive QMD search results. Same schema as
session.sendPolicy:
{
memory: {
qmd: {
scope: {
default: "deny",
rules: [{ action: "allow", match: { chatType: "direct" } }],
},
},
},
}
Default is DM-only. match.keyPrefix matches the normalized session key;
match.rawKeyPrefix matches the raw key including agent:<id>:.
Citations
memory.citations applies to all backends:
| Value | Behavior |
|---|
auto (default) | Include Source: <path#line> footer in snippets |
on | Always include footer |
off | Omit footer (path still passed to agent internally) |
Full QMD example
{
memory: {
backend: "qmd",
citations: "auto",
qmd: {
includeDefaultMemory: true,
update: { interval: "5m", debounceMs: 15000 },
limits: { maxResults: 6, timeoutMs: 4000 },
scope: {
default: "deny",
rules: [{ action: "allow", match: { chatType: "direct" } }],
},
paths: [{ name: "docs", path: "~/notes", pattern: "**/*.md" }],
},
},
}