Tools
Mnemosyne Openclaw
100% offline, local SQLite memory plugin for OpenClaw โ FTS5 full-text search, auto-capture, zero network dependency
Install
npm install
npm
Configuration Example
{
"plugins": {
"slots": { "memory": "mnemosyne" },
"entries": {
"mnemosyne": {
"enabled": true,
"config": {
"dbPath": "~/.openclaw/memory/mnemosyne.db",
"ownerObserveOthers": true,
"noisePatterns": [],
"maxMessagesPerSession": 10000,
"maxMemoriesPerSession": 1000,
"enableFts": true
}
}
},
"allow": ["mnemosyne", "memory-core"]
}
}
README
# Mnemosyne โ Offline Memory Plugin for OpenClaw
> **v1.1.0** โ FTS5 full-text search, crash resilience, and proper session-scoped tools.
## What It Is
**Mnemosyne** is a **100% offline, local-only** memory plugin for OpenClaw agents. It replaces cloud-dependent memory systems (e.g. Honcho) with a synchronous SQLite backend that lives inside the gateway process.
**Zero network. Zero API keys. Zero cloud. Native to OpenClaw.**
## What's New in v1.1
| Change | Before | After |
|--------|--------|-------|
| **Session context** | Tools wrote to ghost `"default_session"` โ agents never saw results | Tools receive real `sessionKey`/`agentId` from OpenClaw runtime |
| **Full-text search** | No cross-session search | `mnemosyne_search` with FTS5 + Porter stemming |
| **Crash resilience** | No crash recovery | `wal_checkpoint(TRUNCATE)` on every startup |
| **Error guards** | DB errors propagated raw | Retry on `SQLITE_BUSY` with exponential backoff |
| **Startup speed** | FTS rebuilt every restart | Guarded rebuild โ only runs once on first migration |
| **Code quality** | Duplicated `ToolRuntimeContext` in two files | Shared in `src/types/runtime.ts` |
## Architecture at a Glance
```
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ OpenClaw Gateway โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ Mnemosyne Plugin (kind: memory) โ โ
โ โ โโโโโโโโโโ โโโโโโโโโโโโ โโโโโโโโโโโโโโโ โ โ
โ โ โ hooks/ โ โ tools/ โ โ database โ โ โ
โ โ โcapture โ โ remember โ โ SQLite WAL โ โ โ
โ โ โ agent_ โ โ recall โ โ FTS5 index โ โ โ
โ โ โ end โ โ search โ โ โ auto-prune โ โ โ
โ โ โ โ โ list โ โโโโโโโโโโโโโโโ โ โ
โ โ โ โ โ forget โ โ โ
โ โ โโโโโโโโโโ โโโโโโโโโโโโ โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ QMD Plugin (untouched) โ โ
โ โ memory_search, memory_get โ โ
โ โ Indexes ~/.openclaw/workspace/ โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
```
## Core Features
| Feature | How It Works |
|---------|-------------|
| **Auto-capture** | `agent_end` hook fires after every successful turn โ messages saved to SQLite |
| **Full-text search** | `mnemosyne_search` โ FTS5 with Porter stemming across ALL sessions |
| **Explicit memory** | `mnemosyne_remember` โ store key-value facts scoped to real session |
| **Cross-session recall** | `mnemosyne_recall(cross_session=true)` โ search memories from any session |
| **List** | `mnemosyne_list` โ enumerate all stored memories |
| **Forget** | `mnemosyne_forget` โ delete a memory by key |
| **Slash command** | `/mnemosyne stats` โ shows counts + FTS status |
| **Auto-pruning** | FIFO deletion per session when limits exceeded |
| **WAL mode** | Crash-safe, concurrent-friendly SQLite |
| **Crash recovery** | `wal_checkpoint(TRUNCATE)` flushes pending WAL on startup |
## Data Model
### `messages` โ Auto-captured conversation turns
- `session_key`, `agent_id`, `role` (user/assistant/system), `content`, `timestamp`
### `memories` โ Explicit key-value stores
- `session_key + key` โ unique composite
- `value`, `timestamp`, `updated_at`
### `sessions` โ Metadata ledger
- `message_count`, `memory_count`, `updated_at`
### `messages_fts` / `memories_fts` โ FTS5 virtual tables
- Porter stemmer, Unicode61 normalizer, diacritic removal
- Keep-fresh triggers on INSERT/UPDATE/DELETE
## Coexistence with QMD (Zero Conflict)
| Layer | System | What It Does | Data Format |
|-------|--------|-------------|-------------|
| **Long-term Document Memory** | **QMD** (unchanged) | Indexes Markdown files โ MEMORY.md, DREAMS.md | Files on disk |
| **Session / Structured Memory** | **Mnemosyne** | Captures conversation turns + explicit key-value remembers + FTS5 search | SQLite (`~/.openclaw/memory/mnemosyne.db`) |
QMD tools stay exactly as they are:
- `memory_search` โ searches Markdown files โ
- `memory_get` โ reads Markdown files โ
Mnemosyne adds new tools alongside them:
- `mnemosyne_remember`, `mnemosyne_recall`, `mnemosyne_search`, `mnemosyne_list`, `mnemosyne_forget`
## Installation (Any OpenClaw, Even Offline)
### Prerequisites
- Node.js 22+ (tested on v24.14.0)
- OpenClaw >= 2026.4.27
- `python3` and `make` (for better-sqlite3 native compilation)
### Step 1: Clone & Build
```bash
git clone https://github.com/smfworks/mnemosyne-openclaw.git
cd mnemosyne-openclaw
npm install
npm run build
```
### Step 2: Load Plugin
```bash
openclaw plugin load /full/path/to/mnemosyne-openclaw
```
### Step 3: Configure
```json
{
"plugins": {
"slots": { "memory": "mnemosyne" },
"entries": {
"mnemosyne": {
"enabled": true,
"config": {
"dbPath": "~/.openclaw/memory/mnemosyne.db",
"ownerObserveOthers": true,
"noisePatterns": [],
"maxMessagesPerSession": 10000,
"maxMemoriesPerSession": 1000,
"enableFts": true
}
}
},
"allow": ["mnemosyne", "memory-core"]
}
}
```
### Step 4: Restart Gateway
```bash
openclaw gateway restart
```
### Step 5: Verify
```
/mnemosyne stats
```
Expected:
```
Mnemosyne Stats:
- Messages: 0
- Memories: 0
- Sessions: 0
- DB: /home/.../.openclaw/memory/mnemosyne.db
- FTS: enabled
```
## Configuration Reference
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `dbPath` | string | `~/.openclaw/memory/mnemosyne.db` | Path to SQLite file |
| `ownerObserveOthers` | boolean | `true` | Capture owner messages alongside agent messages |
| `noisePatterns` | string[] | Built-in + user-defined | Substrings that cause a message to be skipped |
| `maxMessagesPerSession` | integer | 10000 | Auto-pruning: keep N most recent messages per session |
| `maxMemoriesPerSession` | integer | 1000 | Auto-pruning: keep N most recent explicit memories per session |
| `enableFts` | boolean | `true` | Enable FTS5 full-text search indexes (set to `false` to save disk on resource-constrained deployments) |
## Built-in Noise Patterns
- `HEARTBEAT_OK`
- `cron reminder`
- `scheduled run`
- `[heartbeat]`, `[system]`
## Tool Usage (from Agent Prompt)
### Remember
```
mnemosyne_remember(key="user_name", value="Michael", scope="session")
```
### Recall by key
```
mnemosyne_recall(key="user_name")
```
### Recall by query
```
mnemosyne_recall(query="timezone", limit=5)
```
### Cross-session recall
```
mnemosyne_recall(query="plugin", cross_session=true, limit=10)
```
### Full-text search (FTS5)
```
mnemosyne_search(query="Italian wine candles", source="all", limit=10)
# Source filter: "messages" | "memories" | "all"
# Stemming: "remembering" matches "remember", "conversations" matches "conversation"
```
### List all
```
mnemosyne_list(limit=20)
```
### Forget
```
mnemosyne_forget(key="old_fact")
```
## Reliability Guarantees
| Failure Mode | Mitigation |
|-------------|-----------|
| Gateway crash mid-write | SQLite WAL + `wal_checkpoint(TRUNCATE)` on restart |
| Disk full | Graceful degradation; oldest entries pruned |
| Config corruption | Schema validation on every boot; auto-create DB on first run |
| QMD conflict | Completely separate namespaces; QMD tools unaffected |
| Plugin crash on load | Isolated to plugin; gateway stays up; error logged |
| SQLITE_BUSY (WAL contention) | Retry with exponential backoff (3 attempts, max 500ms) |
| Large DB (100K+ messages) | Guarded FTS rebuild โ near-zero startup after first migration |
## Why No HTTP Server?
- **Synchronous** โ No async/await complexity in hooks; `agent_end` blocks until write completes
- **Single process** โ No separate process to monitor, restart, or debug
- **Zero network** โ No `localhost:3001` to fail; direct file I/O
- **Transaction safety** โ SQLite WAL mode handles crashes gracefully
- **Proven stack** โ better-sqlite3 is a production backend used by millions
## File Structure
```
mnemosyne-plugin/
โโโ dist/ โ Compiled JS (tsc output)
โโโ src/
โ โโโ index.ts โ Plugin entry point
โ โโโ config.ts โ Schema + validator
โ โโโ database.ts โ SQLite singleton + FTS5 + WAL checkpoint
โ โโโ state.ts โ Shared plugin state (DI pattern)
โ โโโ helpers.ts โ Session keys, noise filter
โ โโโ hooks/
โ โ โโโ capture.ts โ agent_end handler
โ โโโ tools/
โ โ โโโ index.ts โ 5 tools: remember/recall/search/list/forget
โ โโโ types/
โ โโโ runtime.ts โ ToolRuntimeContext (shared)
โ โโโ better-sqlite3.d.tsโ Type declarations
โ โโโ openclaw-sdk.d.ts โ Plugin API types
โโโ tests/
โ โโโ database.test.js โ Node built-in test runner
โโโ workspace_md/
โ โโโ SOUL.md โ Plugin philosophy
โ โโโ AGENTS.md โ Agent contract
โ โโโ BOOTSTRAP.md โ Quick start
โโโ openclaw.plugin.json โ Plugin manifest
โโโ package.json โ NPM manifest
โโโ tsconfig.json โ TypeScript config
```
## Non-Goals (What This Plugin Does NOT Do)
These features are intentionally excluded to keep Mnemosyne small, safe, and zero-dependency:
| Feature | Status | Rationale |
|---------|--------|-----------|
| **Vector embeddings / semantic search** | โ Not planned | Requires ML runtime (ONNX/transformers.js) โ violates "zero heavy deps" design goal. FTS5 + stemming provides excellent keyword recall without the complexity |
| **Knowledge graph / entity-relationship DB** | โ Not planned | Requires external services (Qdrant, FalkorDB, Neo4j) โ violates single-process design. Use a dedicated graph plugin if needed |
| **LLM-based memory curation** | โ Not planned here | Memory consolidation should happen in OpenClaw's dreaming pipeline, n
... (truncated)
tools
Comments
Sign in to leave a comment