← Back to Plugins
Tools

Mnemosyne Openclaw

smfworks By smfworks ⭐ 1 stars 👁 545 views ▲ 0 votes

100% offline, local SQLite memory plugin for OpenClaw — FTS5 full-text search, auto-capture, zero network dependency

GitHub

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

Loading comments...