@xdarkicex/openclaw-memory-libravdb is a local-first OpenClaw memory system
for people who want more than "top-k vectors plus a prompt footer."
It replaces the default lightweight memory path with a full context lifecycle:
- active session memory
- durable per-user memory
- shared global memory
- continuity-aware compaction
- authored context partitioning
- hybrid scoring across scope, recency, and similarity
This repository pairs a TypeScript OpenClaw plugin with a Go daemon backed by
libraVDB. The plugin owns both the memory and contextEngine slots, while
the daemon handles embeddings, retrieval, storage, and compaction.
On newer OpenClaw builds, it also bridges the built-in memory_search runtime
to the same libraVDB sidecar instead of leaving that tool inert.
The stock "single memory bucket" pattern is good for simple persistence, but it starts to break down when you care about:
- keeping the newest working context raw and intact
- separating ephemeral session state from durable memory
- avoiding long-session prompt collapse
- preserving authored instructions differently from recalled user content
- treating memory retrieval as a ranked assembly problem instead of plain nearest-neighbor lookup
LibraVDB Memory exists for that harder class of memory problem.
These are the core differentiators the project is built around:
- Dual slot ownership: the plugin owns both memory prompt injection and the full context lifecycle.
- Built-in
memory_searchbridge: newer OpenClaw memory runtime calls are routed into the same sidecar-backed retrieval path. - Lifecycle hint adoption:
before_resetandsession_endare used as advisory signals into the sidecar without giving OpenClaw control of ingest or compaction. - Sidecar-owned lifecycle journal: reset/end hints are recorded internally for debugging and auditing without entering normal memory retrieval. The journal is bounded by a sidecar retention cap so it does not grow forever.
- Local-first runtime: the core path does not depend on external embedding services.
- Three-tier memory: session, durable user, and global memory stay distinct.
- Hybrid scoring: retrieval is ranked by semantic similarity, recency, scope, and summary quality instead of cosine alone.
- Automatic compaction: long sessions compact behind a protected recent tail.
- Crash-resilient IPC: the host talks to a sidecar over a stable local socket or loopback TCP endpoint with degraded-mode fallback.
The supported install flow is:
brew tap xDarkicex/openclaw-libravdb-memory
brew install libravdbd
brew services start libravdbd
openclaw plugins install @xdarkicex/openclaw-memory-libravdbThe Homebrew formula installs the daemon plus the bundled ONNX Runtime, embedding assets, and T5 summarizer assets it needs to boot cleanly on supported platforms.
Then assign the plugin to both required OpenClaw slots in
~/.openclaw/openclaw.json:
{
"plugins": {
"slots": {
"memory": "libravdb-memory",
"contextEngine": "libravdb-memory"
},
"configs": {
"libravdb-memory": {
"sidecarPath": "auto"
}
}
}
}Verify the setup:
openclaw memory statusExpected healthy state:
- the daemon is reachable
- the plugin is active as the memory provider
- the runtime can report stored counts and model readiness
LibraVDB Memory can watch markdown roots and sync changed notes into vector memory without changing the Go sidecar RPC contract.
The two built-in source adapters are:
generic: for OpenClaw-owned markdown, including stock files likeMEMORY.mdobsidian: for Obsidian vault roots, with tag-aware defaults
Configuration is driven through the plugin config fields in
openclaw.plugin.json:
markdownIngestionEnabledmarkdownIngestionRootsmarkdownIngestionIncludemarkdownIngestionExcludemarkdownIngestionDebounceMsmarkdownIngestionObsidianEnabledmarkdownIngestionObsidianRootsmarkdownIngestionObsidianIncludemarkdownIngestionObsidianExcludemarkdownIngestionObsidianDebounceMs
Typical usage:
- point
markdownIngestionRootsat OpenClaw-owned markdown roots, such as.openclaw/skills/*/*.mdor a stock memory directory that containsMEMORY.md - enable the Obsidian adapter separately with
markdownIngestionObsidianEnabled: trueand one or more vault roots - use include/exclude globs to narrow what gets watched when needed
By default, the Obsidian adapter only auto-ingests notes that look like memory
notes, using frontmatter tags or inline tags like #project. The OpenClaw
stock MEMORY.md file is always eligible through the generic adapter path.
Dream promotion is a separate, opt-in path for promoting vetted dream diary
entries directly into a dedicated dream:{userId} collection.
It does not use MEMORY.md. Instead, it expects a dream diary markdown file
that contains explicit candidate bullets under promotion-oriented headings such
as ## Deep Sleep. Each promoted bullet should include a trailing metadata
block with the gating fields:
- Preserve the recent tail buffer {score=0.82 recall=3 unique=2}Only bullets that satisfy the sidecar gates are inserted. The dream collection
is isolated from normal user: and global retrieval by default, and dream
phrasing in chat or search queries routes there automatically.
Configure automatic diary watching with:
dreamPromotionEnableddreamPromotionDiaryPathdreamPromotionUserIddreamPromotionDebounceMs
For a manual run, use:
openclaw memory dream-promote --user-id <userId> --dream-file /path/to/DREAMS.mdThe manual command and the automatic watcher both go through the same sidecar promotion RPC, so the admission gates and provenance metadata are identical.
This plugin is intentionally connect-only at install time.
It does not compile Go code during plugin installation, and it does not manage daemon lifecycle automatically from the npm package. That is deliberate: some OpenClaw environments are strict about postinstall behavior, daemon spawning, and anything that looks like binary bootstrap or process management.
Current model:
- npm/OpenClaw package: plugin code and docs
libravdbd: installed and managed separately- default daemon endpoint on macOS/Linux:
unix:$HOME/.clawdb/run/libravdb.sock - default daemon endpoint on Windows:
tcp:127.0.0.1:37421
If your daemon runs elsewhere, set an explicit sidecarPath, for example:
unix:/custom/path/libravdb.socktcp:127.0.0.1:9999
OpenClaw host
-> memoryPromptSection (static capability header)
-> memory runtime bridge (built-in memory_search)
-> context engine (bootstrap / ingest / assemble / compact)
-> plugin runtime
-> JSON-RPC
-> libravdbd
-> libraVDB + local embedding/summarization stack
The main runtime split is:
- TypeScript host layer:
- OpenClaw plugin registration
- prompt assembly
- hybrid ranking
- continuity-aware token budgeting
- degraded-mode behavior
- Go daemon layer:
- vector storage
- embeddings
- search RPCs
- compaction and summarization
- stable local IPC endpoint
For the implemented architecture map, read docs/architecture.md.
The assembly path is not "just search some vectors and paste the top hits."
It combines:
- session search for current-work relevance
- durable user recall for long-lived personal context
- global recall for shared facts
- authored invariant and variant context
- continuity-preserving recent-tail injection
- token-budgeted fitting
The ranking model currently blends:
- semantic similarity
- scope weighting
- recency decay
- summary quality attenuation
The formal math and deeper design notes are kept out of the public index on purpose.
For internal tuning, the repo includes a local LongMemEval harness that runs the dataset through the plugin layer and measures whether the assembled prompt still contains the evidence turns.
The benchmark runner is committed, but the dataset and generated reports are not.
Keep downloaded data and local outputs under benchmarks/longmemeval/, which is
ignored by default.
The harness writes JSONL incrementally, so partial results survive if a transient daemon failure interrupts a long run.
The run summary now prints a compact table with total questions, processed rows, skipped abstentions, errors, session hit rate, turn hit rate, and average prompt size.
Run it with:
LONGMEMEVAL_DATA_FILE=/path/to/longmemeval_oracle.json pnpm run benchmark:longmemevalIf you already have a daemon running and do not want the benchmark to spawn another one, set:
LONGMEMEVAL_USE_EXISTING_DAEMON=1 LONGMEMEVAL_SIDECAR_PATH=unix:/path/to/libravdb.sockIf the local test daemon drops mid-run, the benchmark will restart it and retry the current instance once before recording an error result.
Optional outputs:
LONGMEMEVAL_LIMITto cap the number of questionsLONGMEMEVAL_TOPKto change the search budgetLONGMEMEVAL_OUT_FILEto write JSONL records for analysis
To score a hypothesis JSONL file with the official LongMemEval evaluator, point the repo at a local checkout of the benchmark and run:
LONGMEMEVAL_EVAL_REPO=/path/to/LongMemEval \
LONGMEMEVAL_HYPOTHESIS_FILE=/path/to/hypotheses.jsonl \
LONGMEMEVAL_DATA_FILE=/path/to/longmemeval_oracle.json \
OPENAI_API_KEY=... \
pnpm run benchmark:longmemeval:scoreThat scorer wrapper shells out to the official Python evaluation script and then prints the aggregate metrics from the generated log when available.
This system does not treat long chats as append-only forever.
Older session turns compact behind a protected recent tail, so the plugin can:
- keep the newest working context raw
- preserve adjacency-sensitive continuity near the boundary
- promote older material into summaries
- avoid letting long sessions drown their own prompt budget
Compaction is designed as part of the memory system itself, not as a separate maintenance convenience.
If you are evaluating this as an operator or advanced OpenClaw user, the key practical points are:
- This plugin should own both
memoryandcontextEngine. Partial slot assignment is a misconfiguration. - On hosts that expose
registerMemoryRuntime, the built-inmemory_searchtool now searches the same libraVDB-backed memory stores. - The daemon is a separate operational unit. Treat plugin lifecycle and daemon lifecycle as different concerns.
- The system is local-first by design. The critical retrieval path does not require a remote embedding service.
- The sidecar transport is stable and explicit, which makes it service-manager friendly on macOS, Linux, and Windows.
Good entry points:
If you are studying retrieval, memory systems, or agent architecture, the interesting parts of this repo are:
- continuity-aware assembly:
C_total(q) = I union T_recent union Proj(V_rest, q) - hybrid ranking instead of pure cosine retrieval
- separation of authored invariants from searchable authored lore
- durable-memory admission via domain-adaptive gating
- local daemon architecture rather than in-process TS vector plumbing
- compaction that preserves recent working context instead of flattening the whole transcript
Start here:
- npm package:
@xdarkicex/openclaw-memory-libravdb - OpenClaw plugin id:
libravdb-memory - minimum host version:
openclaw >= 2026.3.22 - default daemon data path:
$HOME/.clawdb/data.libravdb - default daemon endpoint on macOS/Linux:
unix:$HOME/.clawdb/run/libravdb.sock - default daemon endpoint on Windows:
tcp:127.0.0.1:37421
- docs/install.md: quick install and lifecycle guide
- docs/installation.md: full installation and packaging reference
- docs/uninstall.md: clean shutdown and removal
- docs/architecture.md: current implemented system architecture
Because OpenClaw environments can be strict about postinstall downloads, daemon spawning, and scanner-visible binary bootstrap behavior, the cleanest supported user path today is:
- install plugin
- install daemon
- assign both slots
- let the plugin connect to a stable local endpoint
That tradeoff is intentional. It keeps the plugin installation surface simple and auditable while preserving the full local memory engine at runtime.