État d’exécution et persistance
ZeroClaw a une seule racine d’installation, mais pas une unique « base de données d’espace de travail » monolithique. Différentes surfaces d’état ont des propriétaires différents, un comportement de rechargement différent et une durabilité différente. Utilisez cette carte lorsqu’un changement ajoute de l’état, déplace de l’état, met en cache la configuration, touche au rechargement ou modifie le comportement de session/mémoire/journal/coût.
La règle de la source unique de vérité s’applique toujours : si un fait réside déjà dans une surface, ne le copiez pas dans un autre champ stocké. Stockez un nouvel état uniquement lorsque ce tableau identifie la surface propriétaire, ou résolvez-le depuis le propriétaire canonique au moment de l’utilisation.
Installer la mise en page
Pour une installation standard, <install> correspond au répertoire de configuration résolu (~/.zeroclaw/ par défaut, les installations via Homebrew ou avec l’option explicite --config-dir peuvent le déplacer). La structure actuelle est :
<install>/
├── config.toml # canonical user config
├── .secret_key # key for encrypted secrets
├── data/ # instance-wide runtime data
│ ├── sessions/
│ │ ├── sessions.db # default chat/session backend
│ │ └── acp-sessions.db # ACP protocol sessions
│ ├── cron/jobs.db # scheduled job state
│ ├── sop/runs.db # optional durable SOP run state
│ ├── control_plane.db # task supervision records
│ ├── state/
│ │ ├── runtime-trace.jsonl # persisted logs
│ │ └── costs.jsonl # cost ledger
│ ├── devices.db # paired-device metadata
│ └── memory/ # shared instance memory stores
├── shared/ # shared resources, such as skill bundles
└── agents/<alias>/workspace/ # per-agent filesystem sandbox and identity
Le nom hérité <install>/workspace/ est toujours accepté pendant la migration, mais le nouvel état d’exécution doit être décrit en termes de <install>/data/, <install>/shared/ et d’espaces de travail par agent.
Carte d’état
| Surface | Source canonique | Chemin durable | Propriétaire en mémoire | Rechargement / frontière de concurrence | Notes |
|---|---|---|---|---|---|
| Valeurs de configuration | zeroclaw-config::Config chargé depuis config.toml | <install>/config.toml | démon Arc<RwLock<Config>> plus vues résolues par sous-système | /admin/reload relit la configuration et réinstancie les sous-systèmes du démon ; les écritures directes de configuration utilisent la validation du schéma et des contrôles des chemins modifiés. Les mutations de configuration côté RPC sérialisent en outre l’intégralité de leur section de lecture-modification-vidage sur RpcContext::config_write_lock (mutex tokio en premier, parking_lot RwLock en second, et aucun garde parking_lot n’est conservé pendant un .await ou lock().await) ; les mutations de configuration HTTP de la passerelle sérialisent de même l’intégralité de leur section de lecture-modification-échange sur AppState::config_write_lock (même ordre des verrous) | Ne pas mettre en cache les données dérivées de la configuration dans des structs à longue durée de vie, sauf si le cache est explicitement reconstruit lors du rechargement. |
| Durabilité de l’enregistrement de la configuration | Chemin d’écriture atomique de save() / save_dirty() dans zeroclaw-config | <install>/config.toml ainsi que le fichier config.toml.bak conservé | comme pour les valeurs de configuration | Les écritures passent par un fichier temporaire, une synchronisation du répertoire avant remplacement, un renommage atomique, puis une synchronisation du répertoire après remplacement | Ok(()) signifie que le remplacement est visible, et non que la durabilité du renommage est garantie : un échec avant le remplacement interrompt l’opération en laissant le fichier sur disque et la configuration active inchangés, mais un échec de synchronisation du répertoire après le renommage renvoie tout de même Ok(()), avec un avertissement journalisé et config.toml.bak conservé. Après un crash survenant immédiatement après une telle sauvegarde, l’entrée de répertoire peut revenir au fichier précédent ; les appelants ne doivent pas considérer Ok comme une garantie de durabilité plus forte, et la récupération peut consulter le .bak conservé. |
| Secrets chiffrés | Champs secrets de configuration, plus .secret_key | <install>/config.toml, <install>/.secret_key | helpers du magasin de secrets dans zeroclaw-config | Le rechargement observe la configuration modifiée ; la perte de .secret_key rend les secrets de configuration chiffrés irrécupérables | Ne jamais copier les valeurs déchiffrées dans les logs, docs, corps de PR ou métadonnées d’exécution. |
| Identité du système de fichiers de l’agent | Fichiers d’espace de travail par agent | <install>/agents/<alias>/workspace/ | construction de SecurityPolicy effective et de prompt d’agent | Créé de manière différée au démarrage de l’agent ; les accès à l’espace de travail sont évalués à partir de la configuration. | Ceci est le bac à sable du système de fichiers, pas la source de vérité de configuration pour providers/channels/tools. |
| Bundles de compétences partagés | Entrées du bundle de compétences configurées et répertoires de bundle résolus | <install>/shared/skills/<bundle>/ par défaut | chargement de compétences / enrichissement de prompt | Le rechargement et les démarrages de nouveaux agents observent les changements de configuration et du système de fichiers | Les alias de bundle et la résolution des répertoires proviennent de la configuration ; les fichiers correspondent au contenu du bundle. |
| Mémoire de conversation | zeroclaw-memory backend sélectionné par agent | Emplacements des backends SQLite/Postgres/Lucid/Qdrant/Markdown ; le stockage partagé SQLite se trouve sous data/memory/ | Arc<dyn Memory> encapsulé dans des adaptateurs de portée d’agent | Le choix du backend est verrouillé une fois qu’un agent a écrit des données ; le rappel inter-agents sur le même backend est opt-in. | Les lignes de mémoire sont réservées à l’agent. Ne remplacez pas la propriété de la mémoire par des caches de prompts/sessions copiés. |
| Sessions de chat et de canal | [channels].session_backend plus SessionBackend | Par défaut data/sessions/sessions.db; le JSONL hérité/explicite utilise data/sessions/*.jsonl | Les handles du backend zeroclaw-infra sont actuellement construits indépendamment par les canaux, la passerelle, le RPC et les outils de session | Le backend SQLite utilise WAL ; SessionActorQueue sérialise les tours actifs par session ; les mutations JSONL partagent un verrou du répertoire des sessions propre au processus | Les sessions Chat/Code utilisent le contrat de backend unifié. Les sessions du protocole ACP utilisent un stockage distinct. La gestion, au niveau du processus, de la propriété du backend n’est pas encore centralisée dans une source unique. |
| Sessions ACP | Stockage de session du protocole ACP | data/sessions/acp-sessions.db | AcpSessionStore ouvert au démarrage du daemon et dans le contexte RPC | Stockage SQLite basé sur WAL, séparé des sessions de chat | ACP session/load et session/resume opèrent sur ce magasin de protocole, et non le backend de la session de chat. |
| Sessions RPC/TUI en direct | RPC SessionStore | aucun par lui-même | crates/zeroclaw-runtime/src/rpc/session.rs map en mémoire | Local au processus ; l’historique de session ne persiste que via le chat ou le backend ACP | Les identifiants de session en direct, les uploads, les jetons d’annulation, les propriétaires et les surcharges constituent l’état d’exécution. |
| tâches Cron | Configuration déclarative de l’appartenance et stockage cron SQLite | data/cron/jobs.db | zeroclaw-runtime::cron planificateur/stockage | Les chemins de lecture ne créent pas jobs.db ; le planificateur possède l’état due/lock | Les tâches déclaratives sont réconciliées à partir de la configuration, tandis que les métadonnées d’exécution et les verrous résident dans la base de données cron. |
| Exécutions SOP | SopEngine plus SopRunStore | Aucun par défaut ; data/sop/runs.db lorsque l’initialisation SQLite durable réussit | Caches des exécutions actives/terminées du moteur SOP | Le magasin durable détient les demandes d’admission et les révisions persistées ; le moteur restaure l’état actif et terminal au démarrage | L’échec d’initialisation du store enregistre un avertissement et bascule en mémoire. Les enregistrements d’audit en mémoire ne constituent pas la source de vérité du cycle de vie d’exécution. |
| Supervision des tâches en arrière-plan | Plan de contrôle des tâches durables | data/control_plane.db | handle du plan de contrôle, producteurs de tâches et faucheur | L’ID du PID/de démarrage du propriétaire identifie les processus orphelins du démarrage précédent ; le délai d’expiration du signal de vie s’applique uniquement aux producteurs qui émettent des signaux de vie | Les producteurs actuels de délégués/sous-agents enregistrent des lignes en mode best-effort, mais ne renseignent pas les champs heartbeat, parent, route et principal. Les API d’objectifs existent, mais l’exécution de bout en bout des objectifs n’est pas encore câblée. |
| Résultats du délégué en arrière-plan | Enregistrement de résultat délégué | <workspace>/delegate_results/<task-id>.json | registre d’annulation des outils délégués et future en cours d’exécution | Les fichiers de résultats survivent au redémarrage ; les handles d’annulation en direct ne survivent pas | Les lectures privilégient le fichier et n’appliquent la supervision lost ou timed_out que si le fichier indique toujours running ; les écritures de résultats et du plan de contrôle sont indépendantes et peuvent diverger. |
| Journaux d’exécution | zeroclaw-log schéma d’événements et couche d’abonnés | data/state/runtime-trace.jsonl lorsque la persistance est activée | hook de diffusion, writer JSONL, lecteur /api/logs, pont Observer | La persistance rolling/full/none est contrôlée par la configuration ; le SSE du dashboard reçoit les événements même lorsque JSONL est désactivé | Les logs constituent des preuves et de l’observabilité, et non la source de la configuration utilisateur ou de l’état de session. |
| Registre des coûts | CostTracker plus configuration des tarifs | data/state/costs.jsonl | CostTracker global au processus | Le rechargement remplace à chaud CostConfig ; le tracker est construit à la demande si le suivi des coûts devient activé | Les enregistrements existants conservent leur prix enregistré ; les modifications de taux affectent les futures requêtes après le rechargement. |
| Jetons d’appairage de passerelle | PairingGuard de gateway.paired_tokens | hachages de jetons dans la config | garde d’appairage | Recharger reconstruit le garde à partir de la config | Les jetons bearer valides sont un état de configuration, pas des lignes de devices.db. |
| Métadonnées de l’appareil appairé | Lignes du registre des appareils indexées par le hachage du jeton | data/devices.db | DeviceRegistry cache plus SQLite | Registry réconcilie les métadonnées par rapport à l’ensemble canonique de tokens appariés | Cette DB rend les appareils appairés visibles/gérables ; elle n’invente pas de tokens valides. |
| État et statut des composants | les sous-systèmes en cours d’exécution rapportent l’état des composants | aucun | état de santé/statut de la passerelle | Local au processus ; réinitialisé/reconstruit au redémarrage ou au rechargement du démon | /health, /api/health et /api/status sont des observations actuelles, pas une configuration durable. |
| Files d’attente, anti-rebonds, chiens de garde | zeroclaw-infra utilitaires de processus | aucun sauf si un appelant stocke les résultats ailleurs | files d’attente/debouncers/watchdogs en mémoire | Local au processus ; utilisé pour sérialiser, fusionner ou détecter les blocages | Traitez-les comme un état de coordination. Persistez uniquement les données de domaine qu’ils protègent, pas la file d’attente elle-même. |
Recharger et redémarrer
POST /admin/reload envoie un signal de rechargement in-process au daemon. La boucle externe du daemon relit la config depuis le disque et relance le daemon, créant un nouveau câblage pour gateway, channel, heartbeat, scheduler, MQTT, session, memory et cost à partir de la nouvelle config. Le PID reste le même, mais les listeners se rebindent brièvement.
Un redémarrage complet du processus réinitialise également l’état local au processus, notamment les sessions RPC actives, les instantanés de santé, les files d’attente d’acteurs et toute clé d’accusé de réception d’outil éphémère. Les stores durables persistent lors du redémarrage, comme indiqué dans le tableau ci-dessus.
Migration du backend de session
La sélection du backend de session SQLite importe les fichiers hérités data/sessions/*.jsonl lors de la construction d’un handle de backend. L’importateur déplace chaque source vers une génération privée .jsonl.importing tout en maintenant le verrou de mutation JSONL local au processus, écrit les messages, les métadonnées et un reçu d’importation associé à la source dans une transaction SQLite, puis conserve la source sous .jsonl.migrated pour permettre un retour arrière.
Le reçu lie le nom de fichier source, la clé de session, le condensat SHA-256 et la longueur en octets. Avant le début de la transaction du reçu, l’importateur synchronise le fichier source intermédiaire et, sous Unix, le renommage du répertoire live vers le répertoire intermédiaire. Les transactions de migration utilisent une synchronisation SQLite complète pour la validation de l’import, puis restaurent le paramètre d’exécution normal. Le transfert vers l’archive synchronise de même les métadonnées du répertoire sous Unix avant de supprimer la source intermédiaire. La construction du backend restaure l’état inactif local au processus à partir des reçus persistants avant de parcourir les fichiers source. Dès qu’un reçu d’import est validé, les mutations JSONL de ce répertoire de session restent inactives, même si le transfert vers l’archive ou un fichier ultérieur échoue. La construction suivante peut vérifier la source intermédiaire par rapport à ce reçu et terminer le transfert sans insérer de messages en double. Les fichiers JSONL vides ou composés uniquement d’espaces blancs sont conservés en tant que sessions SQLite contenant zéro message ; une source non vide ne contenant aucun message valide échoue néanmoins de manière sécurisée.
Construire le backend SQLite sans importer de source ne désactive pas les mutations JSONL. Un rechargement au sein du processus peut donc repasser à JSONL lorsqu’aucun reçu d’importation persistant n’existe.
Une source dépourvue de reçu n’est pas fusionnée par-dessus les messages SQLite ou les métadonnées existants pour la même clé de session. Si cette vérification préalable à la validation échoue, la source préparée est restaurée sur son chemin JSONL actif. Un reçu incompatible, une source préparée incompatible ou une archive incompatible entraîne une erreur lors de la construction du backend. Chaque point d’entrée de processus décide actuellement indépendamment si cette erreur arrête le sous-système ou désactive la persistance ; la gestion au niveau du processus et la stratégie de démarrage sont distinctes du contrat de migration.
Sauvegarde et restauration
Pour une installation normale sur une seule instance, sauvegardez l’intégralité du répertoire <install>. À minima, incluez :
config.toml.secret_keysi des secrets chiffrés sont utilisésdata/memory/data/sessions/data/cron/jobs.dbsi les tâches cron sont configurées via les surfaces d’exécutiondata/sop/runs.dbsi les exécutions SOP durables sont activéesdata/control_plane.dbsi l’historique des tâches supervisées est importantdata/state/costs.jsonlsi l’historique des coûts est importantdata/state/runtime-trace.jsonlsi des journaux sont nécessaires pour l’examen d’incidentdata/devices.dbpour les métadonnées des appareils appairés
Ne lancez pas deux démons sur la même racine d’installation. Plusieurs magasins utilisent SQLite avec un modèle à écriture unique, et les caches par processus supposent qu’un seul démon possède l’instance.
Pointeurs source
- Résolution de Config, install-root et data-dir :
crates/zeroclaw-config/src/schema.rs - Backends de session :
crates/zeroclaw-infra/src/session_sqlite.rs,crates/zeroclaw-infra/src/session_store.rs - Stockage de sessions ACP :
crates/zeroclaw-infra/src/acp_session_store.rs - Sessions live RPC :
crates/zeroclaw-runtime/src/rpc/session.rs - Persistance Cron :
crates/zeroclaw-runtime/src/cron/store.rs - Persistance de SOP :
crates/zeroclaw-runtime/src/sop/store/ - Supervision des tâches en arrière-plan et des objectifs :
crates/zeroclaw-runtime/src/control_plane/ - Résultats de délégation en arrière-plan :
crates/zeroclaw-runtime/src/tools/delegate.rs - Journaux :
crates/zeroclaw-log/ - Registre des coûts :
crates/zeroclaw-config/src/cost/tracker.rs - Garde d’appairage :
crates/zeroclaw-config/src/pairing.rs - Registre des périphériques :
crates/zeroclaw-gateway/src/api_pairing.rs - Endpoint de rechargement :
crates/zeroclaw-gateway/src/lib.rs