en este artículo
- ¿Por qué mi agente de IA se olvida de todo entre sesiones (y entre máquinas)?
- ¿Qué es Hindsight y por qué correrlo self-hosted?
- ¿Hindsight o mem0? Cuál elegí y con qué criterio
- Deploy de Hindsight paso a paso con Docker
- ¿Cómo lo corro 100% local sin API keys, con Ollama?
- ¿Cómo conecto Hindsight a Claude Code?
- ¿Cómo le doy memoria persistente a Hermes (un agente 24/7)?
- ¿Cómo lo conecto a OpenClaw y comparto memoria entre agentes?
- ¿Y si uso OpenCode, Kimi o MiniMax? Conecta cualquier agente por MCP
- Cómo estructurar tus memory banks (el error que cometí y cómo lo arreglé)
- Conceptos: las 4 capas de memoria y las 3 operaciones
- La parte crítica: memoria durable vs. datos volátiles
¿Por qué mi agente de IA se olvida de todo entre sesiones (y entre máquinas)?
Respuesta corta: un agente de IA no tiene memoria, tiene ventana de contexto. Cuando la sesión termina, ese contexto se borra y la próxima corrida arranca de cero. La memoria persistente para agentes de IA es una capa aparte que guarda hechos durante una sesión y los recupera en la siguiente. No es magia del modelo: es un servicio que vive fuera del modelo.
Si operas con agentes de IA de verdad, ya chocaste con esto. Y duele en dos dimensiones distintas:
- Entre SESIONES. Cierras Claude Code hoy, mañana lo abres y repite las mismas preguntas que ya respondiste ayer. Le explicas otra vez tu stack, tus decisiones, tus preferencias. Cada mañana, tabula rasa.
- Entre MÁQUINAS. Tu
CLAUDE.mdy tus markdown viven en un repo local, en tu Mac. Pero tu agente 24/7 corre en otro server. Ese agente no ve tu markdown, y aunque lo viera, no razona sobre lo que fuiste guardando en otro lado. La memoria de una máquina no cruza a la otra.
La pregunta obvia: “¿y para qué está el CLAUDE.md, la auto-memory, los markdown?”. Sirven, pero no resuelven esto solos. Son estáticos: se cargan enteros en cada sesión, no recuperan lo relevante para lo que estás haciendo ahora. No deduplican, no consolidan, no se dan cuenta de que dijiste lo mismo de tres formas distintas. Y no se comparten con un agente que corre en otra máquina. Son una fuente de verdad excelente para lo que decidiste a propósito escribir. No son memoria.
🤖 ¿Quieres construir tu propio agente de IA?
En el AI Agents Starter Kit pasas del concepto a un agente de ventas funcionando en WhatsApp — camino no-code (Make) o técnico (n8n).
Ver el cursoEsto no es teoría de blog. Tengo un agente —Hermes, al que llamo Nyx— corriendo 24/7 en un DGX Spark, más Claude Code en mi Mac, más un histórico en OpenClaw. Tres agentes, tres contextos, cero memoria compartida entre ellos. Ese fue el dolor concreto que me llevó a montar esto.
Qué vas a tener al terminar esta guía: un motor de memoria self-hosted, 100% local si quieres, corriendo en un contenedor Docker, conectado a Claude Code, a Hermes y a OpenClaw, con la data sin salir nunca de tu máquina.
- Contenedor Hindsight corriendo con persistencia real
- API cerrada (no abierta al mundo)
- Embeddings multilingües fijados antes del primer dato
- Claude Code, Hermes y OpenClaw apuntando al mismo server
- Memoria compartida entre agentes, con un bank
personalpara lo personal y banks aparte solo por otro dueño o confidencialidad
¿Qué es Hindsight y por qué correrlo self-hosted?
Hindsight es un motor de memoria de largo plazo para agentes. Extrae hechos de las conversaciones, los consolida en un grafo temporal y los recupera cuando el agente los necesita. Es, literalmente, la capa que le falta al agente entre una sesión y la otra.
Lo desarrolla Vectorize (github.com/vectorize-io/hindsight, MIT, respaldado por el paper LongMemEval). Lo elegí sobre mem0, Zep y Honcho por una razón muy concreta: es el único con integración de primera clase en ambos lados que me importaban —Claude Code y Hermes— sin escribir pegamento propio. Ese detalle, para alguien que opera solo, decide.
Por qué self-hosted (el diferenciador):
- La data no sale de tu máquina. Todo lo que tu agente aprende de ti se queda en tu red.
- Sin API keys de un SaaS de memoria, sin cuota mensual, sin un tercero que un día cambia precios o cierra.
- Control total y kill switch: apagas el contenedor y se acabó.
El cloud, eso sí, te ahorra operar el contenedor. Si no quieres mantener un Docker vivo, la versión hospedada existe y es legítima. Yo prefiero operar el contenedor a mandar mi contexto a un tercero. Es una decisión, no una verdad universal.
Es aditivo y reversible. Este es el punto que más tranquilidad me dio: Hindsight es una capa EXTRA sobre tus markdown y tu CLAUDE.md, que siguen siendo la fuente primaria. No reemplazas nada. Y apagar el contenedor es un kill limpio: tus archivos siguen intactos, no pierdes tu fuente de verdad.
Anatomía del deployment, para que te ubiques antes de desplegar:
- API en
:8888— el endpoint con el que hablan los plugins. - Control Plane en
:9999— un dashboard web para navegar tus banks a ojo. - Endpoint MCP en
/mcp/{bank_id}/— para consumir la memoria como herramienta MCP.
Un aviso desde ya: por defecto la API viene ABIERTA. La cerramos en el deploy. No te saltes esa parte.
¿Hindsight o mem0? Cuál elegí y con qué criterio
En una frase: mem0 gana si quieres recall simple y arrancar en cinco minutos; Hindsight gana si quieres grafo temporal, consolidación automática, mental models y self-hosted de verdad.
Esta comparación en español casi solo la encuentras en páginas de un vendor o del otro. Va la mía, de founder que probó ambos:
| Criterio | Hindsight | mem0 |
|---|---|---|
| Tokens por retrieval | Más pesado (~27K, orden de magnitud) | Más liviano (~7K, orden de magnitud) |
| Grafo temporal + recency | Sí, nativo | Limitado |
| Capa Reflect / mental models | Sí | No |
| Consolidación / dedup automática | Sí, tras cada retain | Básica |
| Curva de operación | Más alta (operas un contenedor) | Más baja |
| Dónde vive la data | Tu máquina (self-hosted real) | Cloud por defecto |
Trata esos números de tokens como orden de magnitud, no como cifra de laboratorio: Hindsight te devuelve más contexto sintetizado, mem0 te devuelve menos y más directo. Ninguno es “mejor” en abstracto; pagan cosas distintas.
Cuándo mem0 basta (honestidad): si necesitas recall simple, no te importa el grafo ni la reflexión, y quieres estar corriendo hoy. mem0 es una decisión perfectamente sana ahí.
Cuándo Hindsight vale el peso extra: cuando quieres consolidación y dedup automáticas, mental models curados, memoria compartida entre varios agentes, y self-hosted de verdad con la data en tu red.
La tercera vía, para no caer en un falso dilema: puede que no necesites ninguno de los dos. El built-in de Claude Code —CLAUDE.md + auto-memory + /memory— y plugins tipo claude-mem cubren el caso liviano sin ningún motor externo. Si tu agente vive en una sola máquina y tu CLAUDE.md te alcanza, no montes infra por montarla.
Mi elección: Hindsight, self-hosted. No por las features en abstracto, sino porque mi caso es multi-agente y multi-máquina —Claude Code en la Mac, Hermes 24/7 en el Spark— y porque no quiero que el contexto de mi negocio viva en el server de un tercero. Ese es exactamente el caso donde el peso extra de Hindsight se paga solo.
Deploy de Hindsight paso a paso con Docker
Esta es la parte núcleo. Pasos reproducibles, en orden.
1. Requisitos previos
- Docker (yo lo desplegué con Coolify sobre un VPS, como imagen custom — no está en el catálogo one-click, pero es un
docker runnormal). - El stack local al que vas a apuntar si vas 100% local: Ollama sirviendo modelos + un gateway LiteLLM en
:4000. Si vas a usar un cloud barato para la extracción, no necesitas esto todavía.
2. Levantar el contenedor
Nada de latest. Pinea el tag. Y el volumen va en /home/hindsight/.pg0, no en /data (Hindsight trae un Postgres embebido, pg0, que persiste ahí — más sobre esto en los gotchas).
docker run -d --name hindsight \
-p 8888:8888 -p 9999:9999 \
-v hindsight-data:/home/hindsight/.pg0 \
ghcr.io/vectorize-io/hindsight:0.8.4
Existe una variante -slim de la imagen (ghcr.io/vectorize-io/hindsight:0.8.4-slim) si quieres una huella menor. Usa el named volume (hindsight-data): es lo canónico y te evita el gotcha de permisos que explico abajo.
Este comando es el mínimo para ver el contenedor vivo, pero le faltan las variables de los pasos 3-5 (auth, LLM, embeddings). No lo dejes así: en el paso 6 va el comando completo, que es el que corres de verdad. Si arrancas con este “pelado” y agregas variables después, ya levantaste la API abierta y con embeddings en inglés.
3. Cerrar la API (viene abierta)
Este paso no es opcional. Por defecto cualquiera que alcance el :8888 puede hablarle. Se cierra con la extensión de tenant. Estas dos variables son las que cierran la puerta, y son las 100% confirmadas:
-e HINDSIGHT_API_TENANT_EXTENSION=hindsight_api.extensions.builtin.tenant:ApiKeyTenantExtension \
-e HINDSIGHT_API_TENANT_API_KEY=<tu-tenant-key>
Esa tenant key es la misma que después vas a pegar en cada plugin (Claude Code, Hermes, OpenClaw). Guárdala bien.
4. Apuntar el LLM de extracción
Hindsight usa un LLM para leer el texto crudo y extraer hechos atómicos. Por defecto el server apunta a openai/gpt-5-mini. Yo lo apunté a OpenRouter con deepseek porque me sale centavos al mes:
-e HINDSIGHT_API_LLM_PROVIDER=openrouter \
-e HINDSIGHT_API_LLM_API_KEY=<tu-openrouter-key> \
-e HINDSIGHT_API_LLM_MODEL=deepseek/deepseek-v4-flash
Con deepseek-v4-flash hablamos de ~$0.09 / $0.18 por millón de tokens de entrada/salida. Para el volumen de extracción de un agente personal, son centavos al mes. Un aviso: verifica el slug exacto del modelo (y su precio) en la lista viva de modelos de OpenRouter antes de fijarlo. Si el nombre no existe tal cual lo escribiste, el retain devuelve error y la extracción no guarda nada. En silencio, sin romper el contenedor.
Dos cosas útiles: existe HINDSIGHT_API_LLM_BASE_URL por si tu provider necesita una URL propia (clave para el modo 100% local, ver la sección siguiente), y hay overrides por operación si quieres un modelo distinto para extraer que para reflexionar: HINDSIGHT_API_RETAIN_LLM_*, HINDSIGHT_API_REFLECT_LLM_*, HINDSIGHT_API_CONSOLIDATION_LLM_*.
5. Fijar embeddings multilingües ANTES del primer retain
Este es el gotcha #1 y lo detallo abajo, pero va aquí porque el orden importa: fija el embedding multilingüe antes de meter el primer dato. Si lo cambias después, ya guardaste vectores en inglés y el recall en español ya arrancó degradado.
-e HINDSIGHT_API_EMBEDDINGS_PROVIDER=local \
-e HINDSIGHT_API_EMBEDDINGS_LOCAL_MODEL=BAAI/bge-m3
bge-m3 es la recomendación: 100+ idiomas, buen recall multilingüe, y sin prefijos (los modelos E5 exigen prefijos query:/passage: y si el provider no los aplica pierdes calidad en silencio). Yo arranqué con intfloat/multilingual-e5-small por liviano, pero si estás empezando de cero, ve directo a bge-m3 y te ahorras el riesgo.
6. Todo junto (el comando completo)
Los pasos 2-5 los separé para explicarlos uno por uno. En la práctica va todo en un solo docker run, porque las variables de tenant, LLM y embeddings tienen que estar desde el arranque. Este es el comando que corres de verdad:
docker run -d --name hindsight \
-p 8888:8888 -p 9999:9999 \
-v hindsight-data:/home/hindsight/.pg0 \
-e HINDSIGHT_API_TENANT_EXTENSION=hindsight_api.extensions.builtin.tenant:ApiKeyTenantExtension \
-e HINDSIGHT_API_TENANT_API_KEY=<tu-tenant-key> \
-e HINDSIGHT_API_LLM_PROVIDER=openrouter \
-e HINDSIGHT_API_LLM_API_KEY=<tu-openrouter-key> \
-e HINDSIGHT_API_LLM_MODEL=deepseek/deepseek-v4-flash \
-e HINDSIGHT_API_EMBEDDINGS_PROVIDER=local \
-e HINDSIGHT_API_EMBEDDINGS_LOCAL_MODEL=BAAI/bge-m3 \
ghcr.io/vectorize-io/hindsight:0.8.4
En Coolify es exactamente lo mismo, solo que las -e van cargadas como Environment Variables del servicio, no en la línea de comando.
7. Verificar
Abre el Control Plane en :9999, entra y navega el bank vacío. Health check visual: si el dashboard carga y ves el bank, el server está vivo. Un curl al :8888 con tu tenant key confirma que la auth quedó activa (sin key debería rechazarte).
Ojo con otros dos grupos de variables. El par tenant extension + tenant api key de arriba lo doy como exacto y verificado. Pero dos grupos más los tienes que re-verificar contra tu propia instancia, porque las páginas de docs no coinciden del todo entre sí:
- Auth del MCP: los docs muestran
HINDSIGHT_API_MCP_ENABLED(defaulttrue, MCP servido en/mcp/{bank_id}/). El MCP se asegura con su propio token,HINDSIGHT_API_MCP_AUTH_TOKEN(distinto de laHINDSIGHT_API_TENANT_API_KEYdel REST) — es el Bearer que después pegas en OpenCode/Kimi. - Dataplane key del Control Plane: la página de install muestra
HINDSIGHT_CP_DATAPLANE_API_URL+HINDSIGHT_CP_ACCESS_KEY. Los nombres exactos pueden diferir de una versión a otra.
No los tomes como dogma. Toma como dogma el par que cierra la API.
¿Cómo lo corro 100% local sin API keys, con Ollama?
Respuesta directa: apuntas tanto la extracción de hechos como los embeddings a modelos locales servidos por tu gateway LiteLLM (:4000) / Ollama. Ninguna llamada sale de tu red. Cero keys externas.
La extracción, en vez de OpenRouter, va contra tu gateway local. LiteLLM expone una API compatible con OpenAI, así que usas el provider openai apuntando el BASE_URL a tu gateway:
-e HINDSIGHT_API_LLM_PROVIDER=openai \
-e HINDSIGHT_API_LLM_BASE_URL=http://<tu-gateway>:4000/v1 \
-e HINDSIGHT_API_LLM_API_KEY=<key-dummy-del-gateway> \
-e HINDSIGHT_API_LLM_MODEL=deepseek-local
Ojo con la última línea: deepseek-local es un placeholder — tiene que ser exactamente el model_name que definiste en tu config de LiteLLM. Si no coincide, el gateway responde model-not-found y el retain falla en silencio, igual que con un slug malo de OpenRouter.
Los embeddings ya los tienes locales del deploy —bge-m3 vía el provider local—, así que ese lado ya no toca la red:
-e HINDSIGHT_API_EMBEDDINGS_PROVIDER=local \
-e HINDSIGHT_API_EMBEDDINGS_LOCAL_MODEL=BAAI/bge-m3
Con eso, la extracción y los embeddings viven en tu máquina. No hay API key de nadie.
El trade-off real: un modelo local extrae hechos con menos precisión y más latencia que gpt-5-mini o un deepseek por OpenRouter. Para 100% privado vale la pena. Pero si lo que te importa es la máxima calidad de extracción, la jugada realista es mezclar: extracción en un cloud barato (OpenRouter deepseek, centavos al mes) y todo lo demás —embeddings, storage, recall— local. Eso es exactamente lo que corro yo. No te voy a decir que “local es igual de bueno”, porque no lo es en extracción; te digo dónde el trade-off se paga y dónde no.
“Sin API keys, sin que la data salga de tu máquina”: ese es el motivo por el que un founder monta esto en vez de pagar un SaaS de memoria. Si eso no te importa, paga el cloud y sigue con tu vida. Si te importa, este es el camino.
¿Cómo conecto Hindsight a Claude Code?
Integración uno. Verificada, corriendo en mi Mac.
Instalación. Ojo con los nombres: el marketplace se llama vectorize-io/hindsight, pero el plugin se llama hindsight-memory. Son distintos:
claude plugin marketplace add vectorize-io/hindsight
claude plugin install hindsight-memory
Configuración en ~/.hindsight/claude-code.json. Apuntas la URL a tu server :8888 y el token es la tenant key del server:
{
"hindsightApiUrl": "http://tu-servidor:8888",
"hindsightApiToken": "tu-tenant-key",
"bankId": "personal",
"directoryBankMap": {
"/Users/tu-usuario/Playground/flip-legal": "flip",
"/Users/tu-usuario/Playground/semillita": "semillita"
},
"recallAdditionalBanks": ["personal"]
}
Esas cinco keys son todas reales. directoryBankMap mapea cada directorio a un bank aislado (un cerebro aparte, y solo para lo que tiene otro dueño o una frontera de confidencialidad); recallAdditionalBanks habilita recall cruzado —por ejemplo, que tu bank personal personal (identidad + CAR + ecosistema) siga disponible aunque estés trabajando dentro de un bank aparte como flip— y admite recallAdditionalBankFilters para filtrar por tag en cada bank listado.
Defaults relevantes que heredas sin escribirlos (el schema es más rico que esas cinco keys): recallTypes ['observation'], recallBudget 'mid', recallMaxTokens 1024, autoRecall/autoRetain en true, retainMode 'full-session', retainEveryNTurns 10, enableKnowledgeTools true (guárdate este: en OpenClaw viene en false), dynamicBankId false, dynamicBankGranularity ['agent','project']. El orden de carga es: defaults → settings.json → tu user config → variables de entorno. Todo es overrideable por env (HINDSIGHT_API_URL, HINDSIGHT_BANK_ID, etc.).
Los 4 hooks (confirmados, y se registran cuando arranca claude, no en una sesión ya abierta — si acabas de instalar, reinicia):
- SessionStart — health check de conectividad contra tu server.
- UserPromptSubmit — auto-recall: recupera lo relevante y lo inyecta como
additionalContext. - Stop — auto-retain: hace un POST asíncrono del transcript para extraer hechos.
- SessionEnd — retain final del transcript y para el daemon si el plugin lo auto-arrancó.
Aislamiento de banks, tres formas:
- Estático:
dynamicBankId=false+ unbankIdfijo. - Dinámico:
dynamicBankId=true+dynamicBankGranularity(ej.['agent','project']→ genera banks tipo<agent>::<project>). - Explícito:
directoryBankMap, directorio por directorio.
Gotcha importante: si dejas hindsightApiUrl vacío, el plugin levanta un daemon local hindsight-embed que exige una LLM key exportada en el entorno. Para self-hosted eso no es lo que quieres: siempre llena la URL apuntando a tu :8888.
¿Cómo le doy memoria persistente a Hermes (un agente 24/7)?
Integración dos. Esta es la que me importaba de verdad: Hermes (que corre como Nyx) vive 24/7 en mi DGX Spark. Es MI agente, no un hello-world.
Setup. Cuidado con el comando, porque en varios lados se cita mal: es hermes memory setup —un wizard— y ahí eliges hindsight de una lista. No es hermes memory setup hindsight como un solo token. La alternativa manual, sin wizard:
hermes config set memory.provider hindsight
El plugin de Hindsight es nativo: ya viene con Hermes, no lo instalas aparte.
Configuración en ~/.hermes/hindsight/config.json. Para self-hosted, modo local_external:
{
"mode": "local_external",
"api_url": "http://tu-servidor:8888",
"api_key": "tu-tenant-key",
"bank_id": "personal",
"recall_types": ["observation", "world", "experience"]
}
Los tres modos son cloud (default), local_embedded y local_external. Para apuntar a tu server, local_external.
Corrección crítica —y esta rompe un mito cómodo. Es fácil asumir que “la memoria built-in de Hermes no se toca, es aditiva sin fricción”. No es tan limpio. El memory_mode por defecto es hybrid, o sea built-in Y Hindsight activas a la vez. Y los docs advierten, literal, que con ambas activas el LLM puede preferir la built-in. Es decir: puedes tener Hindsight conectado y perfecto, y el modelo seguir tirando de la memoria interna sin leer bien la tuya.
Para que Hindsight sea la fuente clara, hay que decidirlo explícito, no dejarlo al default:
hermes tools disable memory
O ajustas memory_mode. Pero decídelo tú. “Lo dejé en hybrid y asumí que funcionaba” es cómo terminas con un agente que ignora la memoria que montaste.
Gotcha: recall_types viene acotado a observation por defecto. Si no lo amplías (como en el JSON de arriba, a world y experience), no vas a ver las otras capas de memoria en el recall.
Nota de fuente: el modo local_external y estos nombres los confirma el README del plugin en el repo NousResearch/hermes-agent (plugins/memory/hindsight). La página alojada en vectorize.io está simplificada y desactualizada a “cloud/local” — si hay conflicto, gana el README del repo.
¿Cómo lo conecto a OpenClaw y comparto memoria entre agentes?
Integración tres, y con ella lo que de verdad quería: memoria compartida multi-agente.
Instalación:
openclaw plugins install @vectorize-io/hindsight-openclaw
Wizard de setup:
npx --package @vectorize-io/hindsight-openclaw hindsight-openclaw-setup
Con flags no-interactivos si automatizas: --mode cloud|api|embedded, --token hsk_..., --provider openai, --api-key-env OPENAI_API_KEY, --api-url https://....
Configuración en ~/.openclaw/openclaw.json — y aquí está el gotcha que te ahorra media hora: no es flat. La config vive anidada dentro de plugins.entries.hindsight-openclaw.config:
{
"plugins": {
"entries": {
"hindsight-openclaw": {
"config": {
"hindsightApiUrl": "http://tu-servidor:8888",
"hindsightApiToken": "tu-tenant-key"
}
}
}
}
}
Tres modos del wizard:
- Cloud —
api.hindsight.vectorize.io+ token. - External API — tu deployment (
hindsightApiUrl+hindsightApiToken); desactiva el daemon local. Este es el que quieres para self-hosted. - Embedded — levanta un
hindsight-embedlocal; pidellmProvider(openai/anthropic/gemini/groq/ollama/claude-code/openai-codex) +llmApiKey.
La clave para la tesis multi-agente. En OpenClaw, dynamicBankId viene en true por defecto → cada agente/canal/usuario tiene su propio bank. Por defecto, tus agentes son extraños entre sí: cada uno con su cerebro, sin compartir nada.
Para que compartan memoria hay dos caminos, combinables:
- Modo External API con todos apuntando al mismo server.
dynamicBankId=false+ unbankIdcomún.
Así, lo que aprende un agente lo lee el otro. Eso es lo que hace que Hindsight sea infra de memoria compartida y no tres cerebros aislados.
Bonus verificado (resiliencia): en modo external, si tu API se cae, el plugin encola los retain en un JSONL local y los reproduce al reconectar. No pierdes lo aprendido durante la caída. Para un agente 24/7 esto no es un detalle, es la diferencia entre confiar en el sistema o no.
Contraste que conviene recordar: enableKnowledgeTools viene en false en OpenClaw (en Claude Code es true). Si esperas las mismas herramientas de knowledge en ambos, no las vas a tener por defecto.
¿Y si uso OpenCode, Kimi o MiniMax? Conecta cualquier agente por MCP
Hasta acá cubrí los tres agentes con plugin propio. Pero yo no vivo solo en esos: también uso OpenCode y Kimi, y quería la misma memoria en todos. La buena noticia: Hindsight expone un endpoint MCP por bank, así que cualquier agente que hable MCP remoto se conecta a los mismos banks. La memoria no está atada a Claude Code.
El endpoint es https://tu-servidor/mcp/{bank}/ con Authorization: Bearer TU_MCP_TOKEN (el token que pusiste en HINDSIGHT_API_MCP_AUTH_TOKEN, distinto del tenant token del REST). El bank va en la URL.
OpenCode — MCP remoto nativo. En opencode.json:
{
"mcp": {
"hindsight": {
"type": "remote",
"url": "https://tu-servidor/mcp/personal/",
"oauth": false,
"headers": { "Authorization": "Bearer {env:HINDSIGHT_MCP_TOKEN}" },
"enabled": true
}
}
}
Kimi CLI / Kimi Code (Moonshot) — MCP remoto nativo, y usa el mismo formato mcpServers que Claude Code, así que migrar es trivial:
kimi mcp add --transport http hindsight \
https://tu-servidor/mcp/personal/ \
--header "Authorization: Bearer TU_MCP_TOKEN"
MiniMax — ojo acá: su CLI oficial (mmx-cli) no es cliente MCP, es un wrapper de sus APIs generativas. Si quieres usar su modelo (M2/M2.5) con memoria, corre el modelo dentro de OpenCode/Kimi/Claude Code apuntando el base_url a MiniMax, y deja que ese harness hable con Hindsight. No instalas la memoria “en MiniMax”; instalas MiniMax dentro de un harness que ya la tiene.
Dos niveles de integración:
- Automático (hooks) — Claude Code, Hermes y OpenClaw tienen plugin propio: recuerdan y guardan solos, sin que el modelo lo pida.
- Como herramientas (MCP) — OpenCode y Kimi ven
retain/recall/searchcomo herramientas MCP y las invocan. Escriben a los mismos banks; la diferencia es que el recall no es 100% de fondo (aunque ambos tienen hooks para automatizarlo).
Si un agente tropieza con el transporte streamable-HTTP, el fallback universal es un bridge local: npx mcp-remote <url> --header "Authorization: Bearer ...".
Cómo estructurar tus memory banks (el error que cometí y cómo lo arreglé)
Esta parte no la vas a encontrar en la doc de ningún vendor, porque solo se aprende operándolo. Y es donde metí la pata primero, así que te ahorro el rodeo.
Un memory bank es un namespace: un grafo aislado, un “cerebro aparte”. Lo importante que casi nadie dice: Hindsight construye las relaciones entre hechos SOLO dentro de un bank. El cross-recall te deja leer de varios banks a la vez (recallAdditionalBanks), pero no crea links entre grafos. Si dos cosas están en banks distintos, Hindsight nunca las va a relacionar sola.
Ese detalle define toda tu estructura. Mi primer instinto fue separar por proyecto: un bank para CAR (mi comunidad), otro para Ecosistema Startup (mi medio), otro para mi identidad. Se sentía ordenado. Era un error. CAR y Ecosistema son el mismo ecosistema —uno alimenta al otro, se referencian todo el tiempo— y al separarlos, maté justo la relación que más quería: que al preguntar por “rentabilizar Ecosistema” el agente lo conectara con lo que enseño en CAR. Los había puesto en cerebros distintos que nunca se iban a hablar.
La regla correcta, la que uso ahora: todo lo que comparte dueño + dominio + confianza va al MISMO bank. Un bank nuevo solo cuando hay (1) otro dueño/decisor, (2) una frontera de confidencialidad, o (3) un dominio que no comparte contexto útil con lo demás.
Aplicado a mí quedó así:
personal(mi bank por defecto) — mi identidad + CAR + Ecosistema Startup. Todo mi ecosistema personal en UN grafo, para que se relacione solo. Cualquier cosa nueva cae acá salvo que diga lo contrario.flip— Flip Legal, mi firma con un socio. Bank aparte por confidencialidad (no es solo mío).semillita— el negocio de mi señora. Bank aparte porque es de otra dueña.casa— un tema legal de mi casa. Bank aparte porque es otro dominio sin relación con lo demás.
Fíjate en el criterio: entre CAR y una cláusula legal de Flip no hay links que perder —no se relacionan— y sí hay una frontera de confianza. Así que separar no cuesta nada y protege. Entre CAR y Ecosistema es al revés: mil links, cero frontera. Ahí juntar es la ganancia.
Cross-recall para lo transversal. Configuré que mi identidad (voz, preferencias, quién soy) se lea desde cualquier bank con recallAdditionalBanks. Así, aunque esté trabajando en el bank de Flip, el agente igual sabe que escribo en español neutro. Lo transversal se comparte por lectura; lo específico de cada dominio no se filtra.
La regla en una frase: mismo bank si comparte dueño, dominio y confianza; bank nuevo si rompe alguno de los tres.
Conceptos: las 4 capas de memoria y las 3 operaciones
Las 4 capas de memoria. Aquí corrijo un modelo mental simplista que yo mismo tenía al empezar (creía que eran “3 tipos de hecho planos”). No lo son. Son 2 hechos crudos + 2 capas derivadas, una jerarquía:
- World facts — hechos sobre el mundo, crudos.
- Experience facts — experiencias propias del agente, crudas.
- Observations — creencias consolidadas y deduplicadas construidas a partir de múltiples hechos, con fuentes, quotes y proof-count. No es un hecho crudo: es la capa sintetizada. Es lo que el agente “cree” tras juntar evidencia.
- Mental Models — resúmenes curados (por la operación reflect o por un humano). Es la capa de máxima prioridad en retrieval.
recall_types elige qué capas te devuelve el recall. El default está acotado a observation — por eso el gotcha de ampliarlo si quieres ver el resto.
Las 3 operaciones core:
- retain — ingesta. Le pasas texto crudo, el LLM extrae hechos atómicos y consolida/deduplica automáticamente tras cada retain.
- recall — recupera lo relevante.
- reflect — razona sobre lo acumulado y forma mental models. (Esta se me pasó en el setup inicial; vale la pena tenerla presente, es la que sube información cruda a modelo mental curado.)
Retrieval = TEMPR, cuatro vías combinadas:
- Semántico (vector) — significado, no palabras exactas.
- Keyword (BM25) — coincidencia literal.
- Grafo (entidades enlazadas) — relaciones.
- Temporal (recency) — qué tan reciente.
El recall multilingüe lo da la vía semántica. Es la razón por la que una query como “dialecto de castellano” recupera un hecho guardado como “español neutro”: no comparten palabras, comparten significado. Lo probé y funciona. Pero solo funciona si tu embedding es multilingüe — que es justo el próximo tema.
La parte crítica: memoria durable vs. datos volátiles
Acá se decide si tu setup te ayuda o te miente con cara de certeza.
Respuesta directa: no todo va a memoria. Los datos que cambian a diario —métricas vivas— no se confían a la memoria del agente. Nunca.
La regla, sin ambigüedad:
- DURABLE → sí va a memoria. Decisiones, hechos estables, preferencias, patrones, políticas. “Siempre escribo en español neutro.” “Elegí Hindsight self-hosted porque no quiero mandar mi contexto a un tercero.” “La audiencia es LATAM + España.” Eso no cambia mañana; guárdalo.
- VOLÁTIL → NO va a memoria. MRR, número de miembros, ranking, cifras que rotan. Eso vive en la fuente viva —tu tracker, tu base de datos— y se consulta ahí, en el momento.
Por qué importa tanto. Si metes una métrica volátil a memoria, el agente la va a citar desactualizada, con total confianza, dentro de un mes. “Tu MRR es X” —cuando X es de hace seis semanas. La memoria es buenísima para guardar el patrón y la decisión; es pésima para guardar el número del día. Guarda “el MRR se mide en el tracker canónico”, no el valor del MRR.
Respaldo técnico. El recency decay de Hindsight es real y configurable: HINDSIGHT_API_RECENCY_DECAY_FUNCTION=linear con una ventana de 365 días. Puedes hacer que lo viejo pese menos en el retrieval. Ayuda, pero no reemplaza la regla: un dato vivo va a la fuente viva, punto. El decay atenúa, no arregla el problema de fondo.
Cómo operarlo en la práctica:
- Mapea qué capas y qué
recall_typesusas para lo durable. - Define deliberadamente qué NO ingieres. No ingerir es una decisión activa, no un olvido.
- Apóyate en la consolidación/dedup automática tras cada retain — que trae un check enfocado que preserva números, negaciones y entidades para no colapsar diferencias reales (no fusiona “$100” con “$1.000” ni “sí” con “no” como si fueran lo mismo).
Casi ninguna página de vendor te cuenta esto, porque no vende. Pero es lo que evita que tu agente te mienta con cara de certeza.
Gotchas reales que me costaron (y cómo evitarlos)
Esto me pasó, o te va a pasar. Lista para escanear rápido.
1. Embeddings en inglés que degradan el español EN SILENCIO. El default es BAAI/bge-small-en-v1.5 — solo inglés. Con eso, tu recall en español se degrada sin un solo error en logs. Nada te avisa. Fija un modelo multilingüe ANTES del primer retain. Recomendados en orden:
BAAI/bge-m3— mejor overall, 100+ idiomas, sin prefijos. Ve por este.intfloat/multilingual-e5-large— bueno, pero requiere prefijosquery:/passage:(HINDSIGHT_API_EMBEDDINGS_ONNX_QUERY_PREFIX/PASSAGE_PREFIX). Si el providerlocalno los aplica, pierdes calidad en silencio.paraphrase-multilingual-MiniLM-L12-v2— opción liviana decente.intfloat/multilingual-e5-small— el más liviano, pero el de menor calidad de los multilingües, y también exige prefijos. Yo arranqué con este; si empiezas de cero, sube abge-m3.
El punto: bge-m3 elimina el riesgo de los prefijos. No te la juegues.
2. Persistencia de Docker en el path equivocado. Los datos viven en /home/hindsight/.pg0, NO en /data. Si montas el volumen en /data, no persiste nada — reinicias el contenedor y perdiste todo. Usa un named volume. Si insistes en un bind mount, el directorio tiene que ser escribible por el UID 1000 o el Postgres embebido (pg0) falla con Permission denied. Y pinea el tag (0.8.4), no latest.
3. Hermes en hybrid prefiriendo la built-in. El default es memoria built-in Y Hindsight activas, y el LLM puede tirar de la interna e ignorar la tuya. Decídelo explícito: hermes tools disable memory o ajusta memory_mode.
4. Config de OpenClaw anidada + banks aislados por defecto. La config no es flat, vive en plugins.entries.hindsight-openclaw.config. Y dynamicBankId viene en true → por defecto cada agente tiene su propio bank y no comparten memoria. Para compartir: External API al mismo server y/o dynamicBankId=false + bankId común.
5. recall_types acotado a observation. Por defecto en Hermes y Claude Code solo devuelve observations. No verás world, experience ni mental models si no lo amplías.
6. API abierta por defecto. Ya lo dije y lo repito porque es el que más duele: ciérrala con HINDSIGHT_API_TENANT_EXTENSION + HINDSIGHT_API_TENANT_API_KEY. No dejes tu memoria abierta al mundo.
7. Variables a re-verificar en tu instancia. Las de auth del MCP y las de dataplane del Control Plane pueden diferir de lo que viste en otro doc (los docs no coinciden entre versiones). Verifícalas contra tu deployment. Lo único que doy como cerrado y exacto es el par tenant extension + tenant api key.
8. Slug del modelo de extracción mal escrito. Si HINDSIGHT_API_LLM_MODEL no coincide con un modelo real (el slug de OpenRouter, o el model_name de tu LiteLLM en modo local), el retain devuelve error y la extracción no guarda nada —sin romper el contenedor, así que no te enteras hasta que el recall viene vacío—. Verifica el nombre exacto antes de fijarlo.
Cierre: por qué lo comparto (build in public)
Monté esto de verdad. No es un hello-world para un post: es memoria persistente compartida entre tres tipos de agente —Claude Code en mi Mac, Hermes/Nyx 24/7 en un DGX Spark, y el histórico en OpenClaw— con Hindsight self-hosted, un bank personal que junta identidad + CAR + ecosistema startup, con banks aparte solo donde cambia el dueño o la confidencialidad (Flip Legal) y un costo marginal de prácticamente $0 al mes. Lo comparto entero porque en español esta guía hands-on self-hosted no existía. Las landings de vendor te venden la versión cloud; nadie te cuenta los gotchas de operarlo tú.
Y no te voy a vender que quedó perfecto. Lo que sigo afinando: la extracción local es más floja que la de un cloud —por eso hoy mezclo, extracción en OpenRouter y todo lo demás local—; la calidad de recall depende fuerte del embedding que elijas; y sí, operar el contenedor es trabajo que el cloud te ahorraría. Son trade-offs reales, no defectos que esconder.
Y para no afirmar de más: el plugin de Claude Code y el de OpenClaw comparten casi toda la config —apiPort 9077, el daemon hindsight-embed, dynamicBankGranularity, recallTypes—, lo que apunta claramente a mismo linaje y base de código compartida. La dirección exacta del port (quién portó a quién) no la tengo confirmada, así que la dejo como observación, no como hecho.
Si estás montando tu propio agente con memoria, por aquí seguimos documentando lo que funciona y lo que se rompe. Nos leemos.
Preguntas frecuentes
¿Necesito API keys de un SaaS para tener memoria persistente?
No. En modo local puedes correr la extracción y los embeddings con Ollama/LiteLLM en tu red, sin ninguna key externa. El único cloud opcional es un LLM barato para mejorar la extracción, y hasta eso puedes evitarlo.
¿La data sale de mi máquina?
No, en modo local_external o embedded local todo queda en tu red. La memoria, los embeddings y el storage viven en tu contenedor.
¿Hindsight reemplaza a mi CLAUDE.md?
No. Es una capa aditiva. Tus markdown y tu CLAUDE.md siguen siendo la fuente primaria, y el kill switch es apagar el contenedor, sin pérdida de tus archivos.
¿Funciona en español?
Sí, si fijas un embedding multilingüe (bge-m3) antes del primer retain. Con el default en inglés, el recall en español se degrada en silencio.
¿Puedo compartir memoria entre varios agentes?
Sí. Apuntas todos al mismo server con un bankId común. Por defecto cada agente queda aislado, así que la memoria compartida es una decisión que tomas a propósito.
¿mem0 o Hindsight?
mem0 para recall simple y arranque rápido. Hindsight cuando quieres grafo temporal, consolidación automática, mental models y self-hosted de verdad.
¿Cuánto cuesta operarlo?
Un contenedor Docker más tu stack local. Sin cuota de SaaS. Si usas un LLM cloud barato para la extracción, son centavos al mes; el resto es compute que ya tienes.
🤖 ¿Quieres construir tu propio agente de IA?
En el AI Agents Starter Kit pasas del concepto a un agente de ventas funcionando en WhatsApp — camino no-code (Make) o técnico (n8n).
Ver el curso