id : ADR-005 titre : Le stockage mémoire est indépendant du backend, avec SQLite par défaut date : 2026-07-14 statut : accepté concerne :
- 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 : Le stockage de la mémoire est indépendant du backend, avec SQLite comme valeur par défaut
Ceci est un enregistrement rétroactif d’une architecture qui a évolué avant le processus ADR formel. La date exacte de la décision d’origine n’est pas disponible dans cet enregistrement ; la date ci-dessus est la date à laquelle cet ADR a été ajouté à la documentation de l’architecture.
FND-002 décrivait initialement cette décision comme le choix de SQLite et de Markdown comme les deux backends de mémoire. Cette description ne reflète plus le contrat plus large. Ce document décrit l’architecture pérenne au lieu de figer un nombre de backends.
Contexte
ZeroClaw a besoin d’une mémoire persistante entre les installations avec des contraintes opérationnelles différentes. Un agent local mono-processus bénéficie d’un magasin embarqué sans dépendance de service. Les opérateurs peuvent également avoir besoin d’un magasin de système de fichiers lisible par l’humain, d’une base de données partagée, d’une base de données vectorielle ou d’une intégration avec un autre système de mémoire.
Ces stores n’ont pas des schémas ou des propriétés opérationnelles identiques. Ils doivent néanmoins présenter une interface d’exécution unique pour les opérations de mémoire et le cadrage de portée. Les opérations individuelles peuvent avoir une sémantique de capacité spécifique au backend ; par exemple, la mémoire Markdown est en ajout uniquement et ne supprime pas d’entrées. Le traitement des tours ne doit pas dépendre d’un type de base de données concret, et l’ajout d’un backend ne doit pas nécessiter de copier la politique d’assemblage de prompts, de consolidation, d’hygiène ou d’autorisation des agents dans ce backend.
Le dépôt actuel reconnaît les stockages SQLite, Lucid, PostgreSQL, Qdrant et Markdown, ainsi que none pour désactiver la mémoire persistante. SQLite est le stockage par défaut. FND-001 identifie séparément SQLite et Markdown comme les stockages de base souhaités pour le runtime minimal final ; cette cible de packaging ne limite pas le contrat de stockage à deux implémentations.
Décision
La persistance de la mémoire est sélectionnée via un contrat indépendant du backend, SQLite étant le backend par défaut.
Contrat de stockage
Les implémentations concrètes du stockage implémentent le trait Memory de zeroclaw-api. Le trait prend en charge les opérations de persistance indépendantes du backend et la sémantique des entrées. Les appelants utilisent des handles Memory plutôt que d’effectuer des branchements selon SQLite, Markdown, PostgreSQL, Qdrant ou Lucid dans le code de traitement des tours.
La construction du backend consulte actuellement deux niveaux de configuration qui se chevauchent. agents.<alias>.memory.backend route directement uniquement les chemins de construction Markdown et none et fournit le type utilisé pour la validation du partage au sein d’un même backend. Toutes les autres valeurs par agent passent par la fabrique à l’échelle de l’installation, où memory.backend sélectionne l’entrée typée concrète storage.<kind>.<alias> ; les noms simples hérités se résolvent vers l’alias default. Cet ADR consigne cette interaction sans considérer le chevauchement comme un état final idéal. Les composants d’exécution doivent respecter la propriété actuelle de la fabrique et de la validation plutôt que d’inférer une sélection par agent non prise en charge ou de créer un autre sélecteur stocké.
SQLite reste le choix par défaut car il offre un stockage local durable, une récupération hybride et ne nécessite aucun service externe. D’autres backends peuvent être sélectionnés lorsque leurs propriétés de stockage, de déploiement, de lisibilité ou d’intégration sont requises. none est une demande explicite de désactiver la mémoire persistante, et non un repli implicite.
Modifier l’un ou l’autre sélecteur ne migre pas les données existantes. Le déplacement de données entre types de backends nécessite un chemin de migration explicite plutôt que de réinterpréter silencieusement un store comme un autre.
Politique de cycle de vie
Les backends de stockage ne sont pas propriétaires de la construction des prompts ni de la politique de tour. Le moteur de tour est propriétaire de la sélection et du rendu du contexte mémoire. MemoryStrategy est la frontière désignée pour la consolidation et la gouvernance au-dessus d’un handle Memory, mais la migration vers cette frontière n’est pas achevée : certains chemins appellent encore directement des fonctions de cycle de vie de niveau inférieur. Le ticket #6850 suit l’alignement restant. Les implémentations de backend fournissent le comportement de stockage et de récupération sans devenir le propriétaire à long terme de ces règles de cycle de vie.
Portée de l’agent
La portée de la mémoire est définie par l’identité de l’agent, indépendamment du système de stockage concret. Les systèmes de stockage adossés à SQL peuvent utiliser des UUID internes, tandis que les systèmes non SQL peuvent utiliser directement un alias d’agent. Les adaptateurs qui délimitent la portée par agent associent un backend à un agent, et la récupération inter-agents n’est autorisée que via la liste d’autorisation configurée et uniquement lorsque les agents utilisent le même backend. Un appelant ne doit pas contourner ces adaptateurs ni déduire que les identifiants spécifiques au backend ont la même représentation.
Ce document d’architecture (ADR) ne décide pas quelles implémentations de backend sont incluses dans un binaire donné, ni si un backend futur est natif, conditionné par une fonctionnalité (feature-gated), ou fourni par un plugin. Ce sont des décisions relevant du packaging et du cycle de vie des plugins. La contrainte stable est que chaque backend pris en charge respecte le contrat commun de stockage et de portée des agents (agent-scoping).
Conséquences
Conséquences positives :
- Le code des agents, des canaux, des passerelles et des outils peut dépendre d’une seule interface mémoire.
- SQLite fournit une valeur par défaut locale utile sans faire du stockage embarqué le seul modèle de déploiement.
- Les opérateurs peuvent choisir un stockage embarqué, basé sur des fichiers, une base de données partagée ou un stockage vectoriel sans modifier les appelants du traitement des tours.
- La construction, la consolidation et le nettoyage des prompts peuvent évoluer sans ajouter de méthodes de gestion du cycle de vie à chaque implémentation de stockage.
- L’isolation des agents repose sur un contrat unique visible par l’appelant, à travers des modèles d’identifiants et de stockage spécifiques à chaque backend.
Conséquences négatives :
- Les implémentations backend doivent préserver les contrats d’entrée partagés et de portée, même lorsque leurs modèles de stockage et d’interrogation diffèrent.
- Les appelants doivent tenir compte des différences de capacités, telles que les stockages en ajout seul et les opérations de traits qui signalent un comportement non pris en charge ou sans effet.
- La migration entre types de backends nécessite un déplacement explicite des données ; changer un backend configuré ne fait pas apparaître les données existantes dans le nouveau magasin.
- Les services et fonctionnalités facultatifs augmentent la matrice de validation, même si la plupart des appelants ne voient que le trait partagé.
Décisions de suivi :
- Le ticket #6850 suit la frontière entre le stockage et la politique de cycle de vie de la mémoire de plus haut niveau.
- L’adaptateur de mémoire WASM n’est pas encore un backend de démon configurable ; sa construction à l’exécution et son empaquetage restent un travail de plugin distinct.
- Les modifications de la migration inter-backend, du rappel d’agents partagés ou de l’identité de stockage nécessitent une revue de compatibilité explicite.
Références
- ADR-002 : Extensibilité pilotée par les traits
- FND-001: Architecture intentionnelle
- FND-002 : Normes de documentation
- État d’exécution et persistance
- 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