Skip to main content
OpenClaw stores control-plane state in a global SQLite database and agent data in one SQLite database per agent. Schema migrations run forward when a database opens. Older OpenClaw builds refuse databases written by a newer schema.

Database layout

A few high-volume or lifecycle-specific features use dedicated SQLite stores, including the task registry and trajectory data.

Versioning contract

Each database records its schema in two places:
  • PRAGMA user_version is the SQLite schema version.
  • The primary schema_meta row records role, agent_id, schema_version, and app_version. app_version is the OpenClaw build that last wrote the schema metadata.
OpenClaw applies forward-only migrations when it opens an older supported database. It refuses a database whose user_version is newer than the running build and reports a newer schema version error. The Gateway checks all registered databases before startup. openclaw update also refuses a package or source target whose declared schema support is older than an on-disk database. Target packages published before schema metadata was added cannot be preflighted. When Gateway startup encounters a newer database schema, it exits with status 78 so the generated systemd service does not restart it repeatedly. On macOS, it also parks its managed LaunchAgent to stop KeepAlive retries. This applies to failures during CLI bootstrap as well as server startup and does not depend on the database-backed crash counter. Start the Gateway with a build that supports the existing schemas. The older install cannot repair them with doctor --fix; run Doctor from the compatible install if further migration is required, then restart through the service or deployment owner. Changes may stay at the same schema version only when downgraded readers remain safe. New tables qualify because older builds ignore them. An explicitly compatible column on an existing table qualifies only when its declaration is exactly one bare nullable SQLite STRICT datatype: ANY, BLOB, INT, INTEGER, REAL, or TEXT. The declaration cannot have a default, NOT NULL, a primary or unique key, a check, a reference, a collation, a generated expression, or another suffix. Constrained existing-table additions require a schema-version bump or a companion table instead. Matching numeric versions are necessary but not sufficient. A release can add a lazy or startup-repairable table, column, index, or trigger without advancing user_version, so two databases at the same version can still have different shapes. OpenClaw validates the canonical table definitions, constraints, indexes, triggers, virtual tables, and table options owned by the running release. Agent schema 19 records collected input consumption in the nullable session_pending_inputs.consumed_event_id TEXT column. Doctor and the feature’s first-use ensure add it when needed; the schema version stays 19. The supported beta upgrade runs Doctor from the upcoming release. Intermediate builds that already validate the optional pending-input table may reject the added column despite sharing version 19. Consumed source receipts remain until their session window is deleted, so rewriting a transcript cannot make an old input runnable again. The placement-move table uses this same-version rule for its nullable bare abandon_source INTEGER column. The feature lazily ensures the column on first move use. NULL means ordinary reconcile-first movement; 1 records the operator’s explicit offline-device abandonment decision so restart recovery cannot accidentally resume remote reconciliation. Older readers ignore the column and can reopen the same database safely. Conversation associations use the same rule for the nullable bare route_context_json TEXT column. The database-open repair ensures the column for updated binaries. Older readers ignore it and can reopen and update the same database safely; their association update invalidates context captured by a newer writer so it cannot be replayed after re-upgrade. Transcript context eligibility uses a bare nullable session_transcript_active_events.context_eligible INTEGER column without changing agent schema 18. Database open installs the column and a non-unique partial index of unclassified rows. 1 includes an entry in bounded context acquisition, 0 excludes display-only activity, and NULL means the projection still needs reconciliation. Bootstrap control markers remain eligible; history counts, positions, and cursors do not change. Raw transcript JSON stays canonical. Older same-version writers can append or rebuild without supplying eligibility. The existing transcript reconciler detects their NULL rows even when its sequence watermark is current, then rebuilds from raw events before publishing readiness. Readers return a retryable projection-unavailable result while this work is pending; they do not parse every payload or guess eligibility. Initial index creation scans projection metadata once, and startup awaits reconciliation with off-thread parsing and bounded write chunks. Total rebuild cost remains proportional to history. Rewrites invalidate or rebuild the projection in their own transaction, and transcript deletion removes its eligibility rows. Downgrade leaves the additive column and index intact; re-upgrade reconciles unknown rows. User profiles use the same rule for the nullable bare user_profiles.role TEXT column in state schema 9. Operator-role assignment lazily ensures the column on first use. Older readers ignore the column and can reopen the same database safely. Web Push subscription ownership uses the same rule for nullable bare web_push_subscriptions.device_id TEXT, user_profile_id TEXT, and preferences_json TEXT columns. Web Push lazily ensures all three columns on first use. Existing rows remain unbound and test-only until the browser reconnects; older readers ignore the columns and continue reading or updating the endpoint and key fields safely. Approval-notification cleanup uses the same-version additive web_push_approval_deliveries table. It records the approval/subscription identifiers plus the request-time device/profile binding for notifications that may have reached a browser. A terminal or restarted Gateway sends only when the current subscription still has that binding. The table is lazily created on first use, rows cascade away with their approval or subscription, and older readers ignore it safely. Installing OpenClaw manually through npm bypasses the updater guard. Database open checks still refuse an incompatible build. Structured Goal controls use a lazy per-agent session_goal_operations table without changing the schema version. Goal start/resume commits the Goal transition, input turn, run lifecycle, and operation receipt in one transaction. Management operations commit the Goal transition and receipt together. Older readers ignore the added table. Receipts survive Goal clear and session reset/deletion until their 24-hour validity expires; later Goal writes prune expired rows. They retain the original result and a keyed request fingerprint, not a second raw request. There is no backfill or configuration switch. Downgrading preserves the table but disables the new structured controls; upgrading can read retained receipts.

Review checkpoint for material changes

Before implementing a material SQLite or persistent-store change, open or link a maintainer discussion and record acceptance of the design. A schema-version bump is always material, but a change can be material even when the numeric version stays the same. Treat a change as material when it introduces or materially changes any of these:
  • a table, dedicated database, durable projection, cache, index, or other persisted representation
  • which data is canonical, derived, reconstructible, retained, deleted, exported, or visible after restart
  • user-visible persistence semantics, including a second interpretation of existing durable data
  • migration, backfill, repair, downgrade, rollback, retention, compaction, or corruption recovery
  • transaction boundaries, writer ownership, concurrency, locking, publication fencing, or reader consistency
  • read, write, disk, startup, or maintenance cost enough to affect the store’s operating model
The discussion should identify the owning store and lifecycle, the problem being solved, alternatives that avoid new persistence, canonical versus derived data, schema and upgrade/downgrade behavior, retention and deletion behavior, concurrency and recovery invariants, performance/storage impact, rollback plan, and validation limits. The implementing PR must link the accepted decision. The checkpoint normally does not apply to a read-only query that preserves existing semantics, a bounded query-plan improvement with no material write/disk tradeoff, routine maintenance of an existing approved schema, or tests, generated baselines, and documentation that only follow an already accepted design. A mechanical migration or repair still links the decision that approved its persistent contract. For an urgent data-loss, security, or recovery fix, a maintainer may authorize a narrowly scoped exception before implementation. The appropriate public or private review record must capture the reason, temporary scope, rollback and validation plan, and any follow-up needed for the full design decision. The exception accelerates the design record; it does not waive review before merge.

Preflight a target release

Before activating or rolling back a release, run that target release’s CLI against one explicit copied state database:
The command does not read the default state directory or mutate the supplied file. It opens the supplied consolidated file as immutable/read-only, compares the target release’s own schema contract, and reports one status:
  • exact: the copied database matches the target release’s runtime schema. Feature-local tables that are intentionally absent until first use do not require repair.
  • startup-repairable: the numeric version matches and a runtime-owned additive difference remains; startup needs a write to converge the shape.
  • migration-required: the database is older than the target release.
  • incompatible: the database is newer, or its same-version shape has blocking drift such as an unexpected column.
  • indeterminate: the file, integrity metadata, or ownership metadata could not be verified.
JSON output is identified by schema: "openclaw.state-schema-preflight.v1". Use a SQLite online backup or another WAL-aware snapshot produced while the source is safely coordinated. The resulting preflight input must be one consolidated file with no sibling -wal, -shm, or -journal; sidecars make the result indeterminate. Do not copy only the main .sqlite file from an active WAL database. Preflight the exact runtime that will be activated; a package version or numeric schema version alone does not prove same-version shape compatibility.

Agent schema history

Version 3 was an unshipped development step folded into version 4.

Creator namespace migration

Agent schema 19 and shared-state schema 14 add a source discriminator to human creator actors in the existing session and cron JSON records. No table, sidecar, or separate identity ledger is added. The session node remains the immutable creator owner; mutable owner assignments and explicit sharing grants are unchanged. Historical human creators stamped directly by operator or run creation become profile; channel creation becomes channel. Origin-losing cron, inherited spawn or Talk, legacy createdBy, and missing-source history remain unknown. The migration preserves IDs, attribution, creation times, content, and existing sandbox restrictions. A UUID, profile lookup, participant, current route, or required sandbox never supplies missing creator authority. Recovery from incomplete physical projections also produces unknown human attribution. Before upgrading, stop the Gateway and all other writers, then create and verify a WAL-aware backup. Run openclaw doctor --fix with the new build. The agent migration retains the stopped-writer maintenance gate and runs after the schema-18 participant migration, without rebuilding already migrated participant rows. Canonical data and both schema markers commit in the owning database transaction. Shared-state and agent databases are separate transactions; if one fails, keep writers stopped and rerun Doctor before starting the Gateway. Older builds refuse the new versions. For rollback, stop all writers and restore the verified pre-upgrade backups with their matching older build. Do not decrement either schema marker: an older writer cannot maintain the creator-source contract. Unknown historical provenance is irrecoverable from the stored ID alone. Administrators retain sharing management access; assigning responsibility does not restore an implicit creator grant. Required sandbox resources keep their existing keys for proven profile creators. Channel and unknown creators instead use canonical-session isolation, with no new persisted principal field. Their old ambiguous resources are left untouched by migration, not automatically adopted or copied; operators must recover needed files explicitly before ordinary retention or cleanup. See sandbox scope and recovery.

Participant identity migration

Agent schema 18 rebuilds session_participants with the unique key (session_key, identity_namespace, actor_id). The raw actor ID remains separate from its namespace. This replaces the old (session_key, actor_type, actor_id) key; it is not a same-version additive change. Both schema markers advance together. No companion table or per-input ledger is added. Before upgrading existing data, take a verified, WAL-aware backup and stop the Gateway and other agent-database writers. Run openclaw doctor --fix with the new build. The migration uses the existing maintenance lease to reject active writers and fence new claims. Ordinary runtime opens refuse the old participant schema rather than migrating it behind active readers. Earlier structural and media migrations run in their historical order before participant convergence. Explicit Doctor repair exits nonzero if an existing configured, default-layout, or registered database still fails runtime schema readiness, including when a live writer or an unknown table dependency blocks this migration. Readiness uses the same target discovery as migration without registering, pruning, or creating stores. Archive migration warnings remain advisory when required database schemas are ready. Membership and recorded contribution aggregates survive. Historical profile timestamps are unknown because earlier source promotion could contaminate them even when a contribution count was present. Supported agent and channel-only observation times remain; an unresolved historical channel domain stays unresolved. Migration does not invent missing channel rows or inspect transcripts to reconstruct identities. New observations do not turn an unknown first input time into a claimed first-ever time. The rebuild, data copy, version markers, and foreign-key validation commit atomically. Unknown table shapes or database-local dependents are refused. A failed migration rolls back rather than leaving a partial replacement table. Older builds refuse schema 18; do not decrement either version marker or restore the old unique key. Downgrade recovery requires the verified pre-migration backup. Normal admission remains bounded at 32 identities. Same-store alias repair sums aggregates; retryable cross-store copies retain the larger recorded aggregate. Repairs preserve already-retained histories above the admission bound. Reset retains logical-session participation, while deletion removes it with the session node.

State schema history

State schema 15

Schema 15 removes target_agent_id and target_session_id from current_conversation_bindings. The target index uses the complete target_session_key and remains non-unique: several conversations may point at the same destination. This lets plugin-owned targets persist without inventing an OpenClaw agent owner. Channel/account isolation, plugin approvals, binding identifiers, target keys, JSON metadata, expiry, and detach behavior are unchanged. Startup and openclaw doctor --fix run the migration in the existing exclusive write transaction. They remove only the two projections and replace the target index, preserving all other row values. A dependent trigger, index, or failed schema check rolls the transaction back; migration does not discard an unknown dependency to force the upgrade. Column removal rewrites the binding table, so upgrade cost scales with its size. Stop older writers and create a verified, WAL-aware backup before upgrading. Builds supporting shared-state schema 14 or earlier refuse the migrated database. To return to an older build, restore that pre-upgrade backup into a separate state directory; do not lower the version markers or reconstruct an agent projection. See downgrade limitations for the general recovery contract.

State schema 13

Schema 13 makes cron_jobs.job_json, cron_jobs.state_json, and subagent_runs.payload_json the canonical records. Physical columns remain only where production queries, ordering, or runtime-only updates require them. Cron jobs shrink from 75 columns to 15, and subagent runs shrink from 59 columns to six. Migration preserves failure-destination fields explicitly configured as undefined by encoding them as JSON null; it also normalizes legacy run-status aliases into state_json before removing the redundant projections. The shared-state auth_profile_stores and auth_profile_state singletons move into config_machine_state under authProfiles.store and authProfiles.state; per-agent auth tables remain unchanged. Because these rows contain credentials, secret-redacted Git backups omit the authProfiles. machine-state prefix.

State schema 11

Schema 11 removes the skill_lifecycle and skill_workshop_proposal_origin_runs tables. Archived-skill lifecycle state is discarded during the upgrade: previously archived Workshop skills return to the active collection, where weekly collection review judges them by content. The origin-run rows were a never-read projection; canonical proposal provenance stays in skill_workshop_proposals.record_json. Recorded skill usage and collection-review state are preserved.

State schema 9

Schema 9 stores an agent_databases.path value relative to the state directory when the registered agent database is inside that directory. During migration, a foreign default-layout row is re-anchored to the in-root counterpart when that file exists. It is deleted only when the same agent already holds its in-root registration, because dual default-layout registrations cannot produce a valid combined session list. Otherwise, the absolute row is preserved, so genuine external registrations are never deleted. This keeps a copied state directory self-contained without dropping supported external database paths.

Integrity checks

The Gateway startup preflight reads schema headers only. openclaw database preflight performs the release-local shape comparison for an explicit copied file. The background verifier owns the slower recurring full scan for live databases that do not need migration. Quarantine decisions live only in a dedicated openclaw-quarantine.sqlite store, so they survive damage to the databases being quarantined. Verification results are logged.

Troubleshooting

Why you cannot go back after updating to 2026.7.2

Every release through v2026.7.1 used agent schema 1 and state schema 1. The 2026.7.2 release train (starting with v2026.7.2-beta.1) migrates your databases forward on first start. That migration is one-way: the data is rewritten into the newer schema, and installing an older OpenClaw afterwards does not undo it. The older build refuses to start with a newer schema version error that names the build that owns the database. Downgrading the binary never downgrades the data. If you must run a release older than 2026.7.2 after updating, you have three options:
  1. Restore a backup taken before the update. Create and verify backups before major updates.
  2. Run the older build against a separate state directory (OPENCLAW_STATE_DIR). It starts fresh; your migrated data stays untouched for when you return to the newer build.
  3. Follow the manual downgrade procedure below. It is unsupported and risks data loss without a verified backup.
Since 2026.7.2, openclaw update refuses to install a release that cannot open your current databases, so the updater will not put you in this situation. Installing an older version manually through npm bypasses that guard; the databases still refuse the old binary, but only after it is installed.

The Gateway refuses to start with a newer schema version error

A newer OpenClaw build wrote your databases, and the running build is older. The error names the refusing install — release version, commit, and install root — plus the schema it supports and the schema it found. Act on the install root, not the version. One release version string spans many main commits, schema levels, and same-version schema shapes, so two installs can both call themselves 2026.7.2 and still disagree about a database. A prerelease version may not exist on the latest npm tag at all: check npm view openclaw dist-tags before reinstalling, because the tag carrying the schema you need may be beta, and reinstalling from latest can move you further away. When a Gateway runs from a linked source checkout, its status and schema-refusal diagnostics report the commit captured when dist/ was built, not the checkout’s current Git HEAD. If that build identity is unknown, rebuild the checkout (pnpm build) before concluding the version is wrong. Open the database with a build that supports its schema, or point the older build at a separate OPENCLAW_STATE_DIR. Do not edit the database to silence the error. Config reads also save health fingerprints to this database. If that write fails, Config health-state write failed reports the first failure for that database in the current process. Repeated identical failures are suppressed while writes continue to be attempted. A different error, or a failure after a successful health-state write, is reported again. Suppressing duplicates does not resolve the underlying database error.

A database is quarantined after integrity verification failed

The background verifier proved the file is corrupt, and every open now fails fast instead of rescanning. Restore the database from a backup or repair it, then run openclaw doctor --fix to clear the quarantine record. Doctor reports an explicit error if the quarantine record itself cannot be cleared; rerun it until it reports clean.

Downgrades are unsupported

Manual schema downgrades are for agents and operators who accept the risk. Create and verify a backup before editing any database. Stop the Gateway and every process that can open the database. The general procedure is:
  1. Read the target release’s schema and migrations.
  2. In one transaction, restore the target release’s exact table, column, index, and trigger definitions; remove newer objects and recreate objects retired by subsequent upgrades.
  3. Set PRAGMA user_version and schema_meta.schema_version to the target version.
  4. Run the target release’s full database verification before starting the Gateway.

Example: state schema 13 to 12

Schema 13 removed 60 cron-job projection columns, 53 subagent-run projection columns, and five unused indexes. A schema 12 build still expects the exact original column definitions, ordering, and indexes. Adding the removed required columns with defaults produces a different schema that older builds reject, so rebuild both tables instead. Reproject every v12 cron field from canonical job_json and state_json; abort before rebuilding when either record is malformed. Disable foreign-key enforcement before starting the transaction. The cron-runtime authority table references cron_jobs with ON DELETE CASCADE, so dropping the original table while enforcement is active would silently delete its authority rows. Re-enable enforcement after the rebuild commits, and verify that PRAGMA foreign_key_check; returns no rows before starting the older build. Run equivalent SQL against the global state database after inspecting the exact schema that wrote it:
The recreated cron columns are recovered from canonical JSON, including schedule and payload variants, explicit failure-destination clears, boolean false, numeric thread IDs, and runtime state. Canonical JSON bytes remain unchanged. Subagent-run state remains in payload_json; its retired projections are not runtime scheduling inputs. A botched downgrade means restore from the verified backup.

Example: state schema 12 to 11

Schema 12 folded durable state snapshots into config_machine_state and retired rebuildable caches plus the write-only cron store epoch table. A schema 11 build still expects the thirteen former tables, so a manual downgrade must recreate their exact schemas and indexes before lowering the version. Run equivalent SQL against the global state database after inspecting the exact schema that wrote it:
The recreated tables start empty. Migrated voice wake settings, onboarding recommendations, update-check state, sidebar layout, node-host identity, and Web Push signing keys remain readable in config_machine_state under voicewake.triggers, voicewake.routing, onboarding.recommendations.<workspaceKey>, update.checkState, sidebar.sectionOrder, nodeHost.config, and webPush.vapidKeys; manually repopulate their former tables if the older build must retain those settings. Node-host identity and Web Push signing keys are sensitive: avoid copying their values into shell history or logs. Skill-curator, promotions-feed, remote-catalog, and TUI last-session caches can be rebuilt. A botched downgrade means restore from the verified backup.

Example: state schema 11 to 10

Schema 11 removed the retired skill lifecycle table and the never-read proposal origin-run projection. A schema 10 build still requires both canonical tables, so a manual downgrade must recreate their exact empty schemas and lifecycle indexes before lowering the version. Run equivalent SQL against the global state database after inspecting the exact schema that wrote it:
Both recreated tables start empty. The upgrade discarded archived-skill lifecycle state, so those skills returned to the active collection and a manual downgrade cannot recover their previous archived state. Proposal origin-run rows were never read; authoritative provenance remains in each proposal’s record_json. A botched downgrade means restore from the verified backup.

Example: state schema 10 to 9

Schema 10 removed six dead shared-state tables. A schema 9 build still requires those canonical tables and indexes, so a manual downgrade must recreate their exact empty schemas before lowering the version. Run equivalent SQL against the global state database after inspecting the exact schema that wrote it:
The recreated tables start empty because schema 10 discarded only dead or rebuildable cache rows. A botched downgrade means restore from the verified backup.

Example: state schema 9 to 8

Schema 8 expects every agent_databases.path value to be absolute. Before lowering user_version, inspect each registry row on the same platform that wrote it. Leave absolute external paths unchanged; replace every relative path with its platform-native absolute form by resolving it against the state directory that owns state/openclaw.sqlite. Then set both PRAGMA user_version and schema_meta.schema_version to 8 in the same transaction. Do not lower the version while relative registry rows remain. A schema 8 build interprets them relative to its process working directory rather than the copied state directory.

Example: state schema 7 to 6

Schema 7 irreversibly discarded every row in the retired shared commitments table, then removed the table and its indexes. A schema 6 build still requires that canonical table, so a manual downgrade can recreate only its exact empty schema before lowering the version. Restore a verified pre-upgrade backup if the discarded rows are required. Run equivalent SQL against the global state database after inspecting the exact schema that wrote it:
The recreated table starts empty. The downgrade cannot recover discarded commitment rows.

Example: agent schema 17 to 16

Schema 17 removed the tenant-free per-agent lease table. A schema 16 build still requires that canonical table, so a manual downgrade must recreate its exact schema before lowering the version. Run equivalent SQL against each affected per-agent database after inspecting the exact schema that wrote it:
The recreated table starts empty because schema 17 has no agent-DB lease tenants to preserve. A botched downgrade means restore from the verified backup.