Geheugen
OpenClaw-geheugen is platte Markdown in de agentwerkruimte. De bestanden zijn de bron van waarheid; het model “onthoudt” alleen wat naar schijf wordt geschreven. Geheugenz oektools worden geleverd door de actieve geheugenplugin (standaard:memory-core). Schakel geheugenplugins uit met plugins.slots.memory = "none".
Geheugenbestanden (Markdown)
De standaard werkruimte-indeling gebruikt twee geheugenlagen:memory/YYYY-MM-DD.md- Daglog (alleen toevoegen).
- Leest vandaag + gisteren bij sessiestart.
MEMORY.md(optioneel)- Gecureerd langetermijngeheugen.
- Alleen laden in de hoofd-, privésessie (nooit in groepscontexten).
agents.defaults.workspace, standaard
~/.openclaw/workspace). Zie Agent workspace voor de volledige indeling.
Wanneer geheugen schrijven
- Beslissingen, voorkeuren en duurzame feiten gaan naar
MEMORY.md. - Dagelijkse notities en lopende context gaan naar
memory/YYYY-MM-DD.md. - Als iemand zegt “onthoud dit”, schrijf het op (houd het niet in RAM).
- Dit gebied is nog in ontwikkeling. Het helpt om het model eraan te herinneren om herinneringen op te slaan; het weet wat het moet doen.
- Als je wilt dat iets blijft hangen, vraag de bot om het in het geheugen te schrijven.
Automatische geheugenflush (pre-compactie-ping)
Wanneer een sessie dicht bij auto-compactie is, triggert OpenClaw een stille, agentische beurt die het model eraan herinnert om duurzaam geheugen te schrijven vóórdat de context wordt gecompacteerd. De standaardprompts zeggen expliciet dat het model mag antwoorden, maar meestal isNO_REPLY de juiste reactie zodat de gebruiker deze beurt nooit ziet.
Dit wordt aangestuurd door agents.defaults.compaction.memoryFlush:
- Zachte drempel: de flush triggert wanneer de geschatte sessietokens
contextWindow - reserveTokensFloor - softThresholdTokensoverschrijden. - Stil standaard: prompts bevatten
NO_REPLYzodat er niets wordt afgeleverd. - Twee prompts: een gebruikersprompt plus een systeemprompt voegen de herinnering toe.
- Eén flush per compactiecyclus (bijgehouden in
sessions.json). - Werkruimte moet schrijfbaar zijn: als de sessie gesandboxed draait met
workspaceAccess: "ro"of"none", wordt de flush overgeslagen.
Vectorgeheugenz oeken
OpenClaw kan een kleine vectorindex bouwen overMEMORY.md en memory/*.md zodat
semantische queries gerelateerde notities kunnen vinden, zelfs wanneer de formulering verschilt.
Standaardinstellingen:
- Standaard ingeschakeld.
- Houdt geheugenbestanden in de gaten voor wijzigingen (gedebounced).
- Configureer geheugenzoekopdrachten onder
agents.defaults.memorySearch(niet op het topniveaumemorySearch). - Gebruikt standaard externe embeddings. Als
memorySearch.providerniet is ingesteld, selecteert OpenClaw automatisch:localals eenmemorySearch.local.modelPathis geconfigureerd en het bestand bestaat.openaials een OpenAI-sleutel kan worden gevonden.geminials een Gemini-sleutel kan worden gevonden.voyageals een Voyage-sleutel kan worden gevonden.- Anders blijft geheugenzoeken uitgeschakeld totdat het is geconfigureerd.
- Lokale modus gebruikt node-llama-cpp en kan
pnpm approve-buildsvereisen. - Gebruikt sqlite-vec (wanneer beschikbaar) om vectorzoeken binnen SQLite te versnellen.
models.providers.*.apiKey of omgevings-
variabelen. Codex OAuth dekt alleen chat/completions en voldoet niet voor
embeddings voor geheugenzoeken. Voor Gemini, gebruik GEMINI_API_KEY of
models.providers.google.apiKey. Voor Voyage, gebruik VOYAGE_API_KEY of
models.providers.voyage.apiKey. Bij gebruik van een aangepaste OpenAI-compatibele endpoint,
stel memorySearch.remote.apiKey in (en optioneel memorySearch.remote.headers).
QMD-backend (experimenteel)
Stelmemory.backend = "qmd" in om de ingebouwde SQLite-indexer te vervangen door
QMD: een local-first zoek-sidecar die
BM25 + vectoren + reranking combineert. Markdown blijft de bron van waarheid; OpenClaw
roept QMD aan voor retrieval. Belangrijke punten:
Vereisten
- Standaard uitgeschakeld. Opt-in per config (
memory.backend = "qmd"). - Installeer de QMD CLI apart (
bun install -g https://github.com/tobi/qmdof download een release) en zorg dat hetqmd-binary op dePATHvan de gateway staat. - QMD heeft een SQLite-build nodig die extensies toestaat (
brew install sqliteop macOS). - QMD draait volledig lokaal via Bun +
node-llama-cppen downloadt GGUF- modellen automatisch van HuggingFace bij eerste gebruik (geen aparte Ollama-daemon vereist). - De gateway draait QMD in een zelfvoorzienende XDG-home onder
~/.openclaw/agents/<agentId>/qmd/doorXDG_CONFIG_HOMEenXDG_CACHE_HOMEin te stellen. - OS-ondersteuning: macOS en Linux werken out-of-the-box zodra Bun + SQLite zijn geïnstalleerd. Windows wordt het best ondersteund via WSL2.
- De gateway schrijft een zelfvoorzienende QMD-home onder
~/.openclaw/agents/<agentId>/qmd/(config + cache + sqlite-DB). - Collecties worden aangemaakt via
qmd collection addvanuitmemory.qmd.paths(plus standaard werkruimtegeheugenbestanden), daarna draaienqmd update+qmd embedbij boot en op een configureerbaar interval (memory.qmd.update.interval, standaard 5 min). - De gateway initialiseert nu de QMD-manager bij het opstarten, zodat periodieke update-timers actief zijn nog vóór de eerste
memory_search-aanroep. - De boot-verversing draait nu standaard op de achtergrond zodat de chatstart niet
wordt geblokkeerd; stel
memory.qmd.update.waitForBootSync = truein om het eerdere blokkerende gedrag te behouden. - Zoekopdrachten lopen via
qmd query --json. Als de geselecteerde modus flags op jouw QMD-build weigert, probeert OpenClaw het opnieuw metqmd query. Als QMD faalt of het binary ontbreekt, valt OpenClaw automatisch terug op de ingebouwde SQLite-manager zodat geheugentools blijven werken. - OpenClaw stelt momenteel geen QMD embed batch-size tuning bloot; batchgedrag wordt door QMD zelf bepaald.
- Eerste zoekopdracht kan traag zijn: QMD kan lokale GGUF-modellen (reranker/query-
expansie) downloaden bij de eerste
qmd queryrun.-
OpenClaw stelt
XDG_CONFIG_HOME/XDG_CACHE_HOMEautomatisch in wanneer het QMD draait. -
Als je modellen handmatig vooraf wilt downloaden (en dezelfde index wilt opwarmen
die OpenClaw gebruikt), voer een eenmalige query uit met de XDG-dirs van de agent.
De QMD-status van OpenClaw staat onder je state-dir (standaard
~/.openclaw). Je kuntqmdnaar exact dezelfde index laten wijzen door dezelfde XDG-vars te exporteren die OpenClaw gebruikt:
-
OpenClaw stelt
memory.qmd.*)
command(standaardqmd): overschrijft het pad naar het uitvoerbare bestand.includeDefaultMemory(standaardtrue): auto-indexeerMEMORY.md+memory/**/*.md.includeDefaultMemory(standaardtrue): auto-indexeerMEMORY.md+memory/**/*.md.paths[]: voeg extra mappen/bestanden toe (path, optioneelpattern, optioneel stabielname).sessions: opt-in voor sessie-JSONL-indexering (enabled,retentionDays,exportDir).update: regelt verversingscadans en onderhoudsuitvoering: (interval,debounceMs,onBoot,waitForBootSync,embedInterval,commandTimeoutMs,updateTimeoutMs,embedTimeoutMs).limits: begrenst recall-payload (maxResults,maxSnippetChars,maxInjectedChars,timeoutMs).scope: hetzelfde schema alssession.sendPolicy. Standaard is alleen DM (denyalles,allowdirecte chats); versoepel dit om QMD- treffers in groepen/kanalen te tonen.match.keyPrefixkomt overeen met de genormaliseerde session key (in kleine letters, met een eventuele voorloopagent:<id>:verwijderd). Voorbeeld:discord:channel:.match.rawKeyPrefixkomt overeen met de ruwe session key (in kleine letters), inclusiefagent:<id>:. Voorbeeld:agent:main:discord:.- Legacy:
match.keyPrefix: "agent:..."wordt nog steeds behandeld als een raw-key-prefix, maar geef voor de duidelijkheid de voorkeur aanrawKeyPrefix.
- Wanneer
scopeeen zoekopdracht weigert, logt OpenClaw een waarschuwing met het afgeleidechannel/chatType, zodat lege resultaten makkelijker te debuggen zijn. - Snippets die buiten de werkruimte zijn gesourced verschijnen als
qmd/<collection>/<relative-path>inmemory_search-resultaten;memory_getbegrijpt die prefix en leest uit de geconfigureerde QMD-collectiewortel. - Wanneer
memory.qmd.sessions.enabled = true, exporteert OpenClaw opgeschoonde sessie- transcripties (Gebruiker/Assistent-beurten) naar een aparte QMD-collectie onder~/.openclaw/agents/<id>/qmd/sessions/, zodatmemory_searchrecente gesprekken kan ophalen zonder de ingebouwde SQLite-index aan te raken. memory_search-snippets bevatten nu eenSource: <path#line>-footer wanneermemory.citationsauto/onis; stelmemory.citations = "off"in om de padmetadata intern te houden (de agent ontvangt het pad nog steeds voormemory_get, maar de snippettekst laat de footer weg en de systeemprompt waarschuwt de agent om het niet te citeren).
memory.citationsgeldt ongeacht backend (auto/on/off).- Wanneer
qmddraait, taggen westatus().backend = "qmd"zodat diagnostiek toont welke engine de resultaten leverde. Als het QMD-subproces stopt of JSON-uitvoer niet kan worden geparsed, logt de zoekmanager een waarschuwing en retourneert de ingebouwde provider (bestaande Markdown-embeddings) totdat QMD herstelt.
Aanvullende geheugenpaden
Als je Markdown-bestanden buiten de standaard werkruimte-indeling wilt indexeren, voeg expliciete paden toe:- Paden kunnen absoluut zijn of werkruimte-relatief.
- Mappen worden recursief gescand op
.md-bestanden. - Alleen Markdown-bestanden worden geïndexeerd.
- Symlinks worden genegeerd (bestanden of mappen).
Gemini-embeddings (native)
Stel de provider in opgemini om de Gemini-embeddings-API direct te gebruiken:
remote.baseUrlis optioneel (standaard de Gemini API-basis-URL).remote.headerslaat je extra headers toevoegen indien nodig.- Standaardmodel:
gemini-embedding-001.
remote-configuratie met de OpenAI-provider gebruiken:
memorySearch.provider = "local" of stel
memorySearch.fallback = "none" in.
Fallbacks:
memorySearch.fallbackkanopenai,gemini,localofnonezijn.- De fallbackprovider wordt alleen gebruikt wanneer de primaire embeddingprovider faalt.
- Standaard ingeschakeld voor OpenAI- en Gemini-embeddings. Stel
agents.defaults.memorySearch.remote.batch.enabled = falsein om uit te schakelen. - Standaardgedrag wacht op batchvoltooiing; stel
remote.batch.wait,remote.batch.pollIntervalMsenremote.batch.timeoutMinutesaf indien nodig. - Stel
remote.batch.concurrencyin om te bepalen hoeveel batchjobs we parallel indienen (standaard: 2). - Batchmodus is van toepassing wanneer
memorySearch.provider = "openai"of"gemini"en gebruikt de bijbehorende API-sleutel. - Gemini-batchjobs gebruiken het asynchrone embeddings-batchendpoint en vereisen beschikbaarheid van de Gemini Batch API.
- Voor grote backfills is OpenAI doorgaans de snelste optie die we ondersteunen, omdat we veel embedding-aanvragen in één batchjob kunnen indienen en OpenAI ze asynchroon kan verwerken.
- OpenAI biedt gereduceerde prijzen voor Batch API-workloads, waardoor grote indexeer-runs meestal goedkoper zijn dan dezelfde aanvragen synchroon te verzenden.
- Zie de OpenAI Batch API-documentatie en prijzen voor details:
memory_search— retourneert snippets met bestand + regelbereiken.memory_get— lees geheugenbestandsinhoud op pad.
- Stel
agents.defaults.memorySearch.provider = "local"in. - Geef
agents.defaults.memorySearch.local.modelPathop (GGUF ofhf:-URI). - Optioneel: stel
agents.defaults.memorySearch.fallback = "none"in om externe fallback te vermijden.
Hoe de geheugentools werken
memory_searchdoorzoekt semantisch Markdown-chunks (~400 tokens doel, 80-token overlap) uitMEMORY.md+memory/**/*.md. Het retourneert snippettekst (begrensd ~700 tekens), bestandspad, regelbereik, score, provider/model en of we zijn teruggevallen van lokale → externe embeddings. Er wordt geen volledige bestandsinhoud geretourneerd.memory_getleest een specifiek geheugen-Markdownbestand (werkruimte-relatief), optioneel vanaf een startregel en voor N regels. Paden buitenMEMORY.md/memory/worden geweigerd.- Beide tools zijn alleen ingeschakeld wanneer
memorySearch.enabledwaar is voor de agent.
Wat wordt geïndexeerd (en wanneer)
- Bestandstype: alleen Markdown (
MEMORY.md,memory/**/*.md). - Indexopslag: per agent SQLite op
~/.openclaw/memory/<agentId>.sqlite(configureerbaar viaagents.defaults.memorySearch.store.path, ondersteunt{agentId}-token). - Actualiteit: watcher op
MEMORY.md+memory/markeert de index als vervuild (debounce 1,5 s). Sync wordt gepland bij sessiestart, bij zoeken of op een interval en draait asynchroon. Sessietranscripties gebruiken delta-drempels om achtergrond-sync te triggeren. - Herindexeer-triggers: de index slaat de embedding provider/model + endpoint-vingerafdruk + chunking-parameters op. Als een daarvan verandert, reset en herindexeert OpenClaw automatisch de volledige store.
Hybride zoeken (BM25 + vector)
Wanneer ingeschakeld combineert OpenClaw:- Vector-similariteit (semantische match, formulering kan verschillen)
- BM25-sleutelwoordrelevantie (exacte tokens zoals ID’s, omgevingsvariabelen, codesymbolen)
Waarom hybride?
Vectorzoeken is geweldig voor “dit betekent hetzelfde”:- “Mac Studio gateway host” vs “de machine waarop de gateway draait”
- “debounce file updates” vs “indexeren bij elke write vermijden”
- ID’s (
a828e60,b3b9895a…) - codesymbolen (
memorySearch.query.hybrid) - foutstrings (“sqlite-vec unavailable”)
Hoe we resultaten samenvoegen (het huidige ontwerp)
Implementatieschets:- Haal een kandidatenpool op van beide kanten:
- Vector: top
maxResults * candidateMultiplierop cosine-similariteit. - BM25: top
maxResults * candidateMultiplierop FTS5 BM25-rang (lager is beter).
- Converteer BM25-rang naar een 0..1-achtige score:
textScore = 1 / (1 + max(0, bm25Rank))
- Combineer kandidaten per chunk-id en bereken een gewogen score:
finalScore = vectorWeight * vectorScore + textWeight * textScore
vectorWeight+textWeightwordt genormaliseerd naar 1,0 in config-resolutie, zodat gewichten zich als percentages gedragen.- Als embeddings niet beschikbaar zijn (of de provider een nulvector retourneert), draaien we BM25 alsnog en retourneren we sleutelwoordmatches.
- Als FTS5 niet kan worden aangemaakt, behouden we alleen vectorzoeken (geen harde fout).
Embedding-cache
OpenClaw kan chunk-embeddings in SQLite cachen zodat herindexering en frequente updates (vooral sessietranscripties) ongewijzigde tekst niet opnieuw embedden. Config:Sessie-geheugenz oeken (experimenteel)
Je kunt optioneel sessietranscripties indexeren en ze beschikbaar maken viamemory_search.
Dit staat achter een experimentele vlag.
- Sessie-indexering is opt-in (standaard uit).
- Sessie-updates worden gedebounced en asynchroon geïndexeerd zodra ze delta-drempels overschrijden (best-effort).
memory_searchblokkeert nooit op indexering; resultaten kunnen licht verouderd zijn totdat de achtergrond-sync is voltooid.- Resultaten bevatten nog steeds alleen snippets;
memory_getblijft beperkt tot geheugenbestanden. - Sessie-indexering is per agent geïsoleerd (alleen de sessielogs van die agent worden geïndexeerd).
- Sessielogs staan op schijf (
~/.openclaw/agents/<agentId>/sessions/*.jsonl). Elk proces/gebruiker met bestandssysteemtoegang kan ze lezen, dus beschouw schijftoegang als de vertrouwensgrens. Voor strengere isolatie, draai agents onder afzonderlijke OS-gebruikers of hosts.
SQLite-vectorversnelling (sqlite-vec)
Wanneer de sqlite-vec-extensie beschikbaar is, slaat OpenClaw embeddings op in een SQLite-virtuele tabel (vec0) en voert vectorafstandqueries uit in de
database. Dit houdt zoeken snel zonder elke embedding in JS te laden.
Configuratie (optioneel):
enabledstaat standaard op true; wanneer uitgeschakeld, valt zoeken terug op in-proces cosine-similariteit over opgeslagen embeddings.- Als de sqlite-vec-extensie ontbreekt of niet kan worden geladen, logt OpenClaw de fout en gaat door met de JS-fallback (geen vectortabel).
extensionPathoverschrijft het gebundelde sqlite-vec-pad (handig voor aangepaste builds of niet-standaard installatielocaties).
Automatische download van lokale embeddings
- Standaard lokaal embeddingmodel:
hf:ggml-org/embeddinggemma-300M-GGUF/embeddinggemma-300M-Q8_0.gguf(~0,6 GB). - Wanneer
memorySearch.provider = "local", resolveertnode-llama-cppmodelPath; als de GGUF ontbreekt downloadt het automatisch naar de cache (oflocal.modelCacheDirindien ingesteld), en laadt het daarna. Downloads worden hervat bij retry. - Vereiste voor native build: voer
pnpm approve-buildsuit, kiesnode-llama-cpp, en daarnapnpm rebuild node-llama-cpp. - Fallback: als lokale setup faalt en
memorySearch.fallback = "openai", schakelen we automatisch over op externe embeddings (openai/text-embedding-3-smalltenzij overschreven) en registreren we de reden.
Voorbeeld aangepaste OpenAI-compatibele endpoint
remote.*heeft voorrang opmodels.providers.openai.*.remote.headersvoegt samen met OpenAI-headers; extern wint bij sleutelconflicten. Laatremote.headersweg om de OpenAI-standaard te gebruiken.