Skip to content

Commit cc6e71a

Browse files
committed
release: v2026.4.8.0449 — MemPalace Enhanced Memory
- MemPalace memory backend (ChromaDB + temporal KG via Python bridge) - Shared bridge-call.mjs utility (eliminates code duplication) - Memory backend abstraction (MemPalaceBackend + FileBackend + factory) - Migration script (idempotent, dry-run, wing isolation) - Obsidian vault export (frontmatter, wikilinks, MOCs, timeline) - Search hook (unified MemPalace + OpenClaw search, graceful degradation) - CLI bridge with backend selection - setup.mjs Stage 6 (MemPalace detection) - diagnose.sh A12 (MemPalace health check) - 28/28 automated tests, 0 PII findings - SKILL.md Section 23, CHANGELOG, README updated
1 parent 3ff1739 commit cc6e71a

16 files changed

Lines changed: 1742 additions & 4 deletions

CHANGELOG.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,38 @@
22

33
All notable changes to EverClaw are documented here.
44

5+
## [2026.4.8] - 2026-04-08 — MemPalace Enhanced Memory
6+
7+
### Added
8+
- **MemPalace memory backend** — Optional upgrade layering ChromaDB vector search + temporal knowledge graph on top of OpenClaw's built-in `memory_search`. Dual embedding models (embeddinggemma-300m-qat 300M + all-MiniLM-L6-v2 22M) catch different semantic matches.
9+
- **Python bridge** (`scripts/python/mempalace_bridge.py`) — JSON contract between Node.js and MemPalace SDK v3.0.0 via spawn(). Supports search, mine, wake-up, status, init, as-of, and export commands. Full stdout suppression preserves JSON contract.
10+
- **Shared bridge utility** (`scripts/lib/bridge-call.mjs`) — Single source of truth for Python bridge communication. Configurable `rejectOnError` for strict vs graceful degradation modes.
11+
- **Memory backend abstraction** (`scripts/lib/memory-backend.mjs`) — Factory pattern with `MemPalaceBackend` and `FileBackend`. Async dynamic imports, graceful fallback.
12+
- **FileBackend** (`scripts/lib/file-backend.mjs`) — Grep-based search over memory/*.md files. Read-only fallback when MemPalace is not installed.
13+
- **MemPalaceBackend** (`scripts/lib/mempalace-backend.mjs`) — Full ChromaDB + temporal KG access via Python bridge.
14+
- **Migration script** (`scripts/memory/migrate-to-mempalace.mjs`) — One-time ingestion of existing memory files. Idempotent (content-hash IDs), supports dry-run, wing selection, category stats.
15+
- **Search hook** (`scripts/memory/mempalace-search-hook.mjs`) — Unified search API combining MemPalace results with OpenClaw built-in search. Graceful degradation when MemPalace unavailable.
16+
- **Obsidian vault export** (`scripts/memory/export-obsidian-vault.mjs`) — Exports palace as Obsidian-compatible vault with YAML frontmatter, wikilinks, MOCs, timeline pages. 3,245 drawers → 3,302 files in ~3s.
17+
- **CLI bridge** (`scripts/memory/mempalace-bridge.mjs`) — Full CLI for all memory operations with backend selection.
18+
- **Config template** (`templates/everclaw-config-memory.json`) — Memory backend configuration with MemPalace and FileBackend options.
19+
- **Setup Stage 6**`setup.mjs` now detects MemPalace SDK, checks palace existence, and verifies bridge health.
20+
- **Diagnose A12**`diagnose.sh` checks MemPalace installation and palace status.
21+
- **Test suite** — 28 automated tests across `tests/memory-backend.mjs` (19) and `tests/mempalace-bridge.mjs` (9). Covers FileBackend, MemPalaceBackend, factory, error handling, edge cases.
22+
- **SKILL.md Section 23** — Full documentation of MemPalace integration, architecture, CLI usage, and configuration.
23+
24+
### Changed
25+
- **`package.json`** — Added `test:memory` script.
26+
27+
### Security
28+
- All new files pass PII scan (0 findings). MemPalace vaults stored locally in `~/.mempalace/`. Export includes privacy warning.
29+
30+
### Technical Notes
31+
- Requires: `pip install mempalace` (optional — EverClaw works without it)
32+
- First mine downloads 79MB embedding model (all-MiniLM-L6-v2)
33+
- Bridge timeout: 300s default (mining can be slow on first run)
34+
- Idempotent migration: ChromaDB content-hash IDs prevent duplicates on re-run
35+
- Wings provide data isolation (tested: 0 cross-contamination)
36+
537
## [2026.4.7.1833] - 2026-04-07 — Ollama Input Modalities Fix
638

739
### Fixed

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ RUN FDIR="/home/node/.openclaw/workspace/skills/everclaw/templates/flavors/${FLA
170170

171171
# ─── Environment ──────────────────────────────────────────────────────────────
172172

173-
ARG EVERCLAW_VERSION=2026.4.7.1918
173+
ARG EVERCLAW_VERSION=2026.4.8.0449
174174
ENV EVERCLAW_VERSION=${EVERCLAW_VERSION}
175175
ENV NODE_ENV=production
176176
ENV EVERCLAW_PROXY_PORT=8083

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,17 @@ The proxy handles all the blockchain complexity: opening sessions, renewing befo
235235

236236
**Benefit:** Your agent handles MOR tokens and private keys safely. The same security patterns used by professional custody solutions, adapted for AI agents.
237237

238+
### 🧠 MemPalace — Enhanced Memory (Optional)
239+
| Component | What It Does |
240+
|-----------|-------------|
241+
| **ChromaDB Vector Search** | Semantic search across all memory files using all-MiniLM-L6-v2 embeddings |
242+
| **Temporal Knowledge Graph** | Query entity relationships at specific points in time ("What did we know about X on date Y?") |
243+
| **Obsidian Vault Export** | Export palace as browsable vault with frontmatter, wikilinks, MOCs, and timeline pages |
244+
| **Dual Embedding Models** | Complements OpenClaw's built-in embeddinggemma-300m-qat — different models catch different semantic matches |
245+
| **Migration Tool** | Idempotent one-time import of existing memory/*.md files into MemPalace |
246+
247+
**Benefit:** Your agent gets deeper memory recall across thousands of files. Two embedding models (300M + 22M params) searching independently means better coverage. The Obsidian export lets you browse and graph-visualize your agent's entire knowledge base. Requires `pip install mempalace` — EverClaw works without it.
248+
238249
---
239250

240251
## Available Models
@@ -316,6 +327,7 @@ When a session ends, your MOR comes back. Open a new session with the same token
316327
- **macOS or Linux** — macOS Keychain or libsecret for native key storage; encrypted file fallback works everywhere
317328
- **age, zstd, jq** — for backup/restore features (auto-installed by `install.sh`)
318329
- **node-llama-cpp** — for local memory search embeddings (auto-installed by `setup.mjs` and `install.sh`)
330+
- **mempalace** (optional) — `pip install mempalace` for enhanced ChromaDB + temporal KG memory. Not required — EverClaw works without it.
319331

320332
That's it. No external accounts. No API keys. No subscriptions.
321333

SKILL.md

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2634,8 +2634,127 @@ When the restored agent boots and detects a migration note in today's daily memo
26342634
26352635
---
26362636
2637+
## 23. Enhanced Memory with MemPalace (v2026.4.8)
2638+
2639+
Optional upgrade to EverClaw's memory backend using [MemPalace](https://github.com/AiEnigma-Labs/MemPalace) — a local-first memory system with ChromaDB vector search, temporal knowledge graph, and hierarchical organization (wings/rooms/drawers).
2640+
2641+
### Why MemPalace?
2642+
2643+
- **Dual embedding models**: OpenClaw's built-in `memory_search` uses embeddinggemma-300m-qat (300M); MemPalace uses all-MiniLM-L6-v2 (22M). Different models catch different semantic matches.
2644+
- **Temporal awareness**: Query what was known about an entity at a specific date (`as-of` queries).
2645+
- **Wing/room hierarchy**: Organize memories by project, topic, or time period.
2646+
- **Obsidian export**: Browse your agent's memory as a full Obsidian vault with wikilinks and frontmatter.
2647+
- **Zero external APIs**: Everything runs locally. No data leaves the machine.
2648+
2649+
### Install
2650+
2651+
```bash
2652+
pip install mempalace
2653+
```
2654+
2655+
### Migration (one-time import of existing memory files)
2656+
2657+
```bash
2658+
# Preview what will be imported
2659+
node scripts/memory/migrate-to-mempalace.mjs --dry-run
2660+
2661+
# Run the migration
2662+
node scripts/memory/migrate-to-mempalace.mjs --wing agent
2663+
```
2664+
2665+
### Search (CLI)
2666+
2667+
```bash
2668+
# Search memories
2669+
node scripts/memory/mempalace-search-hook.mjs search "wallet encryption" --wing everclaw
2670+
2671+
# Get status
2672+
node scripts/memory/mempalace-search-hook.mjs status
2673+
2674+
# Wake-up context (identity + essential story)
2675+
node scripts/memory/mempalace-search-hook.mjs wake-up
2676+
```
2677+
2678+
### Search (Module API)
2679+
2680+
```javascript
2681+
import { enhancedSearch, getStatus, getWakeUpContext, queryAsOf } from './scripts/memory/mempalace-search-hook.mjs';
2682+
2683+
const results = await enhancedSearch('wallet encryption', { wing: 'everclaw', maxResults: 10 });
2684+
const status = await getStatus();
2685+
const context = await getWakeUpContext({ wing: 'agent' });
2686+
const history = await queryAsOf('EverClaw', '2026-04-01');
2687+
```
2688+
2689+
### Obsidian Vault Export
2690+
2691+
```bash
2692+
# Preview
2693+
node scripts/memory/export-obsidian-vault.mjs --wing everclaw --dry-run
2694+
2695+
# Export
2696+
node scripts/memory/export-obsidian-vault.mjs --wing everclaw --clean
2697+
```
2698+
2699+
Output: `~/Documents/EverClaw-Vault/` — open directly in Obsidian.
2700+
2701+
Vault structure:
2702+
```
2703+
EverClaw-Vault/
2704+
├── index.md # Global Map of Content
2705+
├── wings/<wing>/ # Wing MOC + rooms
2706+
│ └── rooms/<room>/ # Room MOC + drawer files
2707+
├── concepts/ # Entity pages (KG, Phase 2)
2708+
└── timeline/ # Dated memory pages
2709+
```
2710+
2711+
### Architecture
2712+
2713+
```
2714+
OpenClaw memory_search ──→ MEMORY.md + memory/*.md (embeddinggemma-300m-qat)
2715+
↕ complementary
2716+
MemPalace bridge ────────→ ChromaDB + temporal KG (all-MiniLM-L6-v2)
2717+
2718+
mempalace_bridge.py ← Python subprocess, JSON contract on stdout
2719+
mempalace-bridge.mjs ← Node.js wrapper, spawns Python
2720+
```
2721+
2722+
### Tests
2723+
2724+
```bash
2725+
npm run test:memory # 28 tests: backend, factory, bridge, regression
2726+
```
2727+
2728+
### Privacy
2729+
2730+
MemPalace stores data locally in `~/.mempalace/`. Exported vaults may contain PII — consider encrypting the folder or using Obsidian's encryption plugin.
2731+
2732+
### Files
2733+
2734+
| File | Purpose |
2735+
|------|---------|
2736+
| `scripts/python/mempalace_bridge.py` | Python bridge (MemPalace SDK ↔ JSON) |
2737+
| `scripts/memory/mempalace-bridge.mjs` | Node.js bridge wrapper |
2738+
| `scripts/memory/mempalace-search-hook.mjs` | Unified search API |
2739+
| `scripts/memory/migrate-to-mempalace.mjs` | One-time migration script |
2740+
| `scripts/memory/export-obsidian-vault.mjs` | Obsidian vault exporter |
2741+
| `scripts/lib/memory-backend.mjs` | Backend abstraction + factory |
2742+
| `scripts/lib/file-backend.mjs` | FileBackend (legacy fallback) |
2743+
| `scripts/lib/mempalace-backend.mjs` | MemPalaceBackend |
2744+
| `templates/everclaw-config-memory.json` | Memory config template |
2745+
| `tests/memory-backend.mjs` | Backend tests (19 tests) |
2746+
| `tests/mempalace-bridge.mjs` | Bridge tests (9 tests) |
2747+
2748+
---
2749+
26372750
## Changelog
26382751
2752+
### 2026.4.8
2753+
- **MemPalace Enhanced Memory** — ChromaDB vector search + temporal KG + Obsidian export
2754+
- 10 new files, 28 new tests
2755+
- setup.mjs Stage 6: MemPalace detection + bridge health check
2756+
- diagnose.sh A12: MemPalace SDK + palace status check
2757+
26392758
### 2026.4.2
26402759
- **Agent Download** — Say "download my agent" in chat to get a one-click encrypted backup with a temporary download link
26412760
- `agent-download-server.mjs` — Single-use token HTTP server with 15-minute auto-shutdown, CORS, secure shred

docker-compose.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
services:
1515
everclaw:
16-
image: ghcr.io/everclaw/everclaw:2026.4.7.1918
16+
image: ghcr.io/everclaw/everclaw:2026.4.8.0449
1717
build:
1818
context: .
1919
dockerfile: Dockerfile

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "everclaw",
3-
"version": "2026.4.7.1918",
3+
"version": "2026.4.8.0449",
44
"type": "module",
55
"description": "Open-source first AI inference via Morpheus decentralized network",
66
"scripts": {
@@ -10,6 +10,7 @@
1010
"test:docker": "node --test tests/lib-docker.mjs",
1111
"test:keychain": "node --test tests/lib-keychain.mjs",
1212
"test:manifest": "node --test tests/lib-manifest.mjs",
13+
"test:memory": "node --test tests/memory-backend.mjs tests/mempalace-bridge.mjs",
1314
"bootstrap": "node scripts/bootstrap-gateway.mjs"
1415
},
1516
"keywords": [

scripts/diagnose.sh

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,23 @@ print(count)
328328
pass "All model input modalities valid (text/image only)"
329329
fi
330330
fi
331+
332+
# A12: Is MemPalace installed for enhanced memory (optional)?
333+
if command -v python3 &>/dev/null; then
334+
if python3 -c "import mempalace" 2>/dev/null; then
335+
pass "MemPalace SDK installed (enhanced memory available)"
336+
local palace_path="$HOME/.mempalace/palace"
337+
if [[ -d "$palace_path" ]]; then
338+
pass "MemPalace palace exists at $palace_path"
339+
else
340+
warn "MemPalace palace not found — run migration to initialize"
341+
fix "node scripts/memory/migrate-to-mempalace.mjs --dry-run"
342+
fi
343+
else
344+
info "MemPalace not installed (optional enhancement for memory search)"
345+
fix "Install: pip install mempalace"
346+
fi
347+
fi
331348
}
332349

333350
# ═════════════════════════════════════════════════════════════════════════════

scripts/lib/bridge-call.mjs

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/**
2+
* bridge-call.mjs — Shared Python bridge communication utility
3+
*
4+
* Single source of truth for calling mempalace_bridge.py via spawn().
5+
* Used by both MemPalaceBackend and mempalace-search-hook.
6+
*
7+
* @module bridge-call
8+
*/
9+
10+
import { spawn } from 'child_process';
11+
import { join, dirname } from 'path';
12+
import { fileURLToPath } from 'url';
13+
14+
const __dirname = dirname(fileURLToPath(import.meta.url));
15+
const DEFAULT_BRIDGE_PATH = join(__dirname, '..', 'python', 'mempalace_bridge.py');
16+
17+
/**
18+
* Call the Python bridge and return parsed JSON.
19+
*
20+
* @param {string[]} args - Arguments for mempalace_bridge.py
21+
* @param {Object} [options]
22+
* @param {number} [options.timeout=60000] - Timeout in ms
23+
* @param {string} [options.bridgePath] - Override bridge script path
24+
* @param {string} [options.pythonPath='python3'] - Python binary
25+
* @param {boolean} [options.rejectOnError=true] - If false, resolve with error object instead of rejecting
26+
* @returns {Promise<Object>} Parsed JSON result
27+
*/
28+
export function callPythonBridge(args, options = {}) {
29+
const {
30+
timeout = 60_000,
31+
bridgePath = DEFAULT_BRIDGE_PATH,
32+
pythonPath = 'python3',
33+
rejectOnError = true,
34+
} = options;
35+
36+
return new Promise((resolve, reject) => {
37+
const proc = spawn(pythonPath, [bridgePath, ...args], {
38+
env: { ...process.env, PYTHONIOENCODING: 'utf-8' },
39+
timeout,
40+
stdio: ['ignore', 'pipe', 'pipe'],
41+
});
42+
43+
let stdout = '';
44+
let stderr = '';
45+
46+
proc.stdout.on('data', (d) => { stdout += d.toString(); });
47+
proc.stderr.on('data', (d) => { stderr += d.toString(); });
48+
49+
proc.on('close', (code) => {
50+
try {
51+
const result = JSON.parse(stdout.trim());
52+
53+
if (!result.success && rejectOnError) {
54+
const err = new Error(result.error || 'MemPalace bridge error');
55+
err.hint = result.hint;
56+
reject(err);
57+
return;
58+
}
59+
60+
resolve(result);
61+
} catch {
62+
const errorMsg = `MemPalace bridge failed (exit ${code}): ${stderr || stdout || 'no output'}`;
63+
if (rejectOnError) {
64+
reject(new Error(errorMsg));
65+
} else {
66+
resolve({ success: false, error: errorMsg });
67+
}
68+
}
69+
});
70+
71+
proc.on('error', (err) => {
72+
const errorMsg = `Failed to spawn Python bridge: ${err.message}`;
73+
if (rejectOnError) {
74+
reject(new Error(errorMsg));
75+
} else {
76+
resolve({ success: false, error: errorMsg });
77+
}
78+
});
79+
});
80+
}

0 commit comments

Comments
 (0)