01Architecture Overview
OpenClaw uses a two-layer memory design. MEMORY.md serves as a curated,
always-loaded bootstrap file injected into the system prompt. Daily logs in
memory/YYYY-MM-DD.md capture session-specific memories that persist across
context compactions. Both layers are indexed into a SQLite database for fast hybrid search.
A file watcher monitors the workspace for changes and keeps the SQLite index in sync.
When the agent needs to recall past context, it uses memory_search to query
the index and memory_get to retrieve specific lines from memory files.
02Memory Tools
Two tools provide read access to the memory system. Both are defined in
src/agents/tools/memory-tool.ts.
memory_search
Performs hybrid vector + keyword search across all indexed memory files.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
query |
string | Yes | — | The search query to match against memory content |
maxResults |
number | No | 6 |
Maximum number of results to return |
minScore |
number | No | 0.35 |
Minimum similarity score threshold (0–1) |
Return structure per result:
{
path: "memory/2026-02-24.md", // relative file path
startLine: 12, // chunk start line
endLine: 28, // chunk end line
score: 0.72, // combined similarity score
snippet: "...", // matched text excerpt
citation: "memory/2026-02-24.md#L12-L28"
}
memory_get
Retrieves raw text content from a specific memory file. Used after memory_search
to pull the full context around a matched snippet.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
path |
string | Yes | — | Relative path to the memory file |
from |
integer | No | — | Starting line number |
lines |
integer | No | — | Number of lines to return |
Access control: Both tools only access .md files within the
workspace MEMORY.md and memory/ directory. Files outside this
scope are rejected.
03Storage Format
Memory data lives in two forms: human-readable Markdown files on disk and a SQLite database that indexes them for fast search.
File Layout
~/.openclaw/workspace/
MEMORY.md # Curated bootstrap (always in system prompt)
memory/
2026-02-11.md # Daily session logs
2026-02-14.md
2026-02-17.md
...
~/.openclaw/memory/
{agentId}.sqlite # SQLite index database
SQLite Database
The database at ~/.openclaw/memory/{agentId}.sqlite contains six tables.
Schema defined in src/memory/memory-schema.ts.
| Table | Type | Purpose | Key Columns |
|---|---|---|---|
files |
Regular | Tracks indexed files with content hashes for change detection | path (PK), source, hash, mtime, size |
chunks |
Regular | Stores text chunks with their embedding vectors | id (PK), path, start_line, end_line, text, embedding, model |
chunks_fts |
Virtual (FTS5) | Full-text search index for BM25 keyword matching | text (indexed), id, path, start_line, end_line (unindexed) |
chunks_vec |
Virtual (sqlite-vec) | Vector similarity search using cosine distance | Embedding vectors from chunks table |
embedding_cache |
Regular | Caches embedding API responses to avoid redundant calls | provider, model, hash (composite PK), embedding, dims |
meta |
Regular | Key-value store for schema version, dirty flags, etc. | key (PK), value |
04Search Pipeline
When memory_search is called, the query passes through a 9-step hybrid
search pipeline. Implementation spread across src/memory/hybrid.ts,
src/memory/mmr.ts, and src/memory/temporal-decay.ts.
Embedding Providers
The embedding step supports multiple providers. Configured via
agents.defaults.memorySearch.provider.
| Provider | Default Model | Notes |
|---|---|---|
| OpenAI | text-embedding-3-small |
Default provider when set to "auto" |
| Gemini | gemini-embedding-001 |
Google AI embedding model |
| Voyage | voyage-4-large |
Voyage AI high-dimensional embeddings |
| Mistral | mistral-embed |
Mistral AI embedding model |
| Local | embeddinggemma-300m-qat-Q8_0 |
GGUF model via local inference, no API needed |
05Memory Lifecycle
From the moment an agent writes a memory file to the moment that content appears in search results, the data passes through a multi-stage pipeline.
Memory files are split into overlapping chunks for indexing:
- Chunk size: 400 tokens (
agents.defaults.memorySearch.chunking.tokens) - Overlap: 80 tokens (
agents.defaults.memorySearch.chunking.overlap) - Stride: 320 tokens (chunk size minus overlap)
The overlap ensures that content near chunk boundaries is still discoverable. Each chunk
records its start_line and end_line in the source file so
memory_get can retrieve the exact lines later.
Chunks are hashed by content — if the text hasn't changed, the embedding is
reused from embedding_cache instead of calling the provider API again.
06Memory Flush
When a session approaches the context window limit, OpenClaw triggers a silent "memory flush" turn before compaction. This ensures important context is written to disk before the conversation history is truncated.
Trigger Condition
totalTokens ≥ contextWindow − reserveTokensFloor − softThresholdTokens
Where softThresholdTokens defaults to 4000. When the total
token count crosses this threshold, a flush is initiated.
Flush Process
Context compaction removes older messages from the session to free token space. Without memory flush, all knowledge from those messages would be lost. The flush mechanism ensures that:
- 1. The agent is prompted to write important context to
memory/YYYY-MM-DD.mdbefore compaction occurs - 2. The file watcher picks up the new file and indexes it into SQLite
- 3. After compaction, the agent can recover the context via
memory_search - 4.
MEMORY.mdis always present in the system prompt (Section 23), providing a baseline context that never gets compacted
The flush prompt and system prompt are customizable via
agents.defaults.compaction.memoryFlush.prompt and
.systemPrompt.
07System Prompt Integration
Memory is woven into the system prompt at three points. These only appear in full prompt mode.
| Section | Name | Role |
|---|---|---|
| #7 | Memory Recall | Instructions for when and how to use memory_search and memory_get. Tells the agent to search memory before answering questions about prior work, decisions, or dates. |
| #23 | Project Context | MEMORY.md is loaded as a bootstrap file. Its full contents are injected into the prompt so the agent always has baseline memory without needing to search. |
| #26 | Runtime | Runtime metadata line includes memory-related capabilities and configuration state. |
Citation Modes
When memory_search returns results, citations can be included automatically.
Configured via memory.citations.
| Mode | Behavior | Format |
|---|---|---|
auto |
Show citations in direct chats; suppress in groups/channels. This is the default. | memory/2026-02-24.md#L12-L28 |
on |
Always include citations with source file and line range. | memory/2026-02-24.md#L12-L28 |
off |
Never include citations. Only the snippet text is returned. | — |
08Configuration
The full memory system is controlled by configuration paths under
agents.defaults.memorySearch and related namespaces.
Defined in src/config/types.tools.ts.
| Config Path | Default | Description |
|---|---|---|
agents.defaults.memorySearch.enabled |
true |
Master switch for the memory search system |
agents.defaults.memorySearch.provider |
"auto" |
Embedding provider: openai, gemini, voyage, mistral, local, or auto |
agents.defaults.memorySearch.sources |
["memory"] |
Which sources to index: memory (files) and/or sessions |
agents.defaults.memorySearch.query.maxResults |
6 |
Maximum results returned per search |
agents.defaults.memorySearch.query.minScore |
0.35 |
Minimum similarity score threshold |
agents.defaults.memorySearch.query.hybrid.vectorWeight |
0.7 |
Weight for vector (cosine) similarity in hybrid scoring |
agents.defaults.memorySearch.query.hybrid.textWeight |
0.3 |
Weight for keyword (BM25) similarity in hybrid scoring |
agents.defaults.memorySearch.chunking.tokens |
400 |
Token size per chunk |
agents.defaults.memorySearch.chunking.overlap |
80 |
Token overlap between adjacent chunks |
agents.defaults.compaction.memoryFlush.enabled |
true |
Enable pre-compaction memory flush |
plugins.slots.memory |
"memory-core" |
Plugin slot for memory backend (allows alternative implementations) |
memory.backend |
"builtin" |
Memory backend: builtin (native SQLite) or qmd (external) |
09Real-World Example
A real OpenClaw workspace's memory footprint, showing how the layers work in practice.
MEMORY.md
The curated bootstrap file — 237 lines covering identity, preferences, workflows, and lessons learned. Always loaded into the system prompt.
# OpenClaw Memory ## Identity & Role - Agent name: Claw - Primary operator: jingtao - Running on: ailearn (Azure VM, Ubuntu 24.04) ## Preferences & Conventions - Language: All code, comments, docs in English - Git: Imperative mood commits, PRs via gh CLI - Docker: V2 plugin syntax (docker compose) ## Workflows - Server provisioning via numbered scripts (00-, 01-, 02-...) - Docker services at vm/docker-services/<category>/<name>/ - Projects at projects/<name>/ with Dockerfile + docker-compose.yml ## Lessons Learned - Always check CLAUDE.md conventions before modifying ai-learn repo - Use set -euo pipefail in all bash scripts - nginx-proxy needs VIRTUAL_HOST + LETSENCRYPT_HOST for HTTPS ...
Daily Logs
Seven daily log files spanning 2026-02-11 to 2026-02-24, capturing session-specific memories written during memory flushes.
memory/ 2026-02-11.md # Initial setup session 2026-02-14.md # Docker service configurations 2026-02-17.md # OpenClaw Explorer project creation 2026-02-19.md # System prompt page development 2026-02-20.md # Skill system exploration 2026-02-22.md # Multi-page restructuring 2026-02-24.md # Memory management research
Each file contains timestamped entries from that day's sessions, written automatically during memory flush events or manually by the agent when it encounters notable context.
SQLite Index
The database file main.sqlite (68 KB) indexes all memory files into
searchable chunks with embeddings.
- Database file:
~/.openclaw/memory/main.sqlite(68 KB) - Indexed files: 8 (MEMORY.md + 7 daily logs)
- Total chunks: varies with content size (400 tokens each, 80 token overlap)
- Embedding provider: OpenAI
text-embedding-3-small - Embedding cache: reuses embeddings for unchanged chunks