* docs: correct retired cron/audit config keys, cron failure-alert default, memory recall default, and tool-search telemetry claims - configuration-reference: cron block documented cron.webhook and cron.failureDestination, both retired by the config-surface reduction tranches (58452de711,edecdbd05e); the cron schema is strict so a copied snippet is rejected. Document only the live keys and note the doctor --fix migrations. - configuration-reference: root-level audit block is retired; canonical path is logging.audit (src/config/zod-schema.root-shape.ts). - configuration-reference: cron.failureAlert.after default is 2, not 3 (src/cron/service/failure-alerts.ts). - memory-config: rememberAcrossConversations defaults on for personal installs (packages/memory-host-sdk/src/host/config-utils.ts), matching the canonical table earlier in the page. - tool-search: telemetry records catalogSize, per-source counts, and search/describe/call counts, and only on tool_search_code results. No byte accounting exists in the runtime. * docs: retire remaining references to removed cron, audit, and logging config keys Sweep follow-up to the previous commit, covering the same bug class in the pages that still contradicted it. - cron-jobs/cli-cron: global cron.failureDestination is retired; the destination fields now live on cron.failureAlert (src/config/zod-schema.root-shape.ts, merged by legacy-config-migrations.runtime.retired.ts:379). Per-job delivery.failureDestination bullets left intact. - gateway/audit, cli/audit, gateway/protocol: root-level audit.* is retired; canonical path is logging.audit.*. - logging: logging.redactSensitive is retired (dead-config-keys.test.ts:198; removed by legacy-config-migrations.runtime.tier-eval.ts:12). resolveConfigRedaction hardcodes DEFAULT_REDACT_MODE = tools, so redaction is unconditional. Also documented that redactPatterns replaces the defaults on the log path (redact.ts:419) while tool payloads always merge them. - logging: consoleStyle accepts only pretty|json (zod-schema.root-shape.ts:106); compact remains the automatic non-TTY rendering style (logging/console.ts:40) but is no longer settable, and doctor maps a stored one to pretty. - security: security --fix no longer touches redaction and the logging.redact_off audit check is retired (src/security/audit-loopback-logging.test.ts asserts it never fires). * chore(docs): regenerate docs map after retired-key cleanup
34 KiB
summary, title, sidebarTitle, read_when
| summary | title | sidebarTitle | read_when | ||||
|---|---|---|---|---|---|---|---|
| Memory search providers, retrieval modes, QMD, and multimodal indexing | Memory configuration reference | Memory config |
|
This page lists every configuration knob for OpenClaw memory search. For conceptual overviews, see:
How memory works. Default SQLite backend. Local-first sidecar. Search pipeline and tuning. Memory sub-agent for interactive sessions.All shared memory settings live under top-level memory in openclaw.json. Search defaults use memory.search; per-agent search overrides use agents.entries.*.memory.search.
See Active Memory for both activation paths, transcript persistence, and safe rollout guidance.
Remember across conversations
| Key | Type | Default | Description |
|---|---|---|---|
rememberAcrossConversations |
boolean |
On for personal installs; off with configured DM isolation | Use relevant context from this agent's other recognized private conversations. |
Configure it per agent when only a trusted personal agent should use cross-conversation transcript recall:
{
agents: {
entries: {
personal: {
memory: {
search: {
rememberAcrossConversations: true,
},
},
},
},
},
}
The value follows normal memory.search inheritance with a
per-agent override. When unset, it defaults on only if global
session.dmScope is unset or "main" and no binding has a session.dmScope
override. Any configured DM isolation defaults it off. An explicit true or
false always wins. Enabling it implies session transcript indexing and
adds sessions to the agent's resolved memory sources. With QMD, it also
enables that agent's session export; no separate
memory.qmd.sessions.enabled setting is required for this mode.
OpenClaw's built-in memory provider supports this protected path with both the
builtin and QMD backends. Alternate memory providers can keep using their own
recall hooks and advanced Active Memory tools, but this setting is skipped
unless the current provider supports protected private transcript recall.
openclaw doctor reports an unsupported provider or an explicit Active Memory
toolsAllow list that omits memory_search.
The retrieval boundary is narrower than general session search:
- only the same agent's recognized private conversations are eligible
- the conversation being answered is excluded
- groups and channels are excluded as sources and destinations
- unknown conversation kinds fail closed
- sandboxed recall cannot use the special cross-conversation authorization
The setting does not change tools.sessions.visibility, session keys,
transcript storage, delivery routing, or the permissions of sessions_list,
sessions_history, and sessions_send. Active Memory performs a bounded
read-only retrieval pass; unavailable or timed-out retrieval does not block the
reply.
Provider selection
| Key | Type | Default | Description |
|---|---|---|---|
enabled |
boolean |
true |
Enable or disable memory search |
provider |
string |
"openai" |
Embedding adapter ID such as bedrock, deepinfra, gemini, github-copilot, local, mistral, ollama, openai, openai-compatible, or voyage; may also be a configured models.providers.<id> whose api points at a memory embedding adapter or OpenAI-compatible model API |
model |
string |
provider default | Embedding model name |
fallback |
string |
"none" |
Fallback adapter ID when the primary fails |
When provider is not set, OpenClaw uses OpenAI embeddings. Set provider
explicitly to use Bedrock, DeepInfra, Gemini, GitHub Copilot, Mistral, Ollama,
Voyage, a local GGUF model, or an OpenAI-compatible /v1/embeddings endpoint.
Legacy configs that still say provider: "auto" resolve to openai.
When provider is unset, legacy provider: "auto" is present, or
provider: "none" intentionally selects FTS-only mode, memory recall can still
use lexical FTS ranking when embeddings are unavailable.
Explicit non-local providers fail closed. If you set memory.search.provider to
a concrete remote-backed provider such as Bedrock, DeepInfra, Gemini, GitHub
Copilot, LM Studio, Mistral, Ollama, OpenAI, Voyage, or an OpenAI-compatible
custom provider, and that provider is unavailable at runtime, memory_search
returns an unavailable result instead of silently using FTS-only recall. Fix the
provider/auth configuration, switch to a reachable provider, or set
provider: "none" if you want deliberate FTS-only recall.
Custom provider ids
memory.search.provider can point at a custom models.providers.<id> entry for memory-specific provider adapters such as ollama, or for OpenAI-compatible model APIs such as openai-responses / openai-completions. OpenClaw resolves that provider's api owner for the embedding adapter while preserving the custom provider id for endpoint, auth, and model-prefix handling. This lets multi-GPU or multi-host setups dedicate memory embeddings to a specific local endpoint:
{
models: {
providers: {
"ollama-5080": {
api: "ollama",
baseUrl: "http://gpu-box.local:11435",
apiKey: "ollama-local",
models: [{ id: "qwen3-embedding:0.6b", name: "Qwen3 Embedding 0.6B" }],
},
},
},
memory: {
search: {
provider: "ollama-5080",
model: "qwen3-embedding:0.6b",
},
},
}
API key resolution
Remote embeddings require an API key. Bedrock uses the AWS SDK default credential chain instead (instance roles, SSO, access keys, or a Bedrock API key).
| Provider | Env var | Config key |
|---|---|---|
| Bedrock | AWS credential chain, or AWS_BEARER_TOKEN_BEDROCK |
No API key needed |
| DeepInfra | DEEPINFRA_API_KEY |
models.providers.deepinfra.apiKey |
| Gemini | GEMINI_API_KEY |
models.providers.google.apiKey |
| GitHub Copilot | COPILOT_GITHUB_TOKEN, GH_TOKEN, GITHUB_TOKEN |
Auth profile via device login |
| Mistral | MISTRAL_API_KEY |
models.providers.mistral.apiKey |
| Ollama | OLLAMA_API_KEY (placeholder) |
-- |
| OpenAI | OPENAI_API_KEY |
models.providers.openai.apiKey |
| Voyage | VOYAGE_API_KEY |
models.providers.voyage.apiKey |
Remote endpoint config
Use provider: "openai-compatible" for a generic OpenAI-compatible
/v1/embeddings server that should not inherit global OpenAI chat credentials.
{
memory: {
search: {
provider: "openai-compatible",
model: "text-embedding-3-small",
remote: {
baseUrl: "https://api.example.com/v1/",
apiKey: "YOUR_KEY",
},
},
},
}
Provider-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 |<Warning>
Changing model or `outputDimensionality` changes the index identity. OpenClaw
pauses vector search until you explicitly rebuild the memory index.
</Warning>
OpenAI-compatible embedding endpoints can opt into provider-specific `input_type` request fields. This is useful for asymmetric embedding models that require different labels for query and document embeddings.
| Key | Type | Default | Description |
| ------------------- | -------- | ------- | -------------------------------------------------------- |
| `inputType` | `string` | unset | Shared `input_type` for query and document embeddings |
| `queryInputType` | `string` | unset | Query-time `input_type`; overrides `inputType` |
| `documentInputType` | `string` | unset | Index/document `input_type`; overrides `inputType` |
```json5
{
memory: {
search: {
provider: "openai-compatible",
remote: {
baseUrl: "https://embeddings.example/v1",
apiKey: "${EMBEDDINGS_API_KEY}",
},
model: "asymmetric-embedder",
queryInputType: "query",
documentInputType: "passage",
},
},
}
```
Changing these values affects embedding cache identity for provider batch indexing and should be followed by a memory reindex when the upstream model treats the labels differently.
### Bedrock embedding config
Bedrock uses the AWS SDK default credential chain plus an OpenClaw-checked bearer token, so no API keys are stored in config. If OpenClaw runs on EC2 with a Bedrock-enabled instance role, just set the provider and model:
```json5
{
memory: {
search: {
provider: "bedrock",
model: "amazon.titan-embed-text-v2:0",
},
},
}
```
| Key | Type | Default | Description |
| ---------------------- | -------- | ------------------------------- | -------------------------------- |
| `model` | `string` | `amazon.titan-embed-text-v2:0` | Any Bedrock embedding model ID |
| `outputDimensionality` | `number` | model default | For Titan V2: 256, 512, or 1024 |
**Supported models** (with family detection and dimension defaults):
| Model ID | Provider | Default Dims | Configurable Dims |
| ------------------------------------------- | ---------- | ------------- | -------------------------- |
| `amazon.titan-embed-text-v2:0` | Amazon | 1024 | 256, 512, 1024 |
| `amazon.titan-embed-text-v1` | Amazon | 1536 | -- |
| `amazon.titan-embed-g1-text-02` | Amazon | 1536 | -- |
| `amazon.titan-embed-image-v1` | Amazon | 1024 | -- |
| `amazon.nova-2-multimodal-embeddings-v1:0` | Amazon | 1024 | 256, 384, 1024, 3072 |
| `cohere.embed-english-v3` | Cohere | 1024 | -- |
| `cohere.embed-multilingual-v3` | Cohere | 1024 | -- |
| `cohere.embed-v4:0` | Cohere | 1536 | 256, 384, 512, 768, 1024, 1536 |
| `twelvelabs.marengo-embed-3-0-v1:0` | TwelveLabs | 512 | -- |
| `twelvelabs.marengo-embed-2-7-v1:0` | TwelveLabs | 1024 | -- |
Throughput-suffixed variants (e.g., `amazon.titan-embed-text-v1:2:8k`) and region-prefixed inference profile IDs (e.g., `us.amazon.titan-embed-text-v2:0`) inherit the base model's configuration.
**Region:** resolved in this order: the `memory.search.remote.baseUrl` override, the `models.providers.amazon-bedrock.baseUrl` config, `AWS_REGION`, `AWS_DEFAULT_REGION`, then a default of `us-east-1`.
**Authentication:** OpenClaw checks for `AWS_ACCESS_KEY_ID` + `AWS_SECRET_ACCESS_KEY` or `AWS_BEARER_TOKEN_BEDROCK` first, then falls through to the standard AWS SDK default credential provider chain:
1. Environment variables (`AWS_ACCESS_KEY_ID` + `AWS_SECRET_ACCESS_KEY`), unless `AWS_PROFILE` is also set
2. SSO (only when SSO fields are configured)
3. Shared credentials and config files (`fromIni`, includes `AWS_PROFILE`)
4. Credential process (`credential_process` in the AWS config file)
5. Web identity token credentials
6. ECS or EC2 instance metadata credentials
**IAM permissions:** the IAM role or user needs:
```json
{
"Effect": "Allow",
"Action": "bedrock:InvokeModel",
"Resource": "*"
}
```
For least-privilege, scope `InvokeModel` to the specific model:
```text
arn:aws:bedrock:*::foundation-model/amazon.titan-embed-text-v2:0
```
| 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 |
| `local.contextSize` | `number \| "auto"` | `4096` | Context window size for the embedding context. 4096 covers typical chunks (128-512 tokens) while bounding non-weight VRAM. Lower to 1024-2048 on constrained hosts. `"auto"` uses the model's trained maximum -- not recommended for 8B+ models (Qwen3-Embedding-8B: up to 40 960 tokens can push VRAM to ~32 GB). |
Install the official llama.cpp provider first: `openclaw plugins install @openclaw/llama-cpp-provider`.
Default model: `embeddinggemma-300m-qat-Q8_0.gguf` (~0.6 GB, auto-downloaded). Source checkouts still require native build approval: `pnpm approve-builds` then `pnpm rebuild node-llama-cpp`.
Use the standalone CLI to verify the same provider path the Gateway uses:
```bash
openclaw memory status --deep --agent main
openclaw memory index --force --agent main
```
Numeric `local.contextSize` values also inform node-llama-cpp's automatic GPU-layer placement so model weights and the requested embedding context are fitted together. `openclaw memory status --deep` reports last-known llama.cpp backend, device, offload, requested-context, and timestamped memory facts after the runtime has loaded; passive status does not load a model.
Set `provider: "local"` explicitly for local GGUF embeddings. `hf:` and HTTP(S) model references are supported for explicit local configs (via node-llama-cpp's model resolution), but they do not change the default provider.
Indexing behavior
Memory engines own synchronization, batching, watch, and post-compaction indexing heuristics. OpenClaw keeps these behaviors enabled with maintained defaults rather than exposing per-install timing switches.
Hybrid search config
All under memory.search.query:
| Key | Type | Default | Description |
|---|---|---|---|
maxResults |
number |
6 |
Max memory hits returned before injection |
minScore |
number |
0.35 |
Minimum relevance score to include a hit |
Hybrid retrieval remains enabled; MMR and temporal decay remain disabled by the built-in engine policy.
Full example
{
memory: {
search: {
query: {
maxResults: 6,
minScore: 0.35,
},
},
},
}
Additional memory paths
| Key | Type | Description |
|---|---|---|
extraPaths |
string[] |
Additional directories or files to index |
{
memory: {
search: {
extraPaths: ["../team-docs", "/srv/shared-notes"],
},
},
}
Paths can be absolute or workspace-relative. Directories are scanned recursively for .md files. Symlink handling depends on the active backend: the builtin engine skips symlinks, while QMD follows the underlying QMD scanner behavior.
For agent-scoped cross-agent transcript search, use agents.entries.*.memory.search.qmd.extraCollections instead of memory.qmd.paths. Those extra collections follow the same { path, name, pattern? } shape, but they are merged per agent and can preserve explicit shared names when the path points outside the current workspace. If the same resolved path appears in both memory.qmd.paths and memory.search.qmd.extraCollections, QMD keeps the first entry and skips the duplicate.
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 |
10485760 |
Max file size for indexing (10 MiB) |
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 |
true |
Cache chunk embeddings in SQLite |
Prevents re-embedding unchanged text during reindex or transcript updates.
Batch indexing
| Key | Type | Default | Description |
|---|---|---|---|
remote.nonBatchConcurrency |
number |
4 |
Parallel inline embeddings |
remote.batch.enabled |
boolean |
false |
Enable batch embedding API |
Available for gemini, openai, and voyage. OpenAI batch is typically fastest and cheapest for large backfills.
Concurrency, polling, and timeout behavior are provider-owned.
Session memory search
Index session transcripts and surface them via memory_search:
| Key | Type | Default | Description |
|---|---|---|---|
rememberAcrossConversations |
boolean |
On for personal installs; off with configured DM isolation | Permit private cross-conversation recall |
sources |
string[] |
["memory"] |
Add "sessions" to include transcripts |
Ordinary model-invoked session transcript search obeys
tools.sessions.visibility. The default
tree visibility exposes the current session, sessions it spawned, and
same-agent group sessions watched through ambient group awareness. Other
unrelated sessions require agent visibility (or all only when cross-agent
recall is also required and agent-to-agent policy allows it).
rememberAcrossConversations does not widen that setting. It supplies a
separate runtime-only authorization limited to same-agent private
transcripts during the bounded Active Memory pass.
The examples below place these settings under top-level memory.search. You can also
apply equivalent settings in a per-agent memory.search override when only one
agent should index and search session transcripts.
For same-agent gateway-to-DM recall:
```json5 { memory: { search: { experimental: { sessionMemory: true }, sources: ["memory", "sessions"], }, }, tools: { sessions: { visibility: "agent" }, }, } ``` ```json5 { memory: { backend: "qmd", search: { experimental: { sessionMemory: true }, sources: ["memory", "sessions"], }, qmd: { sessions: { enabled: true }, }, }, tools: { sessions: { visibility: "agent" }, }, } ```When using QMD, sources: ["sessions"] does not by itself export transcripts into QMD. Set
memory.qmd.sessions.enabled: true as well. The higher-level
rememberAcrossConversations: true setting is the exception: it implies the
required QMD session export for that agent. Implied exports stay private:
they always use the default internal export location (a configured
sessions.exportDir applies only to explicit exports), they are searched only
during that agent's cross-conversation recall, and ordinary memory_get
cannot read them. Explicit
memory.qmd.sessions.enabled: true keeps its existing behavior and makes
exported transcripts part of the ordinary memory corpus.
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
Built-in memory indexes live in each agent's OpenClaw SQLite database at
agents/<agentId>/agent/openclaw-agent.sqlite.
| Key | Type | Default | Description |
|---|---|---|---|
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; set an absolute path when service PATH differs from your shell |
searchMode |
string |
search |
Search command: search, vsearch, query |
rerank |
boolean |
-- | Set to false with searchMode: "query" and QMD 2.1+ to skip QMD reranking |
includeDefaultMemory |
boolean |
true |
Auto-index MEMORY.md + memory/**/*.md |
paths[] |
array |
-- | Extra paths: { name, path, pattern? } |
sessions.enabled |
boolean |
false |
Export session transcripts into QMD |
sessions.retentionDays |
number |
-- | Transcript retention |
sessions.exportDir |
string |
-- | Export directory |
searchMode: "search" is lexical/BM25-only. OpenClaw does not run semantic vector readiness probes or QMD embedding maintenance for that mode, including during memory status --deep; vsearch and query continue to require QMD vector readiness and embeddings.
rerank: false only changes QMD query mode and requires QMD 2.1 or newer. In direct CLI mode OpenClaw passes --no-rerank; in mcporter-backed MCP mode it passes rerank: false to QMD's unified query tool. Leave it unset to use QMD's default query reranking behavior.
OpenClaw prefers current QMD collection and MCP query shapes, but keeps older QMD releases working by trying compatible collection pattern flags and older MCP tool names when needed. When QMD advertises support for multiple collection filters, same-source collections are searched with one QMD process; older QMD builds keep the per-collection compatibility path. Same-source means durable memory collections (default memory files plus custom paths) are grouped together, while session transcript collections remain a separate group so source diversification still has both inputs.
QMD model overrides stay on the QMD side, not OpenClaw config. If you need to override QMD's models globally, set environment variables such as `QMD_EMBED_MODEL`, `QMD_RERANK_MODEL`, and `QMD_GENERATE_MODEL` in the gateway runtime environment. | Key | Type | Default | Description | | --------------------------- | -------- | ------- | ------------------------------ | | `limits.maxResults` | `number` | `4` | Max search results | | `limits.maxSnippetChars` | `number` | `450` | Clamp snippet length | | `limits.maxInjectedChars` | `number` | `2200` | Clamp total injected chars | | `limits.timeoutMs` | `number` | `4000` | QMD command timeout during QMD-backed search, including `memory_search`; setup, sync, builtin fallback, and supplemental work keep the default tool deadline | Controls which sessions can receive QMD search results. Same schema as [`session.sendPolicy`](/gateway/config-agents#session):```json5
{
memory: {
qmd: {
scope: {
default: "deny",
rules: [{ action: "allow", match: { chatType: "direct" } }],
},
},
},
}
```
The shipped default is DM/direct-only, denying groups and other channel types. `match.keyPrefix` matches the normalized session key; `match.rawKeyPrefix` matches the raw key including `agent:<id>:`.
`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) |
QMD initializes lazily when memory is first used; its adapter owns refresh and embedding schedules.
Full QMD example
{
memory: {
backend: "qmd",
citations: "auto",
qmd: {
includeDefaultMemory: true,
update: { interval: "5m", debounceMs: 15000 },
limits: { maxResults: 4, timeoutMs: 4000 },
scope: {
default: "deny",
rules: [{ action: "allow", match: { chatType: "direct" } }],
},
paths: [{ name: "docs", path: "~/notes", pattern: "**/*.md" }],
},
},
}
Dreaming
Dreaming is configured under plugins.entries.memory-core.config.dreaming, not under memory.search.
Dreaming runs as one scheduled sweep and uses internal light/deep/REM phases as an implementation detail.
For conceptual behavior and slash commands, see Dreaming.
User settings
| Key | Type | Default | Description |
|---|---|---|---|
enabled |
boolean |
false |
Enable or disable dreaming entirely |
frequency |
string |
0 3 * * * |
Optional cron cadence for the full dreaming sweep |
model |
string |
default model | Optional Dream Diary subagent model override |
phases.deep.maxPromotedSnippetTokens |
number |
160 |
Maximum estimated tokens kept from each short-term recall snippet promoted into MEMORY.md; provenance metadata remains visible |
Example
{
plugins: {
entries: {
"memory-core": {
subagent: {
allowModelOverride: true,
allowedModels: ["anthropic/claude-sonnet-4-6"],
},
config: {
dreaming: {
enabled: true,
frequency: "0 3 * * *",
model: "anthropic/claude-sonnet-4-6",
},
},
},
},
},
}