Por qué la memoria Honcho de Hermes acaba en otro proyecto


Tienes tres repositorios: un monorepo de backend, un frontend y una carpeta de scripts de operaciones que no tocas desde hace dos años. La semana pasada reescribiste el flujo de reembolsos en el monorepo. Hoy abres Hermes dentro de la carpeta de scripts, preguntas cómo quedó ese refactor y te responde con todo lujo de detalles sobre un proyecto que nunca has mencionado en ese directorio. El caso inverso da más grima: clonas un repositorio, no has escrito ni una línea y la primera conversación ya “recuerda” todo tu directorio personal. Ejecutas Hermes por proyecto justamente para que cada repositorio tenga su propia memoria. Honcho la estaba archivando en otro sitio.

Los prompts estaban bien. Lo que fallaba era el destino. El PR #112602 (fusionado el 2026-09-16) corrige las dos rutas de código que enrutaban las sesiones al lugar equivocado. Aquí tienes qué se rompió, cómo configurar sessionStrategy para que de verdad se aplique y cómo saber en qué sesión aterrizó tu memoria.

Dos términos, una frase cada uno

Honcho es uno de los memory providers de Hermes: modela al usuario como un perfil que persiste entre sesiones —user representation, peer card— en lugar de tratar cada conversación como una isla.

sessionStrategy decide cómo se mapean las sesiones de Honcho (piensa en “cubos de memoria”) sobre tu trabajo. El valor por defecto es per-directory y hay cuatro opciones:

sessionStrategy Qué hace
per-session Cada ejecución de hermes estrena sesión; la memoria vuelve a través de herramientas. La documentación lo recomienda para quien empieza
per-directory Una sesión por directorio de trabajo; el contexto se acumula entre ejecuciones (por defecto)
per-repo Una sesión por repositorio git
global Una única sesión para todos los directorios

Un detalle que conviene separar de todo lo anterior: en modo hybrid / context Honcho inyecta dos capas de contexto en el system prompt en cada turno: una capa base (resumen de sesión, representación del usuario, peer card, autorrepresentación de la IA) y un suplemento dialéctico generado por un LLM. contextCadence vale 1 por defecto y dialecticCadence 2 (la documentación sugiere 1–5); el resultado concatenado se recorta al presupuesto de contextTokens. La memoria de sesión y el perfil de usuario son dos cosas distintas, y mezclarlas hace que estos bugs sean mucho más difíciles de diagnosticar.

Si prefieres que la memoria viva en tu propio disco, la ruta con LanceDB está en cómo implementa Hermes la memoria semántica: el mismo problema con otro almacenamiento.

El síntoma: tres repositorios, una sola memoria

Tres variantes de la misma queja, todas con la misma configuración de fondo:

  • Preguntas por el repositorio B desde el A y Honcho te saca los detalles de B.
  • Un repositorio recién clonado llega con preferencias y conclusiones de proyectos antiguos.
  • Tu configuración dice per-repo, pero el agente se comporta como global.

Las tres significan lo mismo: todos los proyectos caen en la misma sesión, y esa sesión no lleva el nombre de ninguno de tus repositorios.

Causa uno: un título automático renombra la sesión sin avisar

Hermes escribe títulos por ti. Su procedencia es derived o llm (lo mismo ocurre con los títulos de lineage de las ramas de Desktop). Existen para que reconozcas las conversaciones en una lista: son metadatos de visualización.

El código antiguo no lo entendía así. Si una sesión tenía título, ese título participaba en la derivación del nombre de sesión. Un título automático como “Refactor the billing module” sacaba la conversación de la sesión del repositorio y la renombraba a Refactor-the-billing-module. Tu sessionStrategy seguía configurado; simplemente nadie lo consultaba.

Causa dos: la resolución usaba el directorio de arranque, no el workspace

Esta es más silenciosa. La resolución de la session key se hacía contra os.getcwd(), el directorio de arranque del proceso backend. Bajo Desktop o un messaging gateway ese proceso suele arrancar en $HOME, así que diera igual desde qué repositorio escribieras, el workspace que veía Honcho era tu directorio personal. Todos los proyectos colapsaban en un único cubo llamado home.

De ahí que tantas configuraciones parecieran global mientras el archivo de configuración decía otra cosa.

Qué cambió el PR #112602

El arreglo es deliberadamente estrecho: un cambio por bug, ambos en la ruta de resolución.

  • plugins/memory/honcho/client.py::_resolve_session_name_base — un título con procedencia derived o llm es metadato de visualización y salta por completo la rama del título. Un /title explícito (procedencia user) sí sigue sobrescribiendo. Un título sin fuente registrada mantiene el comportamiento antiguo.
  • plugins/memory/honcho/__init__.py::_resolve_session_key — resuelve contra kwargs["cwd"] o resolve_agent_cwd() (pinned session cwd → TERMINAL_CWD → directorio de arranque): el mismo contrato que ya usaban el system prompt y el descubrimiento de archivos de contexto, en lugar de os.getcwd().
  • hermes_state_common.py — las constantes TITLE_SOURCE_* viven en el módulo hermano cycle-safe, así que SessionDB y el plugin leen el mismo vocabulario.
  • agent/agent_init.py — AIAgent(cwd=...) graba agent.session_cwd, y _memory_provider_init_kwargs pasa session_title_source y cwd al provider.
  • tui_gateway/* — las rutas de eager-resume, branch, compute-host y deferred build pasan cwd_override (su registro de sesión aún no está en _sessions, y _set_session_context borraría el cwd). Un workspace que se mueve durante un deferred build también llega al agente ya construido.

Vale la pena memorizar la precedencia. Los messaging gateways mantienen su session key estable por chat, sea cual sea la estrategia o el título. Para el resto de sesiones: identidad per-session → mapeo manual de directorio → título explícito → la estrategia configurada, y gana la primera coincidencia.

La fusión se validó de extremo a extremo con imports reales (un SessionDB real, un HonchoMemoryProvider real, el cwd del proceso apuntando a un $HOME falso, el cwd de sesión ligado a un repositorio git llamado myapp y estrategia per-repo):

Caso Antes Después
sin título home myapp
título LLM “Refactor the billing module” Refactor-the-billing-module myapp
/title My Explicit Name explícito My-Explicit-Name My-Explicit-Name

La tercera fila es intencionada: un título escrito por ti sigue siendo una sobrescritura.

Configurar bien sessionStrategy

El asistente sigue siendo la vía con menos errores: pregunta por tu gateway y escribe las claves por ti.

hermes memory setup    # elige "honcho" en la lista de providers

Configurado a mano, config.yaml necesita al menos esto:

# ~/.hermes/config.yaml
memory:
  provider: honcho
echo 'HONCHO_API_KEY=***' >> ~/.hermes/.env

La API key se obtiene en honcho.dev. Ajustes como sessionStrategy viven en el bloque de configuración del provider Honcho, el mismo que escribe hermes memory setup. Si prefieres no editar el archivo, pulsa [e] en el prompt del asistente y define las claves en su editor.

Cómo elegir tu estrategia:

  • per-repo — un monorepo más varios repositorios independientes, cada uno con su memoria. Es el escenario de arriba.
  • per-directory — trabajas en un directorio a largo plazo y no necesitas aislamiento entre subcarpetas. Es el valor por defecto por algo.
  • per-session — cada ejecución empieza limpia y la memoria se recupera con herramientas. También es el mejor ajuste para depurar, porque separa con más nitidez la memoria de sesión del perfil de usuario.
  • global — solo si de verdad quieres un perfil compartido entre todos los proyectos.

El resto de ajustes (casi todos de gateway, juntos para referencia):

Ajuste Por defecto Qué hace
sessionStrategy per-directory Los cuatro niveles de arriba; las estrategias por directorio y los mapeos manuales de sessions usan el directorio de trabajo lógico de la sesión, no el de arranque del backend
a2aSessions true Los DM de otros bots se escriben en su propia sesión por bot emisor, nunca en la del humano; false omite del todo los turnos escritos por bots
pinUserPeer false Solo gateway. Con true, todos los usuarios de la plataforma colapsan en peerName
userPeerAliases {} Solo gateway. Mapa de IDs de runtime a peers ({"7654321": "alice"}), de varios a uno
runtimePeerPrefix "" Solo gateway. Da espacio de nombres a los IDs de runtime desconocidos (telegram_7654321) cuando no coincide ningún alias

La resolución de peers en el gateway prueba de arriba abajo y gana la primera: pinUserPeer → userPeerAliases[id] → runtimePeerPrefix + id → ID de runtime en bruto → peerName → fallback de session key. Si los datos de otra persona se te pegan en Telegram o Discord, esa es la tabla que hay que leer. Un aviso de la documentación: pasar pinUserPeer de true a false no migra datos; el historial bajo peerName se queda donde está. Los detalles a nivel de comando están en la referencia de hermes memory.

Cómo saber en qué sesión aterrizó la memoria

Después del arreglo el nombre de sesión es derivable, así que puedes razonar a la inversa:

  1. Mira la forma del nombre. Con estrategias por directorio o repositorio es el nombre del directorio o del repositorio (en la validación, myapp); sin información de workspace es el directorio de arranque (home); un título explícito se convierte en una forma con guiones (My-Explicit-Name). Un nombre de sesión con forma de título es la firma del bug antiguo: si ves Refactor-the-billing-module, el título se apoderó de la sesión.
  2. Haz una prueba cruzada. En el repositorio A, pide al agente que registre una conclusión que solo pertenece a A (una conclusión escrita por honcho_conclude, o la user card que hay detrás de honcho_profile). Luego cambia al repositorio B y pregunta por ella. Con per-repo, B debería quedarse en blanco. Si responde, los dos repositorios hablan con la misma sesión.
  3. Confirma el propio directorio de trabajo. Pide al agente que informe el directorio de trabajo de la ejecución actual y compáralo con el repositorio en el que crees estar. La cadena es contexto de sesión → terminal.cwd con scope → directorio de arranque; si algún eslabón devuelve $HOME, tu memoria se va al cubo home.
  4. Usa per-session como control. Cámbialo temporalmente: cada sesión nueva debería arrancar vacía. Si aparecen datos, vienen del perfil de usuario (user representation / peer card), no de la memoria de sesión; eso es por diseño, no contaminación cruzada.

Sesiones creadas antes del arreglo

La documentación es tajante: las sesiones creadas antes de que se registrara la procedencia del título conservan el comportamiento antiguo. Un título automático viejo no se distingue de un título de usuario viejo, así que un título sin fuente se trata como sobrescritura explícita. Actualizar no devuelve esas sesiones a la sesión del repositorio.

Hay un segundo límite: este cambio no migra los mensajes ya escritos en sesiones mal enrutadas. El historial que cayó en el cubo equivocado se queda ahí. Lo práctico es abrir una sesión nueva en el directorio correcto —resolverá al nombre de sesión correcto— y seguir usando /title explícito cuando quieras una sobrescritura deliberada, porque ese comportamiento no se ha tocado.

Si te gusta convertir las conclusiones en notas duraderas, que el agente escriba en tu bóveda de Obsidian mientras estás en el directorio del proyecto correcto sortea todo el problema: el sistema de archivos ya está particionado por proyecto. Y si programas trabajo, la misma cadena de memoria aparece en cron y continuidad de memoria.

Conclusiones

  • La memoria de Honcho tiene un destino concreto, y ese destino lo deciden sessionStrategy y el directorio de trabajo de la sesión.
  • Dos bugs rompieron una mitad cada uno: los títulos automáticos (derived / llm) ya no anulan la estrategia, y la resolución sigue el workspace de la conversación en lugar del directorio de arranque del proceso. Un /title explícito sigue siendo tu sobrescritura manual.
  • Usa per-repo con varios repositorios, per-directory para trabajo prolongado en un solo directorio y per-session para arranques limpios o cuando persigues un bug de enrutado.
  • Para diagnosticar, mira primero la forma del nombre de sesión y después lanza una pregunta cruzada entre repositorios.
  • Las sesiones heredadas y el historial ya mal enrutado no se mueven solos: abre sesiones nuevas desde el directorio correcto.