id: ADR-005 title: El almacenamiento de memoria es independiente del backend, con SQLite como valor predeterminado date: 2026-07-14 status: accepted relates-to:
- ADR-002
- docs/book/src/foundations/fnd-001-intentional-architecture.md
- docs/book/src/foundations/fnd-002-documentation-standards.md
- https://github.com/zeroclaw-labs/zeroclaw/issues/6850
- crates/zeroclaw-api/src/memory_traits.rs
- crates/zeroclaw-memory
- crates/zeroclaw-config/src/schema.rs
ADR-005: El almacenamiento de memoria es independiente del backend con SQLite como opción predeterminada
Este es un registro retroactivo de una arquitectura que evolucionó antes del proceso formal de ADR. La fecha exacta de la decisión original no está disponible en este registro; la fecha anterior es la fecha en que este ADR se añadió a la documentación de arquitectura.
FND-002 describía originalmente esta decisión como la elección de SQLite y Markdown como los dos backends de memoria. Esa descripción ya no refleja el contrato más amplio. Este registro describe la arquitectura duradera en lugar de congelar un número de backends.
Contexto
ZeroClaw necesita memoria persistente entre instalaciones con diferentes restricciones operativas. Un agente local de un solo proceso se beneficia de un almacén integrado sin dependencia de servicios. Los operadores también pueden necesitar un almacén de sistema de archivos legible por humanos, una base de datos compartida, una base de datos vectorial o una integración con otro sistema de memoria.
Estos almacenes no tienen esquemas ni propiedades operativas idénticas. Aun así, deben presentar una interfaz de tiempo de ejecución única para las operaciones de memoria y la definición de alcance. Las operaciones individuales pueden tener semánticas de capacidad específicas del backend; por ejemplo, la memoria Markdown es de solo anexado y no elimina entradas. El procesamiento de turnos no debe depender de un tipo de base de datos concreto, y agregar un backend no debe requerir copiar la política de ensamblaje de prompts, consolidación, higiene o autorización de agentes en ese backend.
El repositorio actual reconoce los almacenamientos SQLite, Lucid, PostgreSQL, Qdrant y Markdown, además de none para deshabilitar la memoria persistente. SQLite es el valor predeterminado. FND-001 identifica por separado SQLite y Markdown como los almacenamientos base deseados para el tiempo de ejecución mínimo eventual; ese objetivo de empaquetado no limita el contrato de almacenamiento a dos implementaciones.
Decisión
La persistencia de memoria se selecciona mediante un contrato independiente del backend, con SQLite como backend predeterminado.
Contrato de almacenamiento
Los almacenes concretos implementan el trait Memory de zeroclaw-api. El trait posee las operaciones de persistencia neutrales al backend y la semántica de las entradas. Los llamadores usan manejadores Memory en lugar de ramificar entre SQLite, Markdown, PostgreSQL, Qdrant o Lucid en el código de procesamiento de turnos.
La construcción del backend consulta actualmente dos niveles de configuración superpuestos. agents.<alias>.memory.backend dirige directamente solo las rutas de construcción de Markdown y none, y proporciona el tipo utilizado para la validación del uso compartido del mismo backend. Todos los demás valores por agente pasan por la factoría de toda la instalación, donde memory.backend selecciona la entrada concreta tipada storage.<kind>.<alias>; los nombres simples heredados se resuelven en el alias default. Este ADR documenta esa interacción sin considerar la superposición un estado final ideal. Los componentes en tiempo de ejecución deben seguir la factoría y la responsabilidad de validación actuales, en lugar de inferir una selección por agente no compatible o crear otro selector almacenado.
SQLite sigue siendo el predeterminado porque proporciona almacenamiento local duradero, recuperación híbrida y no requiere servicios externos. Se pueden seleccionar otros backends cuando se necesiten sus distintas propiedades de almacenamiento, despliegue, legibilidad o integración. none es una solicitud explícita para deshabilitar la memoria persistente, no una alternativa implícita.
Cambiar cualquiera de los selectores no migra los datos existentes. Mover datos entre tipos de backend requiere una ruta de migración explícita en lugar de reinterpretar de forma silenciosa un almacén como otro.
Política del ciclo de vida
Los backends de almacenamiento no son propietarios de la construcción de prompts ni de la política de turnos. El motor de turnos es el propietario de la selección y representación del contexto de memoria. MemoryStrategy es el límite designado para la consolidación y la gobernanza por encima de un handle Memory, pero la migración a ese límite no está completa: algunas rutas aún llaman directamente a funciones de ciclo de vida de nivel inferior. El issue #6850 realiza el seguimiento de la alineación pendiente. Las implementaciones de backend proporcionan comportamiento de almacenamiento y recuperación sin convertirse en el propietario a largo plazo de esas reglas de ciclo de vida.
Ámbito del agente
La memoria está delimitada a la identidad del agente independientemente del almacén concreto. Los almacenes respaldados por SQL pueden usar UUID internos, mientras que los almacenes no SQL pueden usar directamente un alias de agente. Los adaptadores de delimitación por agente vinculan un backend a un agente, y la recuperación entre agentes solo se permite a través de la allowlist configurada y únicamente cuando los agentes usan el mismo backend. Un llamador no debe eludir esos adaptadores ni inferir que los identificadores específicos del backend tienen la misma representación.
Este ADR no decide qué implementaciones de backend se incluyen en un binario particular ni si un backend futuro es nativo, controlado por feature flags o suministrado por un plugin. Esas son decisiones de empaquetado y ciclo de vida de plugins. La restricción estable es que cada backend compatible preserve el contrato común de almacenamiento y alcance de agentes.
Consecuencias
Consecuencias positivas:
- El código de agentes, canales, puertas de enlace y herramientas puede depender de una única interfaz de memoria.
- SQLite proporciona un valor predeterminado local útil sin convertir el almacenamiento integrado en el único modelo de implementación.
- Los operadores pueden elegir almacenamiento embebido, respaldado por archivos, base de datos compartida o vectorial sin cambiar los llamadores del procesamiento de turnos.
- La construcción, consolidación e higiene de los prompts pueden evolucionar sin necesidad de añadir métodos de política de ciclo de vida a cada implementación de almacenamiento.
- El aislamiento de agentes tiene un único contrato visible para el llamador en los modelos de identificadores y almacenamiento específicos del backend.
Consecuencias negativas:
- Las implementaciones de backend deben preservar los contratos compartidos de entrada y de ámbito incluso cuando sus modelos de almacenamiento y consulta difieran.
- Los llamadores deben tener en cuenta las diferencias de capacidad, como los almacenes de solo anexado y las operaciones de trait que informan comportamiento no compatible o sin efecto.
- La migración entre tipos de backend requiere mover los datos explícitamente; cambiar un backend configurado no hace que los datos existentes aparezcan en el nuevo almacén.
- Los servicios y características opcionales aumentan la matriz de validación aunque la mayoría de los invocadores solo vean el trait compartido.
Decisiones de seguimiento:
- El issue #6850 rastrea el límite entre el almacenamiento y la política de ciclo de vida de memoria de nivel superior.
- El adaptador de memoria WASM aún no es un backend de daemon configurable; su construcción en tiempo de ejecución y su empaquetado siguen siendo trabajo de plugin independiente.
- Los cambios en la migración entre backends, la recuperación de agentes compartidos o la identidad del almacenamiento requieren una revisión explícita de compatibilidad.
Referencias
- ADR-002: Extensibilidad basada en traits
- FND-001: Arquitectura intencional
- FND-002: Estándares de documentación
- Estado en tiempo de ejecución y persistencia
- Issue #6850
crates/zeroclaw-api/src/memory_traits.rscrates/zeroclaw-config/src/schema.rscrates/zeroclaw-memory/src/backend.rscrates/zeroclaw-memory/src/lib.rscrates/zeroclaw-runtime/src/agent/memory_strategy.rs