mirror of https://github.com/openclaw/openclaw.git
164 lines
4.9 KiB
Markdown
164 lines
4.9 KiB
Markdown
---
|
|
title: "QMD Memory Engine"
|
|
summary: "Local-first search sidecar with BM25, vectors, reranking, and query expansion"
|
|
read_when:
|
|
- You want to set up QMD as your memory backend
|
|
- You want advanced memory features like reranking or extra indexed paths
|
|
---
|
|
|
|
# QMD Memory Engine
|
|
|
|
[QMD](https://github.com/tobi/qmd) is a local-first search sidecar that runs
|
|
alongside OpenClaw. It combines BM25, vector search, and reranking in a single
|
|
binary, and can index content beyond your workspace memory files.
|
|
|
|
## What it adds over builtin
|
|
|
|
- **Reranking and query expansion** for better recall.
|
|
- **Index extra directories** -- project docs, team notes, anything on disk.
|
|
- **Index session transcripts** -- recall earlier conversations.
|
|
- **Fully local** -- runs via Bun + node-llama-cpp, auto-downloads GGUF models.
|
|
- **Automatic fallback** -- if QMD is unavailable, OpenClaw falls back to the
|
|
builtin engine seamlessly.
|
|
|
|
## Getting started
|
|
|
|
### Prerequisites
|
|
|
|
- Install QMD: `bun install -g @tobilu/qmd`
|
|
- SQLite build that allows extensions (`brew install sqlite` on macOS).
|
|
- QMD must be on the gateway's `PATH`.
|
|
- macOS and Linux work out of the box. Windows is best supported via WSL2.
|
|
|
|
### Enable
|
|
|
|
```json5
|
|
{
|
|
memory: {
|
|
backend: "qmd",
|
|
},
|
|
}
|
|
```
|
|
|
|
OpenClaw creates a self-contained QMD home under
|
|
`~/.openclaw/agents/<agentId>/qmd/` and manages the sidecar lifecycle
|
|
automatically -- collections, updates, and embedding runs are handled for you.
|
|
|
|
## How the sidecar works
|
|
|
|
- OpenClaw creates collections from your workspace memory files and any
|
|
configured `memory.qmd.paths`, then runs `qmd update` + `qmd embed` on boot
|
|
and periodically (default every 5 minutes).
|
|
- Boot refresh runs in the background so chat startup is not blocked.
|
|
- Searches use the configured `searchMode` (default: `search`; also supports
|
|
`vsearch` and `query`). If a mode fails, OpenClaw retries with `qmd query`.
|
|
- If QMD fails entirely, OpenClaw falls back to the builtin SQLite engine.
|
|
|
|
<Info>
|
|
The first search may be slow -- QMD auto-downloads GGUF models (~2 GB) for
|
|
reranking and query expansion on the first `qmd query` run.
|
|
</Info>
|
|
|
|
## Indexing extra paths
|
|
|
|
Point QMD at additional directories to make them searchable:
|
|
|
|
```json5
|
|
{
|
|
memory: {
|
|
backend: "qmd",
|
|
qmd: {
|
|
paths: [{ name: "docs", path: "~/notes", pattern: "**/*.md" }],
|
|
},
|
|
},
|
|
}
|
|
```
|
|
|
|
Snippets from extra paths appear as `qmd/<collection>/<relative-path>` in
|
|
search results. `memory_get` understands this prefix and reads from the correct
|
|
collection root.
|
|
|
|
## Indexing session transcripts
|
|
|
|
Enable session indexing to recall earlier conversations:
|
|
|
|
```json5
|
|
{
|
|
memory: {
|
|
backend: "qmd",
|
|
qmd: {
|
|
sessions: { enabled: true },
|
|
},
|
|
},
|
|
}
|
|
```
|
|
|
|
Transcripts are exported as sanitized User/Assistant turns into a dedicated QMD
|
|
collection under `~/.openclaw/agents/<id>/qmd/sessions/`.
|
|
|
|
## Search scope
|
|
|
|
By default, QMD search results are only surfaced in DM sessions (not groups or
|
|
channels). Configure `memory.qmd.scope` to change this:
|
|
|
|
```json5
|
|
{
|
|
memory: {
|
|
qmd: {
|
|
scope: {
|
|
default: "deny",
|
|
rules: [{ action: "allow", match: { chatType: "direct" } }],
|
|
},
|
|
},
|
|
},
|
|
}
|
|
```
|
|
|
|
When scope denies a search, OpenClaw logs a warning with the derived channel and
|
|
chat type so empty results are easier to debug.
|
|
|
|
## Citations
|
|
|
|
When `memory.citations` is `auto` or `on`, search snippets include a
|
|
`Source: <path#line>` footer. Set `memory.citations = "off"` to omit the footer
|
|
while still passing the path to the agent internally.
|
|
|
|
## When to use
|
|
|
|
Choose QMD when you need:
|
|
|
|
- Reranking for higher-quality results.
|
|
- To search project docs or notes outside the workspace.
|
|
- To recall past session conversations.
|
|
- Fully local search with no API keys.
|
|
|
|
For simpler setups, the [builtin engine](/concepts/memory-builtin) works well
|
|
with no extra dependencies.
|
|
|
|
## Troubleshooting
|
|
|
|
**QMD not found?** Ensure the binary is on the gateway's `PATH`. If OpenClaw
|
|
runs as a service, create a symlink:
|
|
`sudo ln -s ~/.bun/bin/qmd /usr/local/bin/qmd`.
|
|
|
|
**First search very slow?** QMD downloads GGUF models on first use. Pre-warm
|
|
with `qmd query "test"` using the same XDG dirs OpenClaw uses.
|
|
|
|
**Search times out?** Increase `memory.qmd.limits.timeoutMs` (default: 4000ms).
|
|
Set to `120000` for slower hardware.
|
|
|
|
**Empty results in group chats?** Check `memory.qmd.scope` -- the default only
|
|
allows DM sessions.
|
|
|
|
**Workspace-visible temp repos causing `ENAMETOOLONG` or broken indexing?**
|
|
QMD traversal currently follows the underlying QMD scanner behavior rather than
|
|
OpenClaw's builtin symlink rules. Keep temporary monorepo checkouts under
|
|
hidden directories like `.tmp/` or outside indexed QMD roots until QMD exposes
|
|
cycle-safe traversal or explicit exclusion controls.
|
|
|
|
## Configuration
|
|
|
|
For the full config surface (`memory.qmd.*`), search modes, update intervals,
|
|
scope rules, and all other knobs, see the
|
|
[Memory configuration reference](/reference/memory-config).
|