Back to Zeroclaw

Runtime state and persistence

docs/book/src/architecture/runtime-state-and-persistence.md

0.8.38.6 KB
Original Source

Runtime state and persistence

ZeroClaw has one install root, but not one monolithic "workspace database". Different state surfaces have different owners, reload behavior, and durability. Use this map when a change adds state, moves state, caches config, touches reload, or changes session/memory/log/cost behavior.

The single-source-of-truth rule still applies: if a fact already lives in one surface, do not copy it into another stored field. Store new state only when this table identifies the owning surface, or resolve it from the canonical owner at use time.

Install layout

For a normal install, <install> is the resolved config directory (~/.zeroclaw/ by default, Homebrew and explicit --config-dir installs can move it). The current layout is:

text
<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
│   ├── 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

The legacy <install>/workspace/ name is still accepted during migration, but new runtime state should be described in terms of <install>/data/, <install>/shared/, and per-agent workspaces.

State map

SurfaceCanonical sourceDurable pathIn-memory ownerReload / concurrency boundaryNotes
Config valueszeroclaw-config::Config loaded from config.toml<install>/config.tomldaemon Arc<RwLock<Config>> plus per-subsystem resolved views/admin/reload re-reads config and re-instantiates daemon subsystems; direct config writes use schema validation and dirty-path checksDo not cache config-derived facts in long-lived structs unless the cache is explicitly rebuilt on reload.
Encrypted secretsConfig secret fields plus .secret_key<install>/config.toml, <install>/.secret_keysecret-store helpers in zeroclaw-configReload observes changed config; losing .secret_key makes encrypted config secrets unrecoverableNever copy decrypted values into logs, docs, PR bodies, or runtime metadata.
Agent filesystem identityPer-agent workspace files<install>/agents/<alias>/workspace/effective SecurityPolicy and agent prompt constructionCreated lazily when the agent starts; workspace access is evaluated from configThis is the filesystem sandbox, not the config source of truth for providers/channels/tools.
Shared skill bundlesConfigured skill bundle entries and resolved bundle dirs<install>/shared/skills/<bundle>/ by defaultskill loading / prompt enrichmentReload and new agent starts observe config and filesystem changesBundle aliases and directory resolution come from config; the files are the bundle content.
Conversation memoryzeroclaw-memory backend selected per agentSQLite/Postgres/Lucid/Qdrant/Markdown backend locations; SQLite shared store lives under data/memory/Arc<dyn Memory> wrapped in agent-scoping adaptersBackend choice is locked once an agent has written data; same-backend cross-agent recall is opt-inMemory rows are agent-scoped. Do not replace memory ownership with copied prompt/session caches.
Chat and channel sessions[channels].session_backend plus SessionBackendDefault data/sessions/sessions.db; legacy/explicit JSONL uses data/sessions/*.jsonlzeroclaw-infra session backend shared by channels, gateway, RPC toolsSQLite backend uses WAL; SessionActorQueue serializes active turns per sessionChat/Code sessions use this unified backend. ACP protocol sessions use a separate store.
ACP sessionsACP protocol session storedata/sessions/acp-sessions.dbAcpSessionStore opened at daemon boot and in RPC contextWAL-backed SQLite store, separate from chat sessionsACP session/load and session/resume operate on this protocol store, not the chat session backend.
Live RPC/TUI sessionsRPC SessionStorenone by itselfcrates/zeroclaw-runtime/src/rpc/session.rs in-memory mapProcess-local; session history persists only through the chat or ACP backendLive session handles, uploads, cancel tokens, owners, and overrides are runtime state.
Cron jobsDeclarative config membership plus cron SQLite storedata/cron/jobs.dbzeroclaw-runtime::cron scheduler/storeRead paths do not create jobs.db; scheduler owns due/lock stateDeclarative jobs are reconciled from config, while run metadata and locks live in the cron DB.
Runtime logszeroclaw-log event schema and subscriber layerdata/state/runtime-trace.jsonl when persistence is enabledbroadcast hook, JSONL writer, /api/logs reader, Observer bridgeRolling/full/none persistence is config-controlled; dashboard SSE receives events even when JSONL is disabledLogs are evidence and observability, not the source of user config or session state.
Cost ledgerCostTracker plus rate configdata/state/costs.jsonlprocess-global CostTrackerReload hot-swaps CostConfig; the tracker is constructed on demand if cost tracking becomes enabledExisting records keep their recorded price; rate edits affect future requests after reload.
Gateway pairing tokensPairingGuard from gateway.paired_tokenstoken hashes in configpairing guardReload reconstructs the guard from configValid bearer tokens are config state, not devices.db rows.
Paired device metadataDevice registry rows keyed by token hashdata/devices.dbDeviceRegistry cache plus SQLiteRegistry reconciles metadata against the canonical paired-token setThis DB makes paired devices visible/manageable; it does not invent valid tokens.
Health and component statusrunning subsystems report component statenonegateway health/status stateProcess-local; reset/rebuilt on daemon restart or reload/health, /api/health, and /api/status are current observations, not durable configuration.
Queues, debouncers, watchdogszeroclaw-infra process utilitiesnone unless a caller stores results elsewherein-memory queues/debouncers/watchdogsProcess-local; used to serialize, coalesce, or detect stallsTreat these as coordination state. Persist only the domain data they protect, not the queue itself.

Reload and restart

POST /admin/reload sends an in-process reload signal to the daemon. The outer daemon loop re-reads config from disk and re-runs the daemon, creating fresh gateway, channel, heartbeat, scheduler, MQTT, session, memory, and cost wiring from the new config. The PID stays the same, but listeners briefly rebind.

A full process restart also rotates process-local state such as live RPC sessions, health snapshots, actor queues, and any ephemeral tool-receipt key. Durable stores survive restart according to the table above.

Backup and restore

For a normal single-instance install, back up the whole <install> directory. At minimum, include:

  • config.toml
  • .secret_key if encrypted secrets are used
  • data/memory/
  • data/sessions/
  • data/cron/jobs.db if cron jobs are configured through runtime surfaces
  • data/state/costs.jsonl if cost history matters
  • data/state/runtime-trace.jsonl if logs are needed for incident review
  • data/devices.db for paired-device metadata

Do not run two daemons against the same install root. Several stores use SQLite with a single-writer model, and the process-local caches assume one daemon owns the instance.

Source pointers

  • Config, install-root, and data-dir resolution: crates/zeroclaw-config/src/schema.rs
  • Session backends: 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
  • RPC live sessions: crates/zeroclaw-runtime/src/rpc/session.rs
  • Cron persistence: crates/zeroclaw-runtime/src/cron/store.rs
  • Logs: crates/zeroclaw-log/
  • Cost ledger: crates/zeroclaw-config/src/cost/tracker.rs
  • Pairing guard: crates/zeroclaw-config/src/pairing.rs
  • Device registry: crates/zeroclaw-gateway/src/api_pairing.rs
  • Reload endpoint: crates/zeroclaw-gateway/src/lib.rs