471 lines
19 KiB
Markdown
471 lines
19 KiB
Markdown
# OpenClaw Ultimate Memory Upgrade
|
|
|
|
The most advanced OpenClaw memory system available. Copy-paste this prompt and your agent installs everything — 6 layers of memory, auto-curation, semantic search, and smart token loading. No manual setup required.
|
|
source: https://mission-control-prompts.vercel.app/?utm_source=youtube&utm_medium=video&utm_campaign=long-term-memory
|
|
|
|
💡 **Before you run this:** You'll need a free Google Gemini API key for the vector memory layer. Get one in 30 seconds at [aistudio.google.com](https://aistudio.google.com/) — no credit card required.
|
|
|
|
---
|
|
|
|
🧠 **Ultimate Memory Upgrade Prompt**
|
|
|
|
Paste into your OpenClaw chat — agent does the rest.
|
|
|
|
> You are about to receive a full memory system upgrade. This will install and configure every layer of the elite memory stack — without touching or deleting anything you already have. Read all instructions carefully, then execute them in order.
|
|
|
|
|
|
> ⚠️ **Do this FIRST — if you installed OpenClaw recently**
|
|
>
|
|
> **Applies to you if:** You installed or updated OpenClaw to version `2026.3.2` or newer (released March 4, 2026). New installs on this version default to limited tools and your agent won't be able to run scripts or install packages without this fix.
|
|
>
|
|
> Not sure what version you have? Open your terminal and run `openclaw --version` to check. If you're on an older version, you can skip this step.
|
|
>
|
|
> Run this command in your terminal:
|
|
> ```bash
|
|
> openclaw config set tools.profile coding
|
|
> ```
|
|
>
|
|
> **🍎 Mac**
|
|
>
|
|
> Press `Cmd + Space`, type `Terminal`, hit Enter. Paste the command above and press Enter.
|
|
>
|
|
> **🪟 Windows**
|
|
>
|
|
> Press `Win + R`, type `cmd`, hit Enter. Paste the command above and press Enter.
|
|
>
|
|
> Once done, come back here and copy the prompt below. Your agent handles everything else from chat.
|
|
---
|
|
|
|
### OVERVIEW — What you are installing
|
|
|
|
- **Layer 1: Daily Notes** — auto-written session logs (you likely already have this)
|
|
- **Layer 2: MEMORY.md** — curated long-term memory with smart structure (upgrading yours)
|
|
- **Layer 3: projects.md** — compact project registry for fast startup context loading
|
|
- **Layer 4: Vector DB** — PostgreSQL + pgvector semantic memory with AI-powered search
|
|
- **Layer 5: Smart HEARTBEAT.md loading** — 4K tokens instead of 20K per heartbeat
|
|
- **Layer 6: Twice-weekly auto-curation cron** — MEMORY.md rewrites itself automatically
|
|
|
|
---
|
|
|
|
### Step 1 — Read what you already have
|
|
|
|
Read the following files in full:
|
|
|
|
- `~/.openclaw/workspace/HEARTBEAT.md`
|
|
- `~/.openclaw/workspace/MEMORY.md`
|
|
- `~/.openclaw/workspace/AGENTS.md` (if it exists)
|
|
|
|
Note what is already there. You will upgrade, not replace.
|
|
|
|
---
|
|
|
|
### Step 2 — Create or upgrade `projects.md`
|
|
|
|
Read all files in `~/.openclaw/workspace/memory/` to understand what projects, clients, and tools are already documented.
|
|
|
|
Then create or overwrite `~/.openclaw/workspace/memory/projects.md` with a clean project registry. Include:
|
|
|
|
- Every active project with its live URL (if applicable)
|
|
- Current status (live / in progress / blocked)
|
|
- Tech stack (brief)
|
|
- Key notes or blockers
|
|
- File locations on disk
|
|
|
|
Format it as a markdown table or clean sections. Keep it under 80 lines total. This file loads at every heartbeat so lean is good.
|
|
|
|
If you cannot find enough info to populate it, ask the user:
|
|
> "What are your 3 to 5 most active projects right now? Give me the name, what it does, and the URL if it is live."
|
|
|
|
---
|
|
|
|
### Step 3 — Upgrade `HEARTBEAT.md`
|
|
|
|
Read the current `HEARTBEAT.md`. Add the following block at the very TOP of the file (above everything else). Do not remove anything that is already there:
|
|
|
|
````markdown
|
|
## SMART MEMORY LOADING (do this first, every heartbeat)
|
|
|
|
Before anything else, load context efficiently:
|
|
|
|
1. Read `memory/projects.md` — compact project registry (~1K tokens)
|
|
2. Read `MEMORY.md` — curated long-term memory (~3K tokens)
|
|
3. Only load daily notes (`memory/YYYY-MM-DD.md`) when asked about specific past work
|
|
4. Only run vector search when a specific question about past work comes up
|
|
|
|
This gives full context at ~10% of the token cost. Daily notes are archives, not runtime docs.
|
|
````
|
|
|
|
---
|
|
|
|
### Step 4 — Upgrade `MEMORY.md`
|
|
|
|
Read the current `MEMORY.md`. Add a new section called `## Memory System` (if it does not already exist) with the following content:
|
|
|
|
````markdown
|
|
## Memory System
|
|
|
|
- **Daily notes:** `memory/YYYY-MM-DD.md` — raw session logs, written automatically, load on-demand
|
|
- **MEMORY.md:** curated long-term brain — load every heartbeat (~3K tokens)
|
|
- **projects.md:** compact project registry — load every heartbeat (~1K tokens)
|
|
- **Vector DB:** PostgreSQL + pgvector, semantic search via AI embeddings
|
|
- **Smart loading:** only `projects.md` + `MEMORY.md` at startup. Daily notes + vector search = on-demand only. Saves ~80% token cost vs loading everything.
|
|
````
|
|
|
|
Also update the `Last updated` date at the top of `MEMORY.md` to today's date.
|
|
|
|
---
|
|
|
|
### Step 5 — Install Vector Memory (PostgreSQL + pgvector)
|
|
|
|
#### 5a — Check if PostgreSQL is installed
|
|
|
|
Run:
|
|
```bash
|
|
which psql
|
|
```
|
|
|
|
If not found, install it:
|
|
- **macOS:** `brew install postgresql@17 && brew services start postgresql@17 && echo 'export PATH="/opt/homebrew/opt/postgresql@17/bin:$PATH"' >> ~/.zshrc && source ~/.zshrc`
|
|
- **Linux:** `sudo apt install postgresql postgresql-contrib`
|
|
|
|
#### 5b — Install vector-memory skill scripts
|
|
|
|
Run:
|
|
```bash
|
|
mkdir -p ~/.openclaw/workspace/skills/vector-memory/scripts/
|
|
```
|
|
|
|
Then write each of the following 4 files to disk exactly as shown:
|
|
|
|
**FILE 1: `~/.openclaw/workspace/skills/vector-memory/scripts/memory_flush.py`**
|
|
```python
|
|
#!/usr/bin/env python3
|
|
"""Flush daily memory files into vector database."""
|
|
import argparse, glob, hashlib, json, os, re, sys, urllib.request
|
|
import psycopg2
|
|
|
|
DB = "dbname=openclaw_memory"
|
|
GEMINI_KEY = os.environ.get("GEMINI_API_KEY", "")
|
|
EMBED_MODEL = "gemini-embedding-001"
|
|
WORKSPACE = os.path.expanduser("~/.openclaw/workspace")
|
|
MEMORY_DIR = os.path.join(WORKSPACE, "memory")
|
|
FLUSH_TRACKER = os.path.join(MEMORY_DIR, "vector-flush-tracker.json")
|
|
|
|
def get_embedding(text):
|
|
url = f"https://generativelanguage.googleapis.com/v1beta/models/{EMBED_MODEL}:embedContent?key={GEMINI_KEY}"
|
|
payload = json.dumps({"model": f"models/{EMBED_MODEL}", "content": {"parts": [{"text": text}]}, "outputDimensionality": 768}).encode()
|
|
req = urllib.request.Request(url, data=payload, headers={"Content-Type": "application/json"})
|
|
with urllib.request.urlopen(req) as resp:
|
|
return json.loads(resp.read())["embedding"]["values"]
|
|
|
|
def load_tracker():
|
|
if os.path.exists(FLUSH_TRACKER):
|
|
with open(FLUSH_TRACKER) as f:
|
|
return json.load(f)
|
|
return {"flushed_files": {}}
|
|
|
|
def save_tracker(t):
|
|
with open(FLUSH_TRACKER, "w") as f:
|
|
json.dump(t, f, indent=2)
|
|
|
|
def chunk_markdown(text, source_file):
|
|
chunks, current_section, current_text = [], "", []
|
|
for line in text.split("\n"):
|
|
if re.match(r'^#{1,3}\s', line):
|
|
if current_text:
|
|
content = "\n".join(current_text).strip()
|
|
if len(content) > 20:
|
|
chunks.append({"text": content, "label": current_section.strip("# ").strip(), "source_file": source_file})
|
|
current_section, current_text = line, [line]
|
|
else:
|
|
current_text.append(line)
|
|
if current_text:
|
|
content = "\n".join(current_text).strip()
|
|
if len(content) > 20:
|
|
chunks.append({"text": content, "label": current_section.strip("# ").strip(), "source_file": source_file})
|
|
return chunks
|
|
|
|
def file_hash(fp):
|
|
with open(fp) as f:
|
|
return hashlib.md5(f.read().encode()).hexdigest()
|
|
|
|
def flush(dry_run=False, force=False):
|
|
tracker = load_tracker()
|
|
conn = psycopg2.connect(DB) if not dry_run else None
|
|
files = sorted(glob.glob(os.path.join(MEMORY_DIR, "*.md")))
|
|
memory_md = os.path.join(WORKSPACE, "MEMORY.md")
|
|
if os.path.exists(memory_md):
|
|
files.append(memory_md)
|
|
total_stored = 0
|
|
for filepath in files:
|
|
fname = os.path.basename(filepath)
|
|
fhash = file_hash(filepath)
|
|
if not force and fname in tracker["flushed_files"] and tracker["flushed_files"][fname] == fhash:
|
|
continue
|
|
with open(filepath) as f:
|
|
content = f.read()
|
|
chunks = chunk_markdown(content, fname)
|
|
if dry_run:
|
|
print(f"[DRY RUN] {fname}: {len(chunks)} chunks")
|
|
continue
|
|
cur = conn.cursor()
|
|
cur.execute("DELETE FROM memories WHERE metadata->>'source_file' = %s", (fname,))
|
|
for chunk in chunks:
|
|
embedding = get_embedding(chunk["text"])
|
|
vec_str = "[" + ",".join(str(v) for v in embedding) + "]"
|
|
cur.execute("INSERT INTO memories (text, label, category, source, embedding, metadata) VALUES (%s,%s,%s,%s,%s::vector,%s)",
|
|
(chunk["text"], chunk["label"], "daily-note", "flush", vec_str, json.dumps({"source_file": fname})))
|
|
total_stored += 1
|
|
conn.commit()
|
|
cur.close()
|
|
tracker["flushed_files"][fname] = fhash
|
|
print(f"[FLUSHED] {fname}: {len(chunks)} chunks stored")
|
|
if conn:
|
|
conn.close()
|
|
save_tracker(tracker)
|
|
print(json.dumps({"total_stored": total_stored, "files_processed": len(files)}))
|
|
|
|
if __name__ == "__main__":
|
|
p = argparse.ArgumentParser()
|
|
p.add_argument("--dry-run", action="store_true")
|
|
p.add_argument("--force", action="store_true")
|
|
args = p.parse_args()
|
|
flush(args.dry_run, args.force)
|
|
```
|
|
|
|
**FILE 2: `~/.openclaw/workspace/skills/vector-memory/scripts/memory_search.py`**
|
|
```python
|
|
#!/usr/bin/env python3
|
|
"""Search memories by semantic similarity."""
|
|
import argparse, json, os, urllib.request
|
|
import psycopg2
|
|
|
|
DB = "dbname=openclaw_memory"
|
|
GEMINI_KEY = os.environ.get("GEMINI_API_KEY", "")
|
|
EMBED_MODEL = "gemini-embedding-001"
|
|
|
|
def get_embedding(text):
|
|
url = f"https://generativelanguage.googleapis.com/v1beta/models/{EMBED_MODEL}:embedContent?key={GEMINI_KEY}"
|
|
payload = json.dumps({"model": f"models/{EMBED_MODEL}", "content": {"parts": [{"text": text}]}, "outputDimensionality": 768}).encode()
|
|
req = urllib.request.Request(url, data=payload, headers={"Content-Type": "application/json"})
|
|
with urllib.request.urlopen(req) as resp:
|
|
return json.loads(resp.read())["embedding"]["values"]
|
|
|
|
def search(query, limit=5, category=None, min_score=0.0):
|
|
embedding = get_embedding(query)
|
|
vec_str = "[" + ",".join(str(v) for v in embedding) + "]"
|
|
sql = "SELECT id, text, label, category, source, created_at, 1-(embedding<=>%s::vector) as similarity FROM memories"
|
|
params = [vec_str, vec_str, limit]
|
|
if category:
|
|
sql += " WHERE category=%s"
|
|
params = [vec_str, vec_str, category, limit]
|
|
sql += " ORDER BY embedding<=>%s::vector LIMIT %s"
|
|
conn = psycopg2.connect(DB)
|
|
cur = conn.cursor()
|
|
cur.execute(sql, params)
|
|
results = [{"id": r[0], "text": r[1], "label": r[2], "category": r[3], "source": r[4], "created_at": r[5].isoformat(), "similarity": round(float(r[6]),4)} for r in cur.fetchall() if float(r[6]) >= min_score]
|
|
cur.close()
|
|
conn.close()
|
|
print(json.dumps({"query": query, "count": len(results), "results": results}, indent=2))
|
|
|
|
if __name__ == "__main__":
|
|
p = argparse.ArgumentParser()
|
|
p.add_argument("query")
|
|
p.add_argument("--limit", "-n", type=int, default=5)
|
|
p.add_argument("--category", "-c", default=None)
|
|
p.add_argument("--min-score", type=float, default=0.3)
|
|
args = p.parse_args()
|
|
search(args.query, args.limit, args.category, args.min_score)
|
|
```
|
|
|
|
**FILE 3: `~/.openclaw/workspace/skills/vector-memory/scripts/memory_store.py`**
|
|
```python
|
|
#!/usr/bin/env python3
|
|
"""Store a memory with vector embedding."""
|
|
import argparse, json, os, urllib.request
|
|
import psycopg2
|
|
|
|
DB = "dbname=openclaw_memory"
|
|
GEMINI_KEY = os.environ.get("GEMINI_API_KEY", "")
|
|
EMBED_MODEL = "gemini-embedding-001"
|
|
|
|
def get_embedding(text):
|
|
url = f"https://generativelanguage.googleapis.com/v1beta/models/{EMBED_MODEL}:embedContent?key={GEMINI_KEY}"
|
|
payload = json.dumps({"model": f"models/{EMBED_MODEL}", "content": {"parts": [{"text": text}]}, "outputDimensionality": 768}).encode()
|
|
req = urllib.request.Request(url, data=payload, headers={"Content-Type": "application/json"})
|
|
with urllib.request.urlopen(req) as resp:
|
|
return json.loads(resp.read())["embedding"]["values"]
|
|
|
|
def store(text, label=None, category=None, source="conversation", metadata=None):
|
|
embedding = get_embedding(text)
|
|
vec_str = "[" + ",".join(str(v) for v in embedding) + "]"
|
|
conn = psycopg2.connect(DB)
|
|
cur = conn.cursor()
|
|
cur.execute("INSERT INTO memories (text,label,category,source,embedding,metadata) VALUES (%s,%s,%s,%s,%s::vector,%s) RETURNING id,created_at",
|
|
(text, label, category, source, vec_str, json.dumps(metadata or {})))
|
|
row = cur.fetchone()
|
|
conn.commit()
|
|
cur.close()
|
|
conn.close()
|
|
print(json.dumps({"id": row[0], "created_at": row[1].isoformat(), "label": label, "category": category, "text": text[:100]}))
|
|
|
|
if __name__ == "__main__":
|
|
p = argparse.ArgumentParser()
|
|
p.add_argument("text")
|
|
p.add_argument("--label", "-l", default=None)
|
|
p.add_argument("--category", "-c", default=None)
|
|
p.add_argument("--source", "-s", default="conversation")
|
|
p.add_argument("--meta", "-m", default=None)
|
|
args = p.parse_args()
|
|
store(args.text, args.label, args.category, args.source, json.loads(args.meta) if args.meta else None)
|
|
```
|
|
|
|
**FILE 4: `~/.openclaw/workspace/skills/vector-memory/scripts/memory_forget.py`**
|
|
```python
|
|
#!/usr/bin/env python3
|
|
"""Delete memories by id, category, or age."""
|
|
import argparse, json
|
|
import psycopg2
|
|
from datetime import datetime, timedelta
|
|
|
|
DB = "dbname=openclaw_memory"
|
|
|
|
def forget(id=None, category=None, older_than_days=None):
|
|
conn = psycopg2.connect(DB)
|
|
cur = conn.cursor()
|
|
if id:
|
|
cur.execute("DELETE FROM memories WHERE id=%s RETURNING id,text", (id,))
|
|
elif category:
|
|
cur.execute("DELETE FROM memories WHERE category=%s RETURNING id,text", (category,))
|
|
elif older_than_days:
|
|
cutoff = datetime.now() - timedelta(days=older_than_days)
|
|
cur.execute("DELETE FROM memories WHERE created_at<%s RETURNING id,text", (cutoff,))
|
|
else:
|
|
print("Error: provide --id, --category, or --older-than")
|
|
return
|
|
deleted = cur.fetchall()
|
|
conn.commit()
|
|
cur.close()
|
|
conn.close()
|
|
print(json.dumps({"deleted": len(deleted), "ids": [r[0] for r in deleted]}))
|
|
|
|
if __name__ == "__main__":
|
|
p = argparse.ArgumentParser()
|
|
p.add_argument("--id", type=int, default=None)
|
|
p.add_argument("--category", default=None)
|
|
p.add_argument("--older-than", type=int, default=None)
|
|
args = p.parse_args()
|
|
forget(args.id, args.category, args.older_than)
|
|
```
|
|
|
|
After writing all 4 files, verify they exist:
|
|
```bash
|
|
ls ~/.openclaw/workspace/skills/vector-memory/scripts/
|
|
```
|
|
|
|
#### 5c — Install Python dependency
|
|
|
|
```bash
|
|
pip3 install psycopg2-binary
|
|
```
|
|
(This is the Python driver that connects to PostgreSQL. Required for all 4 scripts.)
|
|
|
|
#### 5d — Set up the database
|
|
|
|
```bash
|
|
psql postgres -c "CREATE DATABASE openclaw_memory;" 2>/dev/null || echo "DB may already exist"
|
|
psql openclaw_memory -c "CREATE EXTENSION IF NOT EXISTS vector;"
|
|
psql openclaw_memory -c "CREATE TABLE IF NOT EXISTS memories (id SERIAL PRIMARY KEY, text TEXT NOT NULL, label TEXT, category TEXT, source TEXT, embedding vector(768), metadata JSONB DEFAULT '{}', created_at TIMESTAMPTZ DEFAULT NOW());"
|
|
psql openclaw_memory -c "CREATE INDEX IF NOT EXISTS memories_embedding_idx ON memories USING ivfflat (embedding vector_cosine_ops);"
|
|
```
|
|
|
|
#### 5e — Check for Gemini API key
|
|
|
|
The vector memory system uses Google Gemini for embeddings (free tier, no credit card needed).
|
|
|
|
Run:
|
|
```bash
|
|
echo $GEMINI_API_KEY
|
|
```
|
|
|
|
If empty, ask the user:
|
|
> "Do you have a Google Gemini API key? Get one free at aistudio.google.com. Paste it here and I will configure it."
|
|
|
|
Once you have the key, add it to your shell profile:
|
|
- **macOS/Linux:** `echo 'export GEMINI_API_KEY="your-key-here"' >> ~/.zshrc && source ~/.zshrc`
|
|
|
|
#### 5f — Run the initial memory flush
|
|
|
|
```bash
|
|
python3 ~/.openclaw/workspace/skills/vector-memory/scripts/memory_flush.py
|
|
```
|
|
Report back how many memories were stored.
|
|
|
|
---
|
|
|
|
### Step 6 — Add twice-weekly auto-curation cron
|
|
|
|
Use the OpenClaw cron tool to create a job with these settings:
|
|
- **Name:** "Twice-Weekly MEMORY.md Auto-Curation"
|
|
- **Schedule:** cron expression `"0 5 * * 3,0"` (Wednesday and Sunday at 5am local time)
|
|
- **Session target:** isolated
|
|
- **Model:** `anthropic/claude-sonnet-4-20250514` (or your default model)
|
|
- **Delivery:** announce to your chat when complete
|
|
|
|
**The cron agent message:**
|
|
> Your job is to auto-curate `MEMORY.md`.
|
|
>
|
|
> **STEP 1:** Find the 7 most recent daily note files. Run: `ls ~/.openclaw/workspace/memory/*.md | sort | tail -10` then read each one.
|
|
>
|
|
> **STEP 2:** Read current `MEMORY.md` in full.
|
|
>
|
|
> **STEP 3:** Identify what is stale (old stats, outdated project info), what is new (decisions, clients, launches), and what should be removed.
|
|
>
|
|
> **STEP 4:** Rewrite `MEMORY.md` with accurate, current information. Keep the same sections. Update numbers. Add new sections for major new things. Remove outdated info. Update the `Last Updated` date. Max 400 lines.
|
|
>
|
|
> **STEP 5:** Run: `python3 ~/.openclaw/workspace/skills/vector-memory/scripts/memory_flush.py`
|
|
>
|
|
> **STEP 6:** Update `projects.md` with any status changes you found.
|
|
>
|
|
> Announce a brief summary when done.
|
|
|
|
---
|
|
|
|
### Step 7 — Add vector memory flush to `HEARTBEAT.md`
|
|
|
|
Add this to your `HEARTBEAT.md` near the bottom:
|
|
|
|
````markdown
|
|
## Vector Memory Flush (every heartbeat)
|
|
|
|
Run: `python3 ~/.openclaw/workspace/skills/vector-memory/scripts/memory_flush.py`
|
|
|
|
If `total_stored = 0`, that is fine — means nothing new to embed.
|
|
````
|
|
|
|
---
|
|
|
|
### Step 8 — Verify everything works
|
|
|
|
Run these 4 checks and report results:
|
|
|
|
1. `python3 ~/.openclaw/workspace/skills/vector-memory/scripts/memory_search.py "recent projects"`
|
|
2. `cat ~/.openclaw/workspace/memory/projects.md`
|
|
3. `head -20 ~/.openclaw/workspace/HEARTBEAT.md`
|
|
4. List cron jobs to confirm the auto-curation cron was created
|
|
|
|
---
|
|
|
|
### Step 9 — Summary report
|
|
|
|
When all steps are complete, give me a summary:
|
|
- [ ] Layers installed (checkmark each one)
|
|
- [ ] Number of memories in vector DB
|
|
- [ ] Projects in `projects.md`
|
|
- [ ] Cron scheduled for (next run date)
|
|
- [ ] Any steps that failed or need manual attention
|
|
|
|
---
|
|
|
|
> You now have the most advanced OpenClaw memory system available. Your agent will load context in 4K tokens instead of 20K+ (80% savings), search memory semantically, auto-update its long-term memory twice a week, and never forget what you have built, decided, or discussed. Let's go.
|