Rag Memory

Vector memory search and RAG skill for OpenClaw. Provides vector_search tool backed by Qdrant, auto-syncs memory .md files and Postgres records via nomic-embed-text embeddings. Triggers on "search memory", "vector search", "resync memory", "RAG", "qdrant".

Audits

Warn

Install

openclaw skills install rag-memory

RAG Memory Skill

Architecture (as of 2026-04-04)

All files live under ~/.openclaw/skills/rag-memory/ — the single source of truth.

FilePurpose
config.envCredentials and tuning (gitignored)
config.env.exampleTemplate with no secrets (tracked in git)
sync_to_qdrant.pyIngest pipeline: Postgres + .md files → Qdrant
requirements.txtPython deps for sync script
venv/Python virtualenv (gitignored)
plugin/index.jsOpenClaw plugin — registers vector_search tool and before_prompt_build hook
plugin/package.jsonPlugin manifest
plugin/openclaw.plugin.jsonPlugin config schema
systemd/Source-of-truth copies of systemd units (deploy with sudo cp + daemon-reload)
references/config-paths.example.mdFile and credential location template (copy to config-paths.md and fill in)
references/operational.mdWhen/how to use vector_search

Plugin is installed at ~/.openclaw/extensions/rag-memory/ and configured in ~/.openclaw/openclaw.json under plugins.entries.rag-memory.

Qdrant collections: {QDRANT_COLLECTION_PREFIX}_memory (daily logs + facts) and {QDRANT_COLLECTION_PREFIX}_docs (tools + skill docs). 768-dim, nomic-embed-text via OpenAI-compatible embedding endpoint.


When to use vector_search

Always prefer vector_search over reading full memory files:

  • Before reading any daily log or MEMORY.md → scope: memory
  • Before reading TOOLS.md or any SKILL.md → scope: docs
  • Unsure → scope: all

Only fall back to reading the file directly if vector_search returns no results.


Sync management

TaskCommand
Incremental sync (unsynced rows only)~/.openclaw/skills/rag-memory/venv/bin/python ~/.openclaw/skills/rag-memory/sync_to_qdrant.py
Full resync (rebuild all vectors)... sync_to_qdrant.py --full
Single file... sync_to_qdrant.py --file /path/to/file.md

Incremental sync also fires automatically when any .md file changes in ~/.openclaw/workspace/memory/ (via sysclaw-rag-watch.path). Nightly full sync runs at 03:00 (sysclaw-rag-sync.timer).


Updating the plugin

If plugin/index.js is changed:

SKILL=~/.openclaw/skills/rag-memory
openclaw plugins install $SKILL/plugin
openclaw gateway restart

If config.env tuning values change, also update the matching values in plugins.entries.rag-memory.config in openclaw.json (especially score_threshold and top_k).


Deploying systemd unit changes

Edit files in systemd/ (source of truth), then deploy using the included script — it substitutes the correct username automatically:

sudo ~/.openclaw/skills/rag-memory/systemd/deploy.sh

Or manually, replacing youruser with the local OpenClaw user:

sudo sed "s/User=openclaw/User=youruser/g" ~/.openclaw/skills/rag-memory/systemd/*.service \
  | sudo tee /etc/systemd/system/sysclaw-rag-{sync,watch}.service > /dev/null
sudo cp ~/.openclaw/skills/rag-memory/systemd/sysclaw-rag-sync.timer /etc/systemd/system/
sudo cp ~/.openclaw/skills/rag-memory/systemd/sysclaw-rag-watch.path /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl restart sysclaw-rag-sync.timer sysclaw-rag-watch.path

Key config values

KeyExample / Default
QDRANT_HOSThttps://qdrant.example.com
EMBED_BASE_URLhttps://litellm.example.com
EMBED_MODELnomic-embed-text
QDRANT_COLLECTION_PREFIXany UUID or unique prefix string
MEMORY_DIR~/.openclaw/workspace/memory
score_threshold0.70 (in both config.env and openclaw.json plugin config)
top_k5

If Qdrant is unreachable

  1. Try once — do not retry in a loop
  2. Fall back to reading the relevant file directly
  3. Note in your response that vector search was unavailable
  4. Check: curl $QDRANT_HOST/readyz
  5. Do not restart Qdrant automatically — alert the user

Not for

Do not activate this skill for:

  • General file search or code search unrelated to memory/RAG
  • Editing files (use read/write tools directly)
  • Tasks that don't involve looking up past context, facts, or tool docs
  • Syncing or resyncing when the user has not asked to update memory
  • Any request where the user explicitly says "don't search memory"

External endpoints

This skill sends data to three external services configured via config.env:

ServiceVariableWhat is sent
Embedding endpoint (OpenAI-compatible)EMBED_BASE_URLText chunks from memory files and Postgres records, for vector embedding
QdrantQDRANT_HOSTEmbedded vectors + metadata for storage and search queries
PostgresPOSTGRES_DSNRead-only queries against memory_entries, daily_logs, tools tables

No data is sent to any Anthropic or third-party endpoint by this skill.


Privacy statement

Memory content (daily logs, facts, tool descriptions) leaves the local machine in two ways:

  1. Text is sent to your configured embedding endpoint (EMBED_BASE_URL) to generate vectors
  2. Vectors + metadata are stored in and queried from your Qdrant instance (QDRANT_HOST)

Both services are self-hosted and configured by the user. No data is sent to any external party by this skill.


Security manifest

Environment variables accessed:

  • QDRANT_HOST, QDRANT_API_KEY, QDRANT_COLLECTION_PREFIX
  • EMBED_BASE_URL, EMBED_API_KEY, EMBED_MODEL
  • POSTGRES_DSN
  • MEMORY_DIR, CHUNK_SIZE, CHUNK_OVERLAP, TOP_K_DEFAULT, SYNC_BATCH_SIZE, EMBED_BATCH_DELAY_MS

Files read:

  • All .md files under MEMORY_DIR
  • config.env (loaded at sync script startup)

Files written:

  • None (no local file writes)

Database writes (Postgres):

  • memory_entries.qdrant_synced_at — updated after successful vector upsert
  • daily_logs.qdrant_synced_at — same
  • tools.qdrant_synced_at — same
  • qdrant_sync_log — one row inserted per sync run (records_synced, duration_ms)

Network:

  • Outbound HTTPS to EMBED_BASE_URL (embedding)
  • Outbound HTTPS to QDRANT_HOST (vector storage/search)
  • Outbound TCP to Postgres host in POSTGRES_DSN

Trust statement

By installing this skill, text from your memory files and database will be sent to the embedding endpoint configured in EMBED_BASE_URL. Vectors are stored in the Qdrant instance at QDRANT_HOST. Both are self-hosted services you configure. Only install if you trust those services with your memory contents.

When auto_inject is enabled (default: true), Qdrant search results are prepended to every prompt context. This data originates from your own self-hosted Qdrant instance — no external party supplies it. The content is sanitized of session boilerplate before storage but is otherwise injected as-is; only enable auto_inject if you trust your Qdrant data as prompt input.


License

MIT-0 — no attribution required.