RAG Memory Skill
Architecture (as of 2026-04-04)
All files live under ~/.openclaw/skills/rag-memory/ — the single source of truth.
| File | Purpose |
|---|---|
config.env | Credentials and tuning (gitignored) |
config.env.example | Template with no secrets (tracked in git) |
sync_to_qdrant.py | Ingest pipeline: Postgres + .md files → Qdrant |
requirements.txt | Python deps for sync script |
venv/ | Python virtualenv (gitignored) |
plugin/index.js | OpenClaw plugin — registers vector_search tool and before_prompt_build hook |
plugin/package.json | Plugin manifest |
plugin/openclaw.plugin.json | Plugin config schema |
systemd/ | Source-of-truth copies of systemd units (deploy with sudo cp + daemon-reload) |
references/config-paths.example.md | File and credential location template (copy to config-paths.md and fill in) |
references/operational.md | When/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
| Task | Command |
|---|---|
| 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
| Key | Example / Default |
|---|---|
QDRANT_HOST | https://qdrant.example.com |
EMBED_BASE_URL | https://litellm.example.com |
EMBED_MODEL | nomic-embed-text |
QDRANT_COLLECTION_PREFIX | any UUID or unique prefix string |
MEMORY_DIR | ~/.openclaw/workspace/memory |
score_threshold | 0.70 (in both config.env and openclaw.json plugin config) |
top_k | 5 |
If Qdrant is unreachable
- Try once — do not retry in a loop
- Fall back to reading the relevant file directly
- Note in your response that vector search was unavailable
- Check:
curl $QDRANT_HOST/readyz - 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:
| Service | Variable | What is sent |
|---|---|---|
| Embedding endpoint (OpenAI-compatible) | EMBED_BASE_URL | Text chunks from memory files and Postgres records, for vector embedding |
| Qdrant | QDRANT_HOST | Embedded vectors + metadata for storage and search queries |
| Postgres | POSTGRES_DSN | Read-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:
- Text is sent to your configured embedding endpoint (
EMBED_BASE_URL) to generate vectors - 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_PREFIXEMBED_BASE_URL,EMBED_API_KEY,EMBED_MODELPOSTGRES_DSNMEMORY_DIR,CHUNK_SIZE,CHUNK_OVERLAP,TOP_K_DEFAULT,SYNC_BATCH_SIZE,EMBED_BATCH_DELAY_MS
Files read:
- All
.mdfiles underMEMORY_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 upsertdaily_logs.qdrant_synced_at— sametools.qdrant_synced_at— sameqdrant_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.