🧪 Skills

Smart Memory

5-layer memory architecture for OpenClaw agents. Solves context bloat, the 48h fogging problem, and rule amnesia. Works for single-agent and multi-agent setu...

v1.5.5
❤️ 0
⬇️ 217
👁 1
Share

Description


name: smart-memory description: > 5-layer memory architecture for OpenClaw agents. Solves context bloat, the 48h fogging problem, and rule amnesia. Works for single-agent and multi-agent setups. Agent reads this file and sets up the full system. metadata: openclaw: emoji: 🧠

Smart Memory — Setup Skill

Was dieses Skill tut

Standard-OpenClaw-Setups akkumulieren über Wochen unkontrolliert Wissen in MEMORY.md. Das führt zu Kontextfenster-Überlastung, Widersprüchen und einem Agenten der wichtige Regeln "vergisst" obwohl sie in MEMORY.md stehen — und zu hartem 48h-Fogging bei Daily Logs.

Dieses Skill richtet eine 5-Schichten-Memory-Architektur ein die das löst.


AGENT: Setup-Anleitung

Gehe die folgenden Schritte der Reihe nach durch. [MULTI-AGENT ONLY]-Schritte können übersprungen werden wenn nur ein Agent im System ist.

Schritt 1: Verzeichnisse anlegen

mkdir -p memory/projects
mkdir -p memory/agents   # [MULTI-AGENT ONLY]
mkdir -p docs

Schritt 2: MEMORY.md auf Kern reduzieren

Lese die bestehende MEMORY.md. Extrahiere:

  • User-Profil (max. 3 Zeilen)
  • Projekt-Headlines (1 Zeile pro Projekt) → Verweis auf CONTEXT.md
  • Kritische Regeln (max. 5 Bullet Points)
  • Agent-Routing-Tabelle [MULTI-AGENT ONLY]

Alles andere gehört in active-context.md oder die Projekt-/Agent-Kontext-Dateien (s.u.). Schreibe das Ergebnis in MEMORY.md — Ziel: max. 35 Zeilen.

Füge am Ende hinzu:

## Memory-Architektur
- active-context.md → offene Themen + Kontext (täglich pflegen)
- memory/projects/<name>/CONTEXT.md → Projekthandbücher (on-demand injizieren)
- memory/agents/<typ>.md → Domain-Wissen (on-demand injizieren) [MULTI-AGENT ONLY]
- ⚠️ Schreib-Pflicht: Strukturelle Änderungen → active-context.md SOFORT updaten (Session kann jederzeit enden)

Schritt 3: active-context.md erstellen

Erstelle memory/active-context.md mit folgendem Header:

# Active Context
# Pflege-Regel: [DONE]-Einträge wöchentlich entfernen (automatisch via Cron/Heartbeat).
# Jeder Eintrag: Status + inhaltlicher Kontext (was der User erklärt hat).
# Nach Erledigung: gesamten Block löschen.
# Größenbremse: > 100 Zeilen = zu viele offene Themen oder zu geschwätzig → kürzen.

---

Befülle die Datei mit allem was aktuell offen ist (aus MEMORY.md, Tages-Logs, Kontext). Format pro Eintrag:

## [OPEN] <Thema> — <Kurzbeschreibung>
<Inhaltlicher Kontext: Was wurde erklärt, entschieden, vereinbart?>
<Relevante Regeln oder Hintergründe die der Agent kennen muss>

---

Besonders wichtig: Kritische Regeln die oft vergessen werden → als [OPEN]-Block aufnehmen (auch wenn sie "immer" gelten — das ist der Punkt, sie bleiben sichtbar bis sie wirklich verinnerlicht sind).

Schritt 4: Projekthandbücher anlegen

Für jedes aktive Projekt: memory/projects/<projektname>/CONTEXT.md

Extrahiere alle projektspezifischen Details aus MEMORY.md in diese Datei. Template: templates/projects/example/CONTEXT.md in diesem Skill-Ordner.

Wann updaten:

⚠️ Kritisch: "Am Ende des Tasks" ist ein Anti-Pattern — Sessions können jederzeit durch Rate-Limits oder Crashes enden. Die korrekte Anweisung ist: CONTEXT.md SOFORT nach der Aktion updaten, in derselben Antwort. Kein nachgelagerter Schritt.

Schritt 5: Agent-Domain-Wissen anlegen [MULTI-AGENT ONLY]

Für jeden Sub-Agent-Typ: memory/agents/<typ>.md

Enthält cross-project Wissen das für diesen Agent-Typ immer gilt. Templates: templates/agents/ in diesem Skill-Ordner.

Abgrenzung:

  • memory/agents/coding.md: "GPT erfindet Swift-Typen → nie GPT für Swift-Code"
  • memory/projects/myapp/CONTEXT.md: "myapp hat zwei .strings-Dateien die synchron bleiben müssen"

Wenn das Wissen beim nächsten Projekt auch gilt → agents/. Sonst → projects/.

Task-Summary-Pflicht für Sub-Agents: Jeder Sub-Agent sendet nach Abschluss eine Summary an den Orchestrator:

sessions_send(sessionKey="agent:main", message="[SUMMARY] Projekt: X | Was: Y | Status: Z")

Zweck: Orchestrator-Heartbeat kann als Backup-Bestätigung prüfen ob CONTEXT.md-Update erfolgte.

Schritt 6: AGENTS.md Startup-Sequenz updaten

Ersetze die "Every Session"-Sektion durch:

## Every Session

Before doing anything else:
1. Read `SOUL.md` — this is who you are
2. Read `USER.md` — this is who you're helping
3. **If in MAIN SESSION:** Read `MEMORY.md` + `memory/active-context.md`
4. Read `memory/YYYY-MM-DD.md` (today + yesterday) for recent raw context

**Sub-Agent Spawns [MULTI-AGENT ONLY]:** Injiziere in den Task-Prompt:
- Immer: Inhalt von `memory/agents/<typ>.md`
- Bei Projektarbeit: Inhalt von `memory/projects/<name>/CONTEXT.md`

Schritt 7: Automatischen Cleanup + Backup einrichten

Option A — Heartbeat (einfach): Füge in HEARTBEAT.md ein:

# TASK: Memory-Hygiene (wöchentlich, jeden Sonntag)
# Prüfe ob seit letztem Cleanup > 6 Tage vergangen (heartbeat-state.json).
# 1. Entferne alle [DONE]-Blöcke komplett aus memory/active-context.md
# 2. [OPEN]-Blöcke älter 30 Tage ohne Aktivität → in Tages-Log, aus active-context entfernen
# 3. memory/projects/*/CONTEXT.md — erledigte Tasks kürzen
# 4. lastMemoryCleanup Timestamp in memory/heartbeat-state.json schreiben

# TASK: Sub-Agent Memory Backup (bei JEDEM Heartbeat) [MULTI-AGENT ONLY]
# Sicherheitsnetz falls Sub-Agent CONTEXT.md-Sofortschreiben vergessen hat.
# 1. Lese letzten Sub-Agent-Output-Channel auf Abschluss-Posts
# 2. Prüfe ob strukturelle Änderungen in CONTEXT.md reflektiert sind
# 3. Falls NICHT → kompakten Eintrag ergänzen (was, wann, Commit/Status)

# TASK: Daily-Log automatisch schreiben (einmal täglich, abends)
# Prüfe ob memory/YYYY-MM-DD.md für heute existiert.
# Wenn NICHT: Lese memory/chat-YYYY-MM-DD.md → destilliere strukturelle Änderungen.
# Schreibe Ergebnis nach memory/YYYY-MM-DD.md (max. 30 Zeilen).

Option B — Cron-Job (präzise):

Schedule: 0 7 * * 0 (Sonntag 07:00 Ortszeit)
Message: "Wöchentliche Memory-Hygiene: [Cleanup-Anweisungen wie oben]"

Schritt 8: Abschlusskontrolle

Prüfe jedes Kriterium:

  • MEMORY.md < 40 Zeilen
  • active-context.md erstellt, mindestens ein [OPEN]-Eintrag
  • Jeder [OPEN]-Eintrag hat inhaltlichen Kontext, nicht nur Statuszeile
  • Keine projektspezifischen Details mehr in MEMORY.md
  • Wöchentlicher Cleanup aktiv (Heartbeat oder Cron)
  • AGENTS.md Startup-Sequenz updated
  • Für jedes aktive Projekt: CONTEXT.md angelegt [MULTI-AGENT ONLY]
  • Für jeden Sub-Agent-Typ: agents/.md angelegt [MULTI-AGENT ONLY]

Berichte dem User kurz: Was wurde eingerichtet, wie viele Zeilen hat MEMORY.md jetzt, wie viele offene Themen sind in active-context.md.


Session-Lifecycle: Graceful Termination (v1.3+)

Das Session-Bloat-Problem: Channel-Sessions (Slack, Discord etc.) wachsen unbegrenzt. Ab ~500 Zeilen wird jede Antwort spürbar langsamer — die gesamte History wird bei jeder Nachricht in den Kontext geladen. Ein harter Trim mitten im Gespräch löscht aber Kontext, Sprache und Persona sofort. Beides ist lösbar — ohne Script, ohne sichtbaren Output im Chat.

Goldene Regel 1 — Immer Memory schreiben lassen, bevor du trimmst oder killst: Bevor eine Session getrimmt oder gelöscht wird, muss der Agent die Möglichkeit haben, seinen Kontext in das Memory-System zu schreiben. Das gilt für manuelle Aktionen genauso wie für automatische Heartbeat-Tasks. Der Hash-Handshake-Flow (s.u.) ist die technische Umsetzung dieser Regel.

Goldene Regel 2: Niemals eine Channel-Session direkt trimmen oder löschen. Immer den Hash-Handshake-Flow verwenden. Kein separates Script nötig — der Heartbeat-LLM führt den Flow direkt aus.

Warum der Flow unsichtbar ist

Channel-Sessions (z.B. Slack) leiten jede Antwort an den Chat weiter. Sobald man aber NO_REPLY als einzigen Inhalt der Antwort vorgibt, unterdrückt OpenClaw den Output vollständig — nichts landet im Kanal. Der Hash in active-context.md dient als Out-of-Band-Bestätigung ohne Chat-Output.

Der Hash-Handshake-Flow

  1. Heartbeat prüft sessions.json → alle Keys mit :channel: ohne :thread:
  2. Für jede Session > 500 Zeilen UND > 2h inaktiv (updatedAt):
    • Generiere einmaligen Hash: TRIM_READY_<4 random chars> (z.B. TRIM_READY_a3f8)
    • sessions_send(sessionKey=<key>, timeoutSeconds=90, message="[WARTUNG] Schreibe jetzt alle offenen Themen und wichtigen Kontext in memory/active-context.md. Füge danach exakt diese Zeile am Ende ein: TRIM_HASH: <hash>. Antworte ausschließlich mit NO_REPLY.")
    • Lese memory/active-context.md → suche nach TRIM_HASH: <hash>
    • Hash gefunden: Sicher trimmen (s.u.) + TRIM_HASH:-Zeile entfernen + Log: TRIMMED
    • Hash nicht gefunden (Timeout): Trotzdem trimmen + Log: FORCE-TRIM

Warum Force-Trim nach Timeout OK ist: Eine Session die 90s nicht reagiert, ist faktisch eingefroren. Wichtige Infos stehen bereits in active-context.md aus früheren Saves. Der Schaden durch dauerhaft aufgeblähte Sessions überwiegt.

⚠️ Thread-Sessions niemals trimmen: Keys mit :thread: enthalten laufende Unterhaltungs-Threads und müssen von der Trim-Logik ausgeschlossen werden.

⚠️ Sicheres Trimmen: Nie mitten in einem Tool-Call schneiden

tail -60 kann mitten in einem Tool-Call-Block landen (toolUse ohne nachfolgendes toolResult, oder toolResult ohne nachfolgende Assistenten-Antwort). Das hinterlässt die Session in einem ungültigen Zustand — der Agent schweigt danach komplett.

Pflicht: Immer auf einer vollständigen Assistenten-Antwort abschneiden.

import json

def safe_trim(session_file, keep_lines=60):
    lines = open(session_file).readlines()
    if len(lines) <= keep_lines:
        return  # Nichts zu tun
    
    # Kandidaten-Startpunkte: nur Zeilen wo role=assistant und kein toolUse
    candidates = []
    for i, line in enumerate(lines):
        try:
            msg = json.loads(line).get('message', {})
            if msg.get('role') != 'assistant':
                continue
            content = msg.get('content', [])
            # Nur wenn keine toolCall-Blöcke in der Antwort
            if not any(c.get('type') == 'toolCall' for c in content if isinstance(c, dict)):
                candidates.append(i)
        except:
            continue
    
    # Letzten Kandidaten der noch >= keep_lines vom Ende entfernt ist
    cutpoint = None
    for i in reversed(candidates):
        if len(lines) - i >= keep_lines:
            cutpoint = i
            break
    
    if cutpoint is None:
        cutpoint = max(0, len(lines) - keep_lines)
    
    with open(session_file, 'w') as f:
        f.writelines(lines[cutpoint:])

Dieses Skript sicherstellen dass der Trim immer nach einer abgeschlossenen Assistenten-Antwort beginnt — nie mitten in einem Tool-Austausch.

Heartbeat-Task-Template (direkt in HEARTBEAT.md einfügen)

# TASK: Auto-Trim große Channel-Sessions (bei JEDEM Heartbeat)
# [INSTRUCTION for LLM]:
# 1. Lese <workspace>/.openclaw/agents/main/sessions/sessions.json
# 2. Finde alle Keys die ":channel:" enthalten UND KEIN ":thread:" haben
# 3. Für jeden solchen Key: prüfe Zeilenanzahl der sessionFile (wc -l)
# 4. Wenn > 500 Zeilen UND updatedAt > 2h her:
#    a. Generiere Hash: TRIM_READY_<4 random chars>
#    b. sessions_send(sessionKey=<key>, timeoutSeconds=90,
#       message="[WARTUNG] Schreibe jetzt alle offenen Themen und wichtigen Kontext
#       in memory/active-context.md. Füge danach exakt diese Zeile am Ende ein:
#       TRIM_HASH: <hash>
#       Antworte ausschließlich mit NO_REPLY.")
#    c. Lese memory/active-context.md → suche nach "TRIM_HASH: <hash>"
#    d. Hash gefunden:
#       - tail -60 <sessionFile> > /tmp/trim.jsonl && mv /tmp/trim.jsonl <sessionFile>
#       - Entferne TRIM_HASH-Zeile aus active-context.md
#       - Log: "<ISO> | <key> | TRIMMED" → memory/trim-log.txt
#    e. Hash nicht gefunden (Timeout):
#       - tail -60 <sessionFile> > /tmp/trim.jsonl && mv /tmp/trim.jsonl <sessionFile>
#       - Log: "<ISO> | <key> | FORCE-TRIM" → memory/trim-log.txt

Pflicht-Ergänzung in AGENTS.md

## Session-Management (Harte Regel, keine Ausnahmen)

NIEMALS eine Channel-Session direkt löschen oder trimmen.
Immer den Hash-Handshake-Flow via Heartbeat verwenden (siehe smart-memory Skill).
Thread-Sessions (:thread: im Key) sind grundsätzlich ausgenommen.

Neue Agents: Memory-System als Standard

Jeder neue Agent bekommt das Memory-System — mit einer Ausnahme:

Agent-Typ Memory-System?
Haupt-Agent (Orchestrator) ✅ Pflicht — vollständige 5-Schichten-Architektur
Persistente Sub-Agents (eigene Channels, lange Laufzeit) ✅ Pflicht — mindestens active-context.md
Reine Task-Sub-Agents (begrenzte Aufgabe, Kontext aus Prompt) ❌ Nicht nötig — Kontext kommt vom Orchestrator

Erkennungsmerkmal für "reine Task-Sub-Agents":

  • Werden für einen einzelnen, klar begrenzten Task gespawnt
  • Erhalten ihren gesamten Kontext im Task-Prompt vom Haupt-Agent
  • Haben keinen eigenen persistenten Channel
  • Schreiben ihr Ergebnis zurück an den Orchestrator (Summary via sessions_send)

Erkennungsmerkmal für "persistente Sub-Agents":

  • Haben einen eigenen Slack-/Discord-Channel
  • Werden wiederholt für ähnliche Tasks genutzt
  • Akkumulieren über Zeit domänenspezifisches Wissen

Faustregel: Wenn ein Agent Gespräche führt oder wiederholtes Wissen aufbaut → Memory. Wenn ein Agent einen einzigen Task abarbeitet und dann fertig ist → kein Memory nötig.


Tägliche Schreib-Regeln (nach Setup)

Situation Aktion
User erklärt etwas Wichtiges [OPEN]-Block in active-context.md mit vollem Kontext
Strukturelle Änderung (Channel, Projekt, Regel) → active-context.md SOFORT in derselben Antwort
Technische Erkenntnis bei Coding → CONTEXT.md SOFORT (nicht am Task-Ende)
Cross-project Lesson → memory/agents/.md updaten
Sub-Agent Task abgeschlossen [MULTI-AGENT] → CONTEXT.md sofort + Summary an Orchestrator
Thema abgeschlossen [DONE] markieren (Cleanup entfernt Block)
MEMORY.md nähert sich 40 Zeilen → destillieren: Was ist wirklich dauerhaft relevant?
active-context.md > 100 Zeilen → Warnsignal: Einträge kürzen oder klären

Goldene Regel: Schreiben ist Teil der Aktion, nicht ein nachgelagerter Schritt. Sessions enden unvorhersehbar. Was nicht sofort geschrieben wird, ist verloren.


Warum das funktioniert

Das Fogging-Problem: In Standard-Setups gibt es nur Daily Logs (heute + gestern). Was vor 3 Tagen besprochen wurde, ist weg. Der User muss alles neu erklären.

Die Lösung: active-context.md schreibt Relevanz, nicht Zeit. Ein offenes Thema bleibt im Kontext bis es erledigt ist — egal wie lange das dauert. Nach Erledigung fliegt es raus. Kein unkontrolliertes Aufblähen, weil erledigte Themen aktiv entfernt werden.

Das Rauschen-Problem: MEMORY.md wächst über Monate auf hunderte Zeilen. Der Agent sieht alles gleichzeitig — Swift-Lektionen neben Marketing-Strategie neben Cron-IDs. Alles konkurriert um Aufmerksamkeit. Regeln werden "vergessen" weil sie im Rauschen untergehen.

Die Lösung: Jede Schicht hat einen klar begrenzten Scope. Projektdetails sind nicht im Orchestrator-Kontext — sie werden on-demand in Sub-Agent-Prompts injiziert wenn sie gebraucht werden. Kein Rauschen, keine Ablenkung.

Das Session-Crash-Problem (neu in v1.1): "Am Ende der Session schreiben" versagt wenn Sessions durch Rate-Limits oder Crashes enden. Die Lösung: Schreiben ist Teil der Aktion selbst — sofort, inline, bevor die Antwort gesendet wird. Der Heartbeat ist das Backup-Netz, nicht der Primary-Trigger.

Reviews (0)

Sign in to write a review.

No reviews yet. Be the first to review!

Comments (0)

Sign in to join the discussion.

No comments yet. Be the first to share your thoughts!

Compatible Platforms

Pricing

Free

Related Configs