#improve memory using qmd

1 messages · Page 1 of 1 (latest)

unique oreBOT
#

To “maximize QMD for better memory”, the big unlock is: QMD doesn’t create memory by itself — it just makes whatever you store in Markdown much easier to retrieve (BM25 + vectors + reranking). So you want (a) better stuff to index, and (b) QMD configured to index it + refresh it.

Docs: https://docs.openclaw.ai/concepts/memory (see “QMD backend (experimental)”)

1) Make the source memory better (biggest ROI)

Write in a retrieval-friendly way (because QMD is still search):

  • Use consistent headings/structure in MEMORY.md (durable) and memory/YYYY-MM-DD.md (daily).
  • Prefer short, atomic bullets with stable keywords:
    • “Preference: …”
    • “Decision: … (why)”
    • “Project: …”
    • “Owner: …”
  • Include “needles” you’ll later search for: IDs, exact names, repo names, error strings.

And operationally: tell the agent to write memory when something matters (“remember X” → “write this to MEMORY.md under Preferences”).

2) Index more than just the default memory files

#

QMD gets way better when you add your actual notes/docs repo(s):

memory: {
  backend: "qmd",
  qmd: {
    includeDefaultMemory: true, // MEMORY.md + memory/**/*.md
    paths: [
      { name: "notes", path: "~/notes", pattern: "**/*.md" },
      // add other doc roots you actually reference
    ]
  }
}

That’s usually the difference between “it kinda remembers” and “it can actually find things”.

#

3) Turn on session transcript indexing (optional, but powerful)

If your pain is “it can’t remember what we talked about”, enable QMD’s session export/index:

  • memory.qmd.sessions.enabled = true

This lets memory_search recall past conversations via the QMD index (with retention controls). It’s great, but it’s also more data—so only do it if you’re comfortable with that footprint.

4) Don’t get tripped up by “it works in DMs but not in channels”

By default, OpenClaw is conservative about surfacing memory in public/group contexts. With QMD there’s also:

  • memory.qmd.scope (same schema idea as session.sendPolicy)

If you want QMD-backed recall to work inside Discord channels/threads, you may need to explicitly allow those chat types/session key prefixes. (Privacy tradeoff: you’re allowing memory retrieval in a public place.)

5) Practical tuning knobs (usually set-and-forget)

  • Increase freshness: memory.qmd.update.interval (default is 5m)
  • Avoid startup delays: keep memory.qmd.update.waitForBootSync = false (default is background refresh)
#
  • Keep results tight: memory.qmd.limits.maxResults, maxSnippetChars, maxInjectedChars

6) Non-QMD suggestions that still help “memory”

  • Enable/keep the automatic memory flush before compaction (agents.defaults.compaction.memoryFlush) so the agent gets reminded to write things down before context is trimmed.
  • Keep MEMORY.md curated. If it becomes a junk drawer, retrieval quality drops no matter how good QMD is.

If you tell me your use case (personal DM assistant vs server bot; “remember preferences” vs “find stuff in my docs” vs “recall past chats”), I can suggest a good memory: config block + what to store where.

#

For a personal DM relationship-manager assistant, QMD shines when you treat your Markdown memory as a tiny “CRM” with consistent structure. QMD will then retrieve the right person + the right detail reliably (BM25 for exact names/emails + vectors for “what were they into again?”).

Docs (QMD section): https://docs.openclaw.ai/concepts/memory

1) Use a “two-layer” memory layout (profile + timeline)

Instead of dumping everything into one daily log, keep:

A) Per-person profile (stable facts)
Create files like:

  • memory/people/alex-smith.md
  • memory/people/mom.md

Template that works well for retrieval:

  • Identifiers: full name, nicknames, handles, email(s)
  • Relationship: how you know them, context
  • Preferences: likes/dislikes, communication style
  • Important dates: birthday, anniversary, etc.
#
  • Current context: job, city, ongoing topics
  • Do/Don’t: boundaries, sensitive topics
  • Last updated: YYYY-MM-DD

B) Interaction notes (what happened + next action)
Either:

  • append a section per date inside the same person file, or
  • keep separate logs: memory/interactions/2026-03-01-alex-smith.md

Each interaction note should include:

  • date
  • what mattered (2–6 bullets)
  • next action (“Follow up next week about …”)

This beats “general memory” because your retrieval queries are usually “what’s up with this person?” not “what happened on Tuesday?”.

2) Write memories in “searchable bullets”

#

QMD is still search. Help it:

  • include exact tokens you’ll search later: emails, nicknames, company names
  • prefix durable facts with consistent labels like Preference:, Boundary:, Gift idea:, Family:, Work:

Example:

  • Preference: hates voice notes, prefers short emails
  • Gift idea: espresso accessories (mentions La Marzocco)

3) Turn on QMD + (optionally) session indexing

Baseline QMD:

memory: {
  backend: "qmd",
  qmd: {
    includeDefaultMemory: true,
    update: { interval: "5m" },
#
    limits: { maxResults: 6, timeoutMs: 4000 }
  }
}

If your main pain is “it forgets what we talked about”, enable session transcript indexing:

  • memory.qmd.sessions.enabled = true (with retentionDays)

That’s usually a big jump for “relationship manager” behavior because it can recall past chats even if you didn’t manually write a note—but I’d still recommend summarizing into the person files for the best long-term signal-to-noise.

4) Keep it DM-only (privacy + avoids weird group leakage)

Since this is personal + involves contacts/emails, keep memory retrieval scoped to direct chats only (this is the default pattern in the docs via memory.qmd.scope). Don’t loosen it to channels unless you really intend that.

5) Add one simple workflow rule: “after interaction → update profile + next step”

The highest leverage habit is: after sending/reading an email or finishing a chat/call, tell the assistant to:

  1. append a short dated interaction note
#
  1. update the person’s profile if a new durable fact appeared
  2. set a “next action”

That’s what converts “tool access” (browser/contacts/mail) into reliable relationship memory.

If you paste (redacted) what you currently store in memory + what it fails to recall (names? last contact? preferences? birthdays?), I can suggest a concrete file structure + a “memory write” template prompt that makes QMD retrieval snap into place.

scenic solstice
#

Whe using multiple agents/workspaces and the experimental qmd memory, it tries to use a single database for all of it. Which results in errors like:

openclaw[]: Bun v1.3.3 (Linux x64)
openclaw[]: [30.8K blob data]
openclaw[]: 1146 |   }
openclaw[]: 1147 | }
openclaw[]: 1148 |
openclaw[]: 1149 | export function clearCache(db: Database): void {
openclaw[]: 1150 |   db.exec(`DELETE FROM llm_cache`);
openclaw[]:             ^
openclaw[]: SQLiteError: database is locked
openclaw[]:       errno: 5,
openclaw[]:  byteOffset: -1,
openclaw[]:        code: "SQLITE_BUSY"
openclaw[]:       at run (bun:sqlite:322:21)
unique oreBOT
#

That SQLITE_BUSY / “database is locked” is almost always two QMD processes trying to touch the same SQLite file at the same time.

A couple things to check in OpenClaw’s QMD setup:

1) Are you running multiple gateways/instances against the same state dir?

QMD’s per-agent state lives under the OpenClaw state dir, e.g. (from the docs):

~/.openclaw/agents/<agentId>/qmd/…/qmd/index.sqlite

So if you have two gateway processes (or containers) both using the same:

  • OPENCLAW_STATE_DIR (or default ~/.openclaw)
  • and the same agentId (often main)

…they will hammer the same QMD index/cache DB and you’ll see “database is locked”.

Fix: ensure only one gateway is running for that state dir, or give each instance its own state dir (OPENCLAW_STATE_DIR=/some/unique/path), or separate Unix users.

#

2) If you enabled memory.qmd.mcporter: try disabling it for multi-agent

If memory.qmd.mcporter.enabled = true, OpenClaw routes QMD through an mcporter daemon. In multi-agent scenarios that can accidentally turn into “shared daemon/shared state” behavior depending on how it’s launched, which increases the chance of DB contention.

Workaround: set

memory: {
  backend: "qmd",
  qmd: { mcporter: { enabled: false } }
}

3) Reduce background writers (quick mitigation)

Even in a single gateway, lock contention is more likely if QMD is doing frequent background maintenance while you’re searching.

You can mitigate by:

  • increasing memory.qmd.update.debounceMs
  • increasing memory.qmd.update.interval