Estado en tiempo de ejecución y persistencia
ZeroClaw tiene un único directorio raíz de instalación, pero no una sola “base de datos del espacio de trabajo” monolítica. Las distintas superficies de estado tienen propietarios, comportamiento de recarga y durabilidad diferentes. Usa este mapa cuando un cambio añada estado, mueva estado, almacene en caché la configuración, toque la recarga o cambie el comportamiento de sesión/memoria/log/coste.
La regla de fuente única de verdad sigue aplicándose: si un dato ya reside en una superficie, no lo copies en otro campo almacenado. Almacena el nuevo estado solo cuando esta tabla identifique la superficie propietaria, o resuélvelo desde el propietario canónico en el momento de uso.
Instalar diseño
Para una instalación normal, <install> es el directorio de configuración resuelto (~/.zeroclaw/ de forma predeterminada; las instalaciones de Homebrew y las que usan --config-dir explícito pueden moverlo). La disposición actual es:
<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
El nombre heredado <install>/workspace/ todavía se acepta durante la migración, pero el nuevo estado en tiempo de ejecución debe describirse en términos de <install>/data/, <install>/shared/ y espacios de trabajo por agente.
Mapa de estado
| Superficie | Fuente canónica | Ruta duradera | Propietario en memoria | Recarga / límite de concurrencia | Notas |
|---|---|---|---|---|---|
| Valores de configuración | zeroclaw-config::Config cargado desde config.toml | <install>/config.toml | daemon Arc<RwLock<Config>> más vistas resueltas por subsistema | /admin/reload vuelve a leer la configuración y vuelve a instanciar los subsistemas del demonio; las escrituras directas de configuración usan la validación del esquema y comprobaciones de rutas modificadas. Las mutaciones de configuración del lado de RPC serializan además toda su sección de lectura-modificación-volcado en RpcContext::config_write_lock (primero el mutex de tokio, después RwLock de parking_lot, y nunca se mantiene una guarda de parking_lot durante un .await o lock().await); las mutaciones de configuración del gateway HTTP también serializan toda su sección de lectura-modificación-intercambio en AppState::config_write_lock (el mismo orden de bloqueos) | No almacenes en caché hechos derivados de la configuración en estructuras de larga duración, a menos que la caché se reconstruya explícitamente al recargar. |
| Durabilidad del guardado de la configuración | Ruta de escritura atómica de save() / save_dirty() en zeroclaw-config | <install>/config.toml y se conserva config.toml.bak | igual que los valores de configuración | Las escrituras se realizan mediante un archivo temporal, una sincronización del directorio previa al reemplazo, un renombrado atómico y una sincronización del directorio posterior al reemplazo | Ok(()) significa que el reemplazo es visible, no que se haya demostrado la durabilidad del renombrado: un fallo previo al reemplazo aborta dejando el disco y la configuración activa sin cambios, pero un fallo de sincronización del directorio posterior al renombrado aún devuelve Ok(()), registra una advertencia y conserva config.toml.bak. Tras un bloqueo inmediatamente después de un guardado de este tipo, la entrada del directorio puede volver a apuntar al archivo anterior; los llamadores no deben tratar Ok como una garantía de durabilidad más sólida, y la recuperación puede consultar el .bak conservado. |
| Secretos cifrados | Campos secretos de configuración más .secret_key | <install>/config.toml, <install>/.secret_key | ayudantes de secret-store en zeroclaw-config | Reload observa los cambios de configuración; perder .secret_key hace irrecuperables los secretos de configuración cifrada | Nunca copies valores descifrados en registros, documentación, cuerpos de PR ni metadatos en tiempo de ejecución. |
| Identidad del sistema de archivos del agente | Archivos de espacio de trabajo por agente | <install>/agents/<alias>/workspace/ | construcción efectiva de SecurityPolicy y del prompt del agente | Creado perezosamente cuando el agente se inicia; el acceso al espacio de trabajo se evalúa desde la configuración | Este es el sandbox del sistema de archivos, no la fuente de verdad de configuración para proveedores/canales/herramientas. |
| Paquetes de habilidades compartidos | Entradas del paquete de habilidades configuradas y directorios del paquete resueltos | <install>/shared/skills/<bundle>/ de forma predeterminada | carga de habilidades / enriquecimiento de prompts | Recargue y el nuevo agente comienza a observar los cambios de configuración y del sistema de archivos | Los alias del bundle y la resolución de directorios provienen de la configuración; los archivos son el contenido del bundle. |
| Memoria de conversación | zeroclaw-memory backend seleccionado por agente | Ubicaciones del backend de SQLite/Postgres/Lucid/Qdrant/Markdown; el almacén compartido de SQLite vive en data/memory/ | Arc<dyn Memory> envuelto en adaptadores de ámbito de agente | La elección del backend queda bloqueada una vez que un agente ha escrito datos; la recuperación entre agentes en el mismo backend es opcional. | Las filas de memoria están acotadas al agente. No reemplace la propiedad de la memoria con copias de cachés de prompt/sesión. |
| Sesiones de chat y canal | [channels].session_backend más SessionBackend | Predeterminado data/sessions/sessions.db; JSONL heredado/expreso usa data/sessions/*.jsonl | Los manejadores del backend zeroclaw-infra se construyen actualmente de forma independiente en los canales, la puerta de enlace, RPC y las herramientas de sesión | El backend de SQLite usa WAL; SessionActorQueue serializa los turnos activos por sesión; las mutaciones de JSONL comparten un bloqueo del directorio de sesiones local al proceso | Las sesiones de Chat/Code usan el contrato de backend unificado. Las sesiones del protocolo ACP usan un almacén independiente. La propiedad del backend a nivel de proceso aún no está centralizada en una única fuente. |
| ACP sessions | ACP protocolo session store | data/sessions/acp-sessions.db | AcpSessionStore abierto al iniciar el daemon y en contexto RPC | Almacén SQLite respaldado por WAL, separado de las sesiones de chat | ACP session/load y session/resume operan sobre este almacén de protocolo, no sobre el backend de sesión de chat. |
| Sesiones RPC/TUI en vivo | RPC SessionStore | ninguno por sí solo | crates/zeroclaw-runtime/src/rpc/session.rs mapa en memoria | Local al proceso; el historial de sesión persiste solo a través del chat o del backend de ACP | Los identificadores de sesión en vivo, las cargas, los tokens de cancelación, los propietarios y las anulaciones son estado en tiempo de ejecución. |
| Trabajos cron | Membresía de configuración declarativa más almacén SQLite de cron | data/cron/jobs.db | zeroclaw-runtime::cron programador/almacén | Las rutas de lectura no crean jobs.db; el programador es propietario del estado de vencimiento/bloqueo | Los trabajos declarativos se reconcilian a partir de la configuración, mientras que los metadatos de ejecución y los bloqueos residen en la base de datos de cron. |
| ejecuciones de SOP | SopEngine más SopRunStore | Ninguno por defecto; data/sop/runs.db cuando la inicialización durable de SQLite se realiza correctamente | Cachés de ejecuciones activas/finalizadas del motor SOP | El almacén durable posee las reclamaciones de admisión y las revisiones persistidas; el motor restaura el estado activo y terminal al iniciarse | El fallo de inicialización del almacén registra una advertencia y recurre a la memoria. Los registros de auditoría respaldados en memoria no son la fuente de verdad del ciclo de vida de ejecución. |
| Supervisión de tareas en segundo plano | Plano de control de tareas duradero | data/control_plane.db | manejador del plano de control, productores de tareas y recolector | El PID de propietario/ID de arranque identifica huérfanos de arranques anteriores; el tiempo de espera de latido solo se aplica a los productores que emiten latidos | Los productores delegados/subagentes actuales registran filas de mejor esfuerzo, pero dejan ausentes los campos de heartbeat, parent, route y principal. Existen APIs de objetivos, pero la ejecución de objetivos de extremo a extremo aún no está conectada. |
| Resultados del delegado en segundo plano | Registro de resultado de delegación | <workspace>/delegate_results/<task-id>.json | registro de delegación de cancelación de herramientas y futuro en ejecución | Los archivos de resultado sobreviven al reinicio; los identificadores de cancelación en vivo no | Las lecturas priorizan el archivo y solo superponen la supervisión lost o timed_out cuando el archivo aún indica running; las escrituras de resultados y del plano de control son independientes y pueden divergir. |
| Registros de ejecución | zeroclaw-log esquema de eventos y capa de suscriptor | data/state/runtime-trace.jsonl cuando la persistencia está habilitada | hook de difusión, escritor JSONL, lector de /api/logs, puente Observer | La persistencia rolling/full/none está controlada por la configuración; el SSE del panel recibe eventos incluso cuando JSONL está deshabilitado | Los registros son evidencia y observabilidad, no la fuente de la configuración del usuario ni del estado de la sesión. |
| Libro mayor de costos | CostTracker más la configuración de tarifas | data/state/costs.jsonl | process-global CostTracker | Reload intercambia en caliente CostConfig; el rastreador se construye bajo demanda si el seguimiento de costes se habilita | Los registros existentes conservan su precio registrado; las ediciones de tarifa afectan las solicitudes futuras después de recargar. |
| Tokens de emparejamiento de Gateway | PairingGuard de gateway.paired_tokens | hashes de tokens en la configuración | emparejamiento de guardia | Reload reconstruye el guardián a partir de la configuración | Los tokens portadores válidos son estado de configuración, no filas de devices.db. |
| Metadatos del dispositivo emparejado | Filas del registro de dispositivos indexadas por hash de token | data/devices.db | DeviceRegistry caché más SQLite | Registry reconcilia los metadatos con el conjunto canónico de tokens emparejados | Esta DB hace que los dispositivos emparejados sean visibles y gestionables; no inventa tokens válidos. |
| Estado de salud y de los componentes | información del estado de los componentes de los subsistemas en ejecución | ninguno | estado de salud/estado de la gateway | Local al proceso; se restablece y recompila al reiniciar o recargar el daemon | /health, /api/health y /api/status son observaciones actuales, no configuración duradera. |
| Colas, debouncers, watchdogs | zeroclaw-infra utilidades de proceso | ninguno, a menos que un llamador almacene los resultados en otro lugar | colas/antirrebote/perros guardianes en memoria | Local del proceso; se utiliza para serializar, combinar o detectar bloqueos | Trátalas como estado de coordinación. Conserva solo los datos de dominio que protegen, no la cola en sí. |
Recargar y reiniciar
POST /admin/reload envía una señal de recarga en el mismo proceso al daemon. El bucle externo del daemon vuelve a leer la configuración desde disco y vuelve a ejecutar el daemon, creando nuevas conexiones de gateway, canal, heartbeat, scheduler, MQTT, sesión, memoria y cost wiring a partir de la nueva configuración. El PID permanece igual, pero los listeners se vuelven a enlazar brevemente.
Un reinicio completo del proceso también rota el estado local del proceso, como las sesiones RPC activas, las instantáneas de salud, las colas de actor y cualquier clave efímera de recibo de herramienta. Los almacenes duraderos sobreviven al reinicio según la tabla anterior.
Migración del backend de sesiones
Al seleccionar el backend de sesiones SQLite, se importan los archivos heredados data/sessions/*.jsonl cuando se construye un controlador del backend. El importador mueve cada origen a una generación privada .jsonl.importing mientras mantiene el bloqueo de mutaciones JSONL local al proceso, escribe los mensajes, los metadatos y un comprobante de importación vinculado al origen en una única transacción de SQLite y, después, conserva el origen como .jsonl.migrated para permitir la reversión.
El recibo vincula el nombre de archivo de origen, la clave de sesión, el resumen SHA-256 y la longitud en bytes. Antes de que comience la transacción del recibo, el importador sincroniza el archivo de origen preparado y, en Unix, el cambio de nombre del directorio de activo a preparado. Las transacciones de migración usan la sincronización completa de SQLite para la confirmación de la importación y, después, restauran la configuración normal de ejecución. La transferencia al archivo también sincroniza los metadatos del directorio en Unix antes de eliminar el origen preparado. La construcción del backend restaura el estado inactivo local del proceso a partir de los recibos persistentes antes de explorar los archivos de origen. En cuanto se confirma un recibo de importación, las mutaciones JSONL de ese directorio de sesiones permanecen inactivas aunque falle la transferencia al archivo o un archivo posterior. La siguiente construcción puede verificar el origen preparado con ese recibo y finalizar la transferencia sin insertar mensajes duplicados. Los archivos JSONL vacíos o que solo contienen espacios en blanco se conservan como sesiones SQLite sin mensajes; un origen no vacío sin mensajes válidos sigue fallando de forma segura.
Construir el backend de SQLite sin importar un origen no desactiva las mutaciones de JSONL. Por lo tanto, una recarga dentro del proceso puede volver a cambiar a JSONL cuando no existe un comprobante de importación persistente.
Una fuente sin recibo no se combina con los mensajes ni los metadatos existentes de SQLite para la misma clave de sesión. Si esa comprobación previa a la confirmación falla, la fuente preparada se restaura en su ruta JSONL activa. Un recibo, una fuente preparada o un archivo incompatibles hacen que la construcción del backend devuelva un error. Cada punto de entrada del proceso decide actualmente de forma independiente si ese error detiene el subsistema o deshabilita la persistencia; la responsabilidad a nivel de proceso y la política de inicio son independientes del contrato de migración.
Copia de seguridad y restauración
Para una instalación normal de una sola instancia, haga una copia de seguridad de todo el directorio <install>. Como mínimo, incluya:
config.toml.secret_keysi se usan secretos cifradosdata/memory/data/sessions/data/cron/jobs.dbsi los cron jobs se configuran a través de superficies de tiempo de ejecucióndata/sop/runs.dbsi están habilitadas las ejecuciones de SOP duraderasdata/control_plane.dbsi el historial de tareas supervisadas es relevantedata/state/costs.jsonlsi el historial de costos importadata/state/runtime-trace.jsonlsi se necesitan registros para la revisión del incidentedata/devices.dbpara metadatos de dispositivos emparejados
No ejecutes dos demonios contra la misma raíz de instalación. Varios almacenes usan SQLite con un modelo de un solo escritor, y las cachés locales del proceso asumen que un único demonio es propietario de la instancia.
Punteros de origen
- Resolución de Config, install-root y data-dir:
crates/zeroclaw-config/src/schema.rs - Backends de sesión:
crates/zeroclaw-infra/src/session_sqlite.rs,crates/zeroclaw-infra/src/session_store.rs - ACP session store:
crates/zeroclaw-infra/src/acp_session_store.rs - Sesiones RPC en vivo:
crates/zeroclaw-runtime/src/rpc/session.rs - Persistencia de Cron:
crates/zeroclaw-runtime/src/cron/store.rs - Persistencia de SOP:
crates/zeroclaw-runtime/src/sop/store/ - Supervisión de tareas en segundo plano y objetivos:
crates/zeroclaw-runtime/src/control_plane/ - Resultados de la delegación en segundo plano:
crates/zeroclaw-runtime/src/tools/delegate.rs - Registros:
crates/zeroclaw-log/ - Libro mayor de costos:
crates/zeroclaw-config/src/cost/tracker.rs - Guardia de emparejamiento:
crates/zeroclaw-config/src/pairing.rs - Registro de dispositivos:
crates/zeroclaw-gateway/src/api_pairing.rs - Punto final de recarga:
crates/zeroclaw-gateway/src/lib.rs