📋 Resumen Ejecutivo
Esta investigación analiza el mecanismo de compaction y memory flush de OpenClaw, su configuración actual, y las discrepancias observadas entre documentación y comportamiento real.
NO_REPLY en transcripts JSONL de sesiones antiguas
memoryFlushAt y memoryFlushCompactionCount son null actualmente
mode: "safeguard", no hay override de memoryFlush
memory/ tiene 3 archivos (Jan 31, Feb 2, Feb 4) pero gaps en días intermedios
1. Objetivo de la Investigación
Se buscaba entender y potencialmente extender el sistema de hooks de OpenClaw para ejecutar lógica personalizada before/after compaction. El caso de uso principal: asegurar que información crítica de sesión se persista a disco antes de que el contexto sea compactado (y potencialmente perdido).
Preguntas clave
- ¿Existe un sistema de hooks
before_compaction/after_compaction? - ¿Cómo funciona el
memoryFlushnativo de OpenClaw? - ¿Por qué no vemos archivos de sesión nuevos en
~/.openclaw/agents/main/sessions/? - ¿Cómo verificar si el flush está ejecutándose?
2. Documentación vs. Código Real
Lo que dicen los docs
La documentación en /opt/openclaw/docs/ describe un sistema completo de memory flush pre-compaction:
"When a session is close to auto-compaction, OpenClaw triggers a silent, agentic turn that reminds the model to write durable memory before the context is compacted."
agents.defaults.compaction.memoryFlush:
enabled: true (default)
softThresholdTokens: 4000 (default)
prompt: "Write any lasting notes to memory/YYYY-MM-DD.md..."
systemPrompt: "Session nearing compaction. Store durable memories now."
Lo que encontramos en código
El código en /opt/openclaw/dist/auto-reply/reply/agent-runner-memory.js confirma la existencia del sistema:
// Extractos del código real
const memoryFlushSettings = resolveMemoryFlushSettings(params.cfg);
if (!memoryFlushSettings) { return; }
const shouldFlushMemory = memoryFlushSettings &&
memoryFlushWritable &&
reserveTokensFloor: memoryFlushSettings.reserveTokensFloor,
softThresholdTokens: memoryFlushSettings.softThresholdTokens,
// Tracking en session entry
memoryFlushAt: Date.now(),
memoryFlushCompactionCount: nextCount
Discrepancias observadas
| Aspecto | Documentación | Realidad Observada |
|---|---|---|
| memoryFlush.enabled | Default true |
No explícito en config, asumido true |
| Tracking fields | Se actualizan en sessions.json | Todos null actualmente |
| Hook before_compact | "Pi exposes session_before_compact" | No visible en openclaw hooks list |
| Evidencia de ejecución | Silent turns con NO_REPLY | 18 ocurrencias en JSONL antiguos ✓ |
3. Cómo Funciona memoryFlush
Flujo de ejecución
┌─────────────────────────────────────────────────────────────┐
│ SESSION TURN │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. Gateway recibe mensaje │
│ ↓ │
│ 2. Calcula contextTokens vs contextWindow │
│ ↓ │
│ 3. Si contextTokens > (window - reserveFloor - softThresh) │
│ ↓ │
│ 4. ¿memoryFlushCompactionCount < compactionCount? │
│ ↓ │
│ YES → Ejecuta silent turn con prompt de flush │
│ ↓ │
│ 5. Agente escribe a memory/YYYY-MM-DD.md │
│ ↓ │
│ 6. Responde "NO_REPLY" (suprimido al usuario) │
│ ↓ │
│ 7. Actualiza memoryFlushAt + memoryFlushCompactionCount │
│ ↓ │
│ 8. Continúa con el turn normal del usuario │
│ │
└─────────────────────────────────────────────────────────────┘
Condiciones para el flush
- memoryFlush.enabled debe ser
true - Workspace debe ser writable (
workspaceAccessno"ro"ni"none") - Tokens cerca del límite:
contextTokens > contextWindow - reserveTokensFloor - softThresholdTokens - No se ha hecho flush en este ciclo:
memoryFlushCompactionCount < compactionCount - Solo sesiones Pi embedded (CLI backends lo saltan)
Defaults del sistema
Prompts default
// User prompt
"Pre-compaction memory flush. Store durable memories now
(use memory/YYYY-MM-DD.md; create memory/ if needed).
If nothing to store, reply with NO_REPLY."
// System prompt append
"Session nearing compaction. Store durable memories now."
4. Campos de Tracking en sessions.json
El archivo ~/.openclaw/agents/main/sessions/sessions.json contiene un objeto por cada sessionKey con los siguientes campos relevantes:
| Campo | Tipo | Descripción |
|---|---|---|
compactionCount |
number | null | Veces que se ha ejecutado auto-compaction |
memoryFlushAt |
timestamp | null | Última vez que se ejecutó el flush |
memoryFlushCompactionCount |
number | null | compactionCount cuando se hizo el último flush |
contextTokens |
number | Estimación de tokens en contexto actual |
Estado actual observado
// Ejemplo de sesión WhatsApp principal
"agent:main:whatsapp:dm:+34690395233": {
"compactionCount": 0,
"memoryFlushAt": null,
"memoryFlushCompactionCount": null
}
// Ejemplo de sesión MS Teams con compaction
"agent:main:msteams:group:19:d2e55d7c...@thread.v2": {
"compactionCount": 2,
"memoryFlushAt": null,
"memoryFlushCompactionCount": null
}
A pesar de que compactionCount: 2 indica que ha habido compaction, memoryFlushAt sigue siendo null. Esto sugiere que el flush no se ejecutó antes de esas compactions, o los campos no se están persistiendo correctamente.
5. Análisis de Evidencia
Evidencia positiva: JSONL transcripts
Encontramos 18 ocurrencias de NO_REPLY en los transcripts JSONL, con el patrón exacto del memory flush:
// Archivo: 0bcee1ba-4e58-41b2-a365-41e3c12840e1.jsonl (Jan 31)
// User prompt (silent injection)
{
"role": "user",
"text": "Pre-compaction memory flush. Store durable memories now
(use memory/YYYY-MM-DD.md; create memory/ if needed).
If nothing to store, reply with NO_REPLY."
}
// Assistant response
{
"role": "assistant",
"thinking": "Good, I've updated the memory file with the current state.
The summary is now persisted. I should reply NO_REPLY since
this was a memory flush request...",
"text": "NO_REPLY"
}
El sistema memoryFlush funcionó correctamente el 31 de enero. El agente recibió el prompt, reflexionó sobre qué guardar, escribió a memory/2026-01-31.md, y respondió NO_REPLY.
Archivos de memoria existentes
| Archivo | Fecha modificación | Tamaño |
|---|---|---|
memory/2026-01-31.md |
Jan 31 10:59 | 1.6 KB |
memory/2026-02-02.md |
Feb 2 17:41 | 2.2 KB |
memory/2026-02-04.md |
Feb 4 17:12 | 0.9 KB |
Hay gaps en Feb 1 y Feb 3. Posiblemente no hubo suficiente actividad para triggear el flush, o las sesiones se resetearon antes de alcanzar el threshold.
6. Estado Actual del Sistema
Configuración de compaction
// ~/.openclaw/openclaw.json (extracto)
{
"agents": {
"defaults": {
"compaction": {
"mode": "safeguard"
}
}
}
}
El modo "safeguard" permite que OpenClaw maneje compaction automáticamente con defaults seguros. No hay override explícito de memoryFlush, por lo que usa los defaults del sistema.
Sesiones activas por uso de contexto
| Sesión | Modelo | Tokens | % Contexto | Status |
|---|---|---|---|---|
| whatsapp:dm:+34690395233 | gpt-5.2 | 181k/400k | 45% | Watch |
| cron:...d3f99a | claude-opus-4-5 | 109k/200k | 54% | Watch |
| agent:main:main | claude-opus-4-5 | 69k/200k | 34% | OK |
| whatsapp:dm:+34667475153 | claude-opus-4-5 | 48k/200k | 24% | OK |
Hooks disponibles
$ openclaw hooks list
Hooks (3/4 ready)
┌───────────┬──────────────────┬────────────────────────────────────────┐
│ Status │ Hook │ Description │
├───────────┼──────────────────┼────────────────────────────────────────┤
│ ✓ ready │ 🚀 boot-md │ Run BOOT.md on gateway startup │
│ ✓ ready │ 📝 command-logger │ Log all command events │
│ ✓ ready │ 💾 session-memory │ Save session context on /new command │
│ ✗ missing │ 😈 soul-evil │ Swap SOUL.md with SOUL_EVIL.md │
└───────────┴──────────────────┴────────────────────────────────────────┘
El hook session_before_compact mencionado en docs ("Pi exposes a hook in the extension API") no aparece en la lista de hooks disponibles. Esto puede significar: (a) está en la extension API de Pi, no en OpenClaw hooks CLI, o (b) no está implementado todavía.
7. ¿Por Qué No Hay Archivos Recientes?
Varias razones explican por qué no vemos actividad de memoryFlush en los últimos días:
Hipótesis 1: Threshold no alcanzado
El flush se dispara cuando:
contextTokens > contextWindow - reserveTokensFloor - softThresholdTokens
Para Claude Opus (200k window):
contextTokens > 200,000 - 20,000 - 4,000 = 176,000 tokens
La sesión más cargada tiene 109k tokens (54%), aún lejos del threshold de ~176k (88%).
Hipótesis 2: Daily session reset
OpenClaw hace reset automático de sesión a las 4:00 AM por defecto. Si las sesiones se resetean antes de alcanzar el threshold, nunca se dispara el flush.
Hipótesis 3: Cambio de modelo mid-conversation
Si una sesión cambia de modelo (ej: claude → gpt-5.2), el context window cambia. Un session con 181k tokens en gpt-5.2 (400k window) está al 45%, muy lejos del threshold.
Hipótesis 4: Session archivos son de sesiones antiguas
Los archivos memory/*.md fueron creados por sesiones que ya no existen (session IDs diferentes). Las sesiones actuales no han alcanzado el threshold todavía.
8. Recomendaciones y Próximos Pasos
Opción A: Ajustar thresholds de memoryFlush
Reducir el threshold para que el flush ocurra más temprano:
// En ~/.openclaw/openclaw.json
{
"agents": {
"defaults": {
"compaction": {
"mode": "safeguard",
"memoryFlush": {
"enabled": true,
"softThresholdTokens": 20000, // Trigger más temprano
"reserveTokensFloor": 30000 // Más margen
}
}
}
}
}
Pro: Flush ocurre más frecuentemente. Con: Más turns silenciosos, más tokens consumidos.
Opción B: Personalizar el prompt de flush
Hacer el prompt más específico para tu workflow:
"memoryFlush": {
"prompt": "Session approaching compaction. Write critical context to memory/YYYY-MM-DD.md:\n- Key decisions made\n- User preferences learned\n- Action items pending\n- Important facts mentioned\nIf nothing critical, reply NO_REPLY.",
"systemPrompt": "You are about to lose context. Preserve anything important."
}
Opción C: Hook en session-memory
El hook session-memory ya existe y se ejecuta en /new. Se podría extender para:
- Ejecutar también en compaction events (si OpenClaw expone el hook)
- Forzar escritura de memoria a intervalos regulares
Opción D: Inyección en before_agent_start
Si no hay hook nativo, se puede inyectar lógica en el system prompt para recordar al agente que escriba a memoria periódicamente:
// En AGENTS.md o system prompt
"Every ~10 turns, proactively write a summary of the conversation
to memory/YYYY-MM-DD.md. Don't wait for compaction."
Opción E: Plugin custom
Crear un plugin de OpenClaw que intercepte eventos de sesión y fuerce flush basado en criterios custom (tiempo, turns, tokens).
Empezar con Opción A (bajar threshold) + Opción B (prompt específico). Es la solución menos invasiva y usa mecanismos ya existentes. Monitorear sessions.json para verificar que memoryFlushAt se actualiza.
9. Checklist de Verificación
Para verificar que memoryFlush está funcionando:
-
Revisar sessions.json
cat ~/.openclaw/agents/main/sessions/sessions.json | \ jq '.[] | select(.memoryFlushAt != null)' -
Buscar NO_REPLY en transcripts recientes
grep -l "NO_REPLY" ~/.openclaw/agents/main/sessions/*.jsonl | \ xargs ls -la -
Monitorear archivos de memoria
watch -n 60 'ls -la /root/kleo/memory/' -
Verificar logs del gateway
grep -i "memory.*flush\|compaction" /tmp/openclaw/openclaw-*.log - Forzar threshold bajo temporalmente para testear que el mecanismo funciona
📄 Versión Markdown
# OpenClaw Compaction & Memory Flush — Informe de Investigación
**Fecha:** 2026-02-04
**Autor:** 498AS Research
**Sistema:** OpenClaw 2026.1.29
---
## Resumen Ejecutivo
Esta investigación analiza el mecanismo de **compaction** y **memory flush** de OpenClaw, su configuración actual, y las discrepancias observadas entre documentación y comportamiento real.
### Key Findings
- ✅ **memoryFlush existe y funciona** — 18 invocaciones con `NO_REPLY` en transcripts JSONL antiguos
- ⚠️ **No hay tracking activo** — Campos `memoryFlushAt` y `memoryFlushCompactionCount` son `null`
- 🔧 **Configuración en safeguard mode** — Compaction usa defaults del sistema
- 📂 **Archivos de memoria existen** — 3 archivos en `memory/` con gaps en días intermedios
---
## 1. Objetivo
Entender y extender el sistema de hooks para ejecutar lógica **before/after compaction**.
Caso de uso: persistir información crítica antes de que el contexto sea compactado.
---
## 2. Documentación vs Realidad
### Documentación dice:
- `memoryFlush.enabled: true` (default)
- Soft threshold: 4000 tokens
- Reserve floor: 20000 tokens
- Silent turn con `NO_REPLY`
### Código confirma:
- Sistema existe en `agent-runner-memory.js`
- Tracking fields en sessions.json
- Prompt injection funciona
### Discrepancias:
| Aspecto | Docs | Realidad |
|---------|------|----------|
| Tracking fields | Se actualizan | Todos `null` |
| Hook before_compact | "Pi exposes it" | No visible en CLI |
| Evidencia ejecución | Expected | 18 ocurrencias ✓ |
---
## 3. Cómo Funciona memoryFlush
### Condiciones para trigger:
1. `memoryFlush.enabled = true`
2. Workspace writable
3. `contextTokens > contextWindow - reserveFloor - softThreshold`
4. `memoryFlushCompactionCount < compactionCount`
5. Sesión Pi embedded (no CLI)
### Defaults:
- reserveTokensFloor: 20,000
- softThresholdTokens: 4,000
- Para 200k window: trigger a ~176k tokens (88%)
---
## 4. Estado Actual
### Sessions activas:
| Sesión | Tokens | % | Status |
|--------|--------|---|--------|
| whatsapp:+34690395233 | 181k/400k | 45% | Watch |
| cron:...d3f99a | 109k/200k | 54% | Watch |
| main | 69k/200k | 34% | OK |
### Hooks disponibles:
- ✓ boot-md
- ✓ command-logger
- ✓ session-memory
- ✗ soul-evil (missing)
- ✗ before_compaction (no existe en CLI)
---
## 5. Por Qué No Hay Actividad Reciente
1. **Threshold no alcanzado** — Sesiones más cargadas están al 54%, threshold es ~88%
2. **Daily reset** — 4:00 AM reset puede ocurrir antes del threshold
3. **Cambio de modelo** — GPT-5.2 tiene 400k window, más difícil alcanzar threshold
---
## 6. Recomendaciones
### Opción A: Bajar thresholds
```json
"memoryFlush": {
"softThresholdTokens": 20000,
"reserveTokensFloor": 30000
}
```
### Opción B: Prompt específico
Personalizar el prompt de flush para tu workflow.
### Opción C: Proactive memory
Instruir al agente a escribir memoria cada ~10 turns.
---
## 7. Verificación
```bash
# Check sessions.json
jq '.[] | select(.memoryFlushAt != null)' sessions.json
# Buscar NO_REPLY
grep -l "NO_REPLY" *.jsonl
# Monitor memory files
watch ls -la /root/kleo/memory/
```
---
*Generado por OpenClaw Research Pipeline*