Skip to main content
Checks 0-2 cover config normalization and the legacy config key migrations, plus how doctor publishes shared-state schema during an update.

Schema publication during a 2026.9.2 update

When OpenClaw 2026.9.2 drives an update that needs a newer shared-state schema, Doctor applies the migration content and reports schema content applied; version publication deferred until update run <id> finishes. The old updater can finish its ledger access, while the new Gateway uses the migrated content. Publication waits until all affected terminal runs are at least five minutes old; a running row unchanged for more than 30 minutes counts as abandoned. Every writable database open follows this rule, and the Gateway watcher schedules publication after the deadline. Ordinary CLI commands, including Doctor, remain usable while that Gateway runs. Applied content counts as ready; only the owning Gateway, or a writable opener when no Gateway owns the state directory, publishes the version after the grace. Deferral does not cover agent-database migrations. Doctor reports update-schema-bump-unfenced if one is pending, if the required shared-state metadata table is missing, or if the content migration fails. Follow the manual update sequence from the refusal. See Database schemas for the publication contract and the remaining risk for an old CLI stalled beyond the grace period.

Checks 0-2

If this is a git checkout and doctor is running interactively, it offers to update (fetch/rebase/build) before running doctor.
Doctor normalizes legacy value shapes into the current schema. Current Talk speech config is talk.provider + talk.providers.<provider>, with realtime voice config under talk.realtime.*. Doctor rewrites old talk.voiceId / talk.voiceAliases / talk.modelId / talk.outputFormat / talk.apiKey shapes into the provider map, and rewrites legacy top-level realtime selectors (talk.mode, talk.transport, talk.brain, talk.model, talk.voice) into talk.realtime.Doctor also warns when plugins.allow is non-empty and tool policy uses wildcard or plugin-owned tool entries. tools.allow: ["*"] only matches tools from plugins that actually load; it does not bypass the exclusive plugin allowlist.doctor --fix removes workspace: null from agents.entries.<id> so normal workspace resolution can apply. It also removes invalid heartbeat.activeHours windows from agent entries and agents.defaults, preserving other heartbeat settings. Reconfigure a valid window if needed; without an explicit or inherited window, heartbeat hours are unrestricted. These repairs also apply after migrating a legacy agents.list roster.
Gateway startup automatically applies deterministic, prompt-free legacy config migrations when an otherwise invalid single-file config can be fully migrated. It uses the same migration transforms as openclaw doctor --fix, validates the complete result including plugin config before writing, and reports the applied changes. The write runs under the startup migration lease and preserves the previous config in the five-slot openclaw.json.bak / .bak.1 through .bak.4 backup ring.Startup does not migrate configs using $include, configs in Nix mode, or configs last written by a newer OpenClaw version. It also skips automatic config migration while an update is in progress and plugin validation is deferred; the post-update doctor run owns that repair. If any validation or legacy-key issue remains after migration, startup leaves the config unchanged, refuses to start, and prints the openclaw doctor --fix hint. An interactive terminal can still offer to run doctor and retry once for configs that need other repairs; headless services stop with the hint.Other commands that encounter legacy keys still ask you to run openclaw doctor. Doctor explains the issues, shows its migrations, and rewrites ~/.openclaw/openclaw.json with the updated schema. Cron job store migrations are also handled by openclaw doctor --fix; automatic config-key migration does not import legacy session stores or repair services.When a readable active config can be fully migrated, Doctor preserves it before considering last-known-good recovery. This includes legacy multi-agent rosters with a default: true owner: unrelated settings and the original agent ownership survive the migration.Per-agent migrations apply to both keyed agents.entries and legacy agents.list rosters, including rosters that already set agents.ownership: "explicit". For example, Doctor preserves an agent’s legacy memorySearch settings under memory.search and converts sandbox.perSession to sandbox.scope. Existing values at the current config paths take precedence.For legacy rosters with multiple agents and no resolvable ambient owner, Doctor seeds agents.defaults.systemAgent.agentId from a uniquely marked default: true agent, or main when present. Sole-agent rosters and legacy default markers already honored by the runtime need no owner repair and produce no missing-owner advice. Explicit fleet ownership disables the legacy default-marker fallback, so those rosters may still need repair. Doctor also pins agents.defaults.heartbeat.agentId only when heartbeat enrollment would otherwise be unresolved; existing heartbeat owners, shared defaults, and per-agent enrollment are preserved. These changes are reported and saved by doctor --fix, including the update-time doctor pass. If no default can be identified, configure the system-agent owner explicitly.
Doctor only carries automatic migrations for roughly two months after a key is retired. Older legacy keys (for example the original routing.queue, routing.bindings, routing.agents/defaultAgentId, routing.transcribeAudio, top-level agent.*, or top-level identity from the pre-multi-agent config shape) no longer have a migration path; config using them now fails validation instead of being rewritten. Fix those keys by hand against the current config reference before doctor can proceed.
Active migrations:
The Voice Call plugin supplies the migration for its legacy config keys. openclaw doctor --fix invokes it and persists the canonical shape in openclaw.json; runtime config parsing accepts only current keys. Existing canonical settings win over legacy values, including streaming provider credentials, models, and timing. Doctor reports retained destinations instead of claiming those legacy values were moved.
Per-agent memorySearch migrations work with both old agents.list rosters and keyed agents.entries. Doctor preserves explicit memory.search settings when merging legacy values, including environment references moved to the new paths. When repairs affect only per-agent settings, single-file agent includes stay in their included file.The retired tools.message.allowCrossContextSend flag migrates at both root and per-agent scopes. Doctor preserves the effective cross-context permissions, including an agent’s false override of a root true flag.Account-default guidance for multi-account channels:
  • If two or more channels.<channel>.accounts entries are configured without channels.<channel>.defaultAccount or accounts.default, doctor warns that fallback routing can pick an unexpected account.
  • If channels.<channel>.defaultAccount is set to an unknown account ID, doctor warns and lists configured account IDs.
In multi-agent configs, doctor --fix adds a missing account-scoped routing binding when all matchable narrower bindings for that channel/account explicitly name one configured agent. Existing routes remain unchanged. Accounts with no owner evidence or conflicting owners need an explicit binding; Doctor does not infer their owner from roster order or another channel/account.