Plugin Compatibility Contracts and Migration
Learn how OpenClaw maintains older plugin contracts through compatibility adapters and a registry. Essential for plugin maintainers and SDK developers.
Read this when
- You maintain an OpenClaw plugin
- You see a plugin compatibility warning
- You are planning a plugin SDK or manifest migration
OpenClaw maintains older plugin contracts through named compatibility adapters prior to their eventual removal. This approach safeguards both bundled and third-party plugins while the SDK, manifest, setup, config, and agent runtime contracts continue to evolve.
Compatibility registry
The core registry at src/plugins/compat/registry.ts tracks plugin compatibility contracts. Each entry contains:
- a stable compatibility code
- status:
active,deprecated,removal-pending, orremoved - owner:
sdk,config,setup,channel,provider,plugin-execution,agent-runtime, orcore - introduction and deprecation dates where applicable
- an exact
removeAfterdate or namedremovalGateonce approved by the owning maintainer; a record lacking both stays ineligible for removal - replacement guidance
- docs, diagnostics, and tests covering both the old and new behavior
Maintainers use this registry as their planning source, and future plugin inspector checks will rely on it too. Whenever a plugin-facing behavior shifts, the compatibility record must be added or updated in the same change that introduces the adapter.
Doctor repair and migration compatibility get tracked separately at src/commands/doctor/shared/deprecation-compat.ts. These entries cover old config shapes, install-ledger layouts, and repair shims that might need to remain available after the runtime compatibility path is gone.
Every doctor compatibility record declares introduced and removeAfter.
The pnpm check:doctor-deprecation-registry guard triggers a failure when a record is still
deprecated on or after removeAfter; maintainers must either remove it after
supported-upgrade proof or shift it to removal-pending with a documented
blocker. removal-pending records escape the date guard failure but stay in the
explicit review queue until their upgrade conditions are satisfied.
Release sweeps should inspect both registries. A doctor migration should not be deleted just because the matching runtime or config compatibility record has expired; first confirm no supported upgrade path still depends on the repair. During release planning, revalidate each replacement annotation as well, since plugin ownership and config footprint can shift when providers and channels leave core.
Deprecation policy
OpenClaw must not remove a documented plugin contract in the same release that brings in its replacement. The migration sequence:
- Introduce the new contract.
- Keep the old behavior connected through a named compatibility adapter.
- Emit diagnostics or warnings where plugin authors can take action.
- Document the replacement and its timeline.
- Test both the old and new paths.
- Wait through the announced migration window.
- Remove only with explicit breaking-release approval.
Deprecated records need a warning start date, replacement, docs link, and either a final removal date no later than three months after the warning begins or an explicit version boundary such as next-plugin-sdk-major. A deprecated compatibility path with an open-ended removal window is not allowed unless maintainers explicitly designate it as permanent compatibility and label it active instead.
Current compatibility areas
The July 2026 sweep removed the expired root SDK, manifest, provider, runtime, registry-flag, and plugin-owned web-config aliases. Doctor migrations remain separately tracked so supported upgrade paths can still repair old config.
The remaining dated compatibility areas are:
- the September SDK subpath window described in the migration guide
- the beta.5 session-store bridge
- the shipped agent-harness SDK aliases, whose removal awaits a new externally documented migration decision
- the October 2026 SDK annotation families listed below
Active, undated registry records cover supported behavior rather than removal debt, including activation hints, plugin capture, bundled plugin enablement, and the generated channel-config fallback.
The annotation-only compatibility audit added these dated records. Their removeAfter date marks the earliest review date, not authorization to remove a surface while its stated reader or migration condition remains unmet.
| Compatibility code | Removal condition | removeAfter |
|---|---|---|
plugin-sdk-channel-setup-input-fields | Repeat the published-plugin artifact sweep and remove only fields with no reader. | 2026-10-01 |
plugin-sdk-broad-runtime-barrels | Move bundled and indexed external consumers to focused SDK subpaths. | 2026-10-01 |
plugin-sdk-provider-owned-helper-shims | Move each deprecated provider helper to its provider-local API and prove no published reader remains. | 2026-10-01 |
message-presentation-legacy-bridges | Move reply producers and official channel packages to MessagePresentation. | 2026-10-01 |
plugin-sdk-focused-compat-aliases | Prove every enumerated alias has no bundled or published reader. | 2026-10-01 |
agent-harness-terminal-result-aliases | Move harnesses to terminal and visibleReplies, then prove the legacy result fields are unread. | 2026-10-01 |
official-plugin-export-aliases | Move users of Google Meet testing, channel presentation, and Discord timeout exports to canonical APIs. | 2026-10-01 |
memory-host-compatibility-aliases | Use canonical memory tables and prepared runtime config everywhere. | 2026-10-01 |
plugin-runtime-api-compat-aliases | Move flat plugin registration/runtime calls to their namespaced or focused replacements. | 2026-10-01 |
plugin-provider-manifest-compat-aliases | Move kind/setup/catalog ownership to manifests and model-catalog registration. | 2026-10-01 |
deprecated-session-store-beta5-api | End the v2026.7.x whole-store upgrade window, including package-root aliases. | 2026-10-12 |
pnpm plugins:boundary-report reports removal-pending records separately
from deprecated records. A due removal-pending record remains blocked until
its reported migration condition is satisfied and its reader references are
cleared; the existing --fail-on-eligible-compat gate continues to apply only
to dated deprecated records. Reader references are surface-token matches for
triage; use the published-artifact sweep before authorizing removal.
Auth profile cooldown classifications
AuthProfileStore.usageStats[*].cooldownReason remains the closed canonical
AuthProfileFailureReason union. Host policy records WHAM HTTP 401 as auth
and HTTP 403 as auth_permanent.
cooldownClassification is an optional additive host diagnostic. Its current
values are wham_token_expired and wham_account_dead. Plugins that display
this field must keep a default or fallback for future optional classifications.
Canonical failover uses resolveProfilesUnavailableReason; the diagnostic is
presentation state only and must never be used as authorization.
Channel prompt-context identifier aliases
New channel plugins are expected to adopt MsgContext.ChannelPromptContext,
MsgContext.ChannelStructuredContext, ChannelStructuredContextEntry, and
SupplementalContextFacts.channelStructuredContext. The legacy
UntrustedContext, UntrustedStructuredContext,
UntrustedStructuredContextEntry, and supplementary untrustedContext designations
persist as deprecated SDK aliases through 2026-09-08 (registry entry
sdk-untrusted-context-identifier-aliases). During inbound finalization, those outdated fields get merged into
the channel-named equivalents, and the original keys disappear from runtime
context.
On the same timeline, the security runtime exposes buildChannelMetadata, with the
deprecated buildUntrustedChannelMetadata alias still accessible.
WhatsApp inbound callback retirement
The WhatsApp callback compatibility window from August 2026 has ended.
Runtime callbacks exclusively accept WebInboundCallbackMessage now: nested event,
payload, quote, group, and platform contexts, along with the mandatory
public admission envelope. Flat callback fields and top-level admission
aliases are rejected outright.
From inbound provider payloads, payload.channelStructuredContext gets pulled out.
Before relying on its payload as definitive, plugins need to examine
label, source, and type.
Plugin inspector package
Position the plugin inspector as a standalone package or repository outside the core OpenClaw repo, grounded in the versioned compatibility and manifest contracts. The initial CLI should look like:
openclaw-plugin-inspector ./my-plugin
It needs to produce manifest and schema validation, the contract
compatibility version under review, install and source metadata checks,
cold-path import checks, and deprecation or compatibility warnings. For
stable machine-readable output in CI annotations, rely on --json. OpenClaw
core should supply contracts and fixtures for the inspector to consume, but
the main openclaw package should not ship the inspector binary.
Maintainer acceptance lane
When validating the external inspector against OpenClaw plugin packages, employ Crabbox-backed Blacksmith Testbox for the installable-package acceptance lane. Execute it from a pristine OpenClaw checkout once the package is built:
pnpm crabbox:run -- --provider blacksmith-testbox --timing-json --shell -- "pnpm install && pnpm build && npm exec --yes @openclaw/plugin-inspector@0.1.0 -- ./extensions/telegram --json"
pnpm crabbox:run -- --provider blacksmith-testbox --timing-json --shell -- "npm exec --yes @openclaw/plugin-inspector@0.1.0 -- ./extensions/discord --json"
pnpm crabbox:run -- --provider blacksmith-testbox --timing-json --shell -- "npm exec --yes @openclaw/plugin-inspector@0.1.0 -- <clawhub-plugin-dir> --json"
Maintainers should treat this lane as opt-in, given that it pulls in an external npm package and might examine plugin packages cloned beyond the repo. The local repo guards handle the SDK export map, compatibility registry metadata, deprecated SDK-import burn-down, and bundled extension import boundaries; the Testbox inspector proof covers the package as external plugin authors experience it.
Release notes
Release notes ought to list upcoming plugin deprecations, complete with
target dates and migration doc links, prior to any compatibility path
shifting to removal-pending or removed.