mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-22 14:38:09 +00:00
219 lines
10 KiB
Markdown
219 lines
10 KiB
Markdown
---
|
|
summary: "Plugin compatibility contracts, deprecation metadata, and migration expectations"
|
|
title: "Plugin compatibility"
|
|
read_when:
|
|
- You maintain an OpenClaw plugin
|
|
- You see a plugin compatibility warning
|
|
- You are planning a plugin SDK or manifest migration
|
|
---
|
|
|
|
OpenClaw keeps older plugin contracts wired through named compatibility
|
|
adapters before removing them. This protects existing bundled and external
|
|
plugins while the SDK, manifest, setup, config, and agent runtime contracts
|
|
evolve.
|
|
|
|
## Compatibility registry
|
|
|
|
Plugin compatibility contracts are tracked in the core registry at
|
|
`src/plugins/compat/registry.ts`.
|
|
|
|
Each record has:
|
|
|
|
- a stable compatibility code
|
|
- status: `active`, `deprecated`, `removal-pending`, or `removed`
|
|
- owner: SDK, config, setup, channel, provider, plugin execution, agent runtime,
|
|
or core
|
|
- introduction and deprecation dates when applicable
|
|
- replacement guidance
|
|
- docs, diagnostics, and tests that cover the old and new behavior
|
|
|
|
The registry is the source for maintainer planning and future plugin inspector
|
|
checks. If a plugin-facing behavior changes, add or update the compatibility
|
|
record in the same change that adds the adapter.
|
|
|
|
Doctor repair and migration compatibility is tracked separately at
|
|
`src/commands/doctor/shared/deprecation-compat.ts`. Those records cover old
|
|
config shapes, install-ledger layouts, and repair shims that may need to stay
|
|
available after the runtime compatibility path is removed.
|
|
|
|
Release sweeps should check both registries. Do not delete a doctor migration
|
|
just because the matching runtime or config compatibility record expired; first
|
|
verify there is no supported upgrade path that still needs the repair. Also
|
|
revalidate each replacement annotation during release planning because plugin
|
|
ownership and config footprint can change as providers and channels move out of
|
|
core.
|
|
|
|
## Plugin inspector package
|
|
|
|
The plugin inspector should live outside the core OpenClaw repo as a separate
|
|
package/repository backed by the versioned compatibility and manifest
|
|
contracts.
|
|
|
|
The day-one CLI should be:
|
|
|
|
```sh
|
|
openclaw-plugin-inspector ./my-plugin
|
|
```
|
|
|
|
It should emit:
|
|
|
|
- manifest/schema validation
|
|
- the contract compatibility version being checked
|
|
- install/source metadata checks
|
|
- cold-path import checks
|
|
- deprecation and compatibility warnings
|
|
|
|
Use `--json` for stable machine-readable output in CI annotations. OpenClaw
|
|
core should expose contracts and fixtures the inspector can consume, but should
|
|
not publish the inspector binary from the main `openclaw` package.
|
|
|
|
### Maintainer acceptance lane
|
|
|
|
Use Crabbox-backed Blacksmith Testbox for the installable-package acceptance
|
|
lane when validating the external inspector against OpenClaw plugin packages.
|
|
Run it from a clean OpenClaw checkout after the package is built:
|
|
|
|
```sh
|
|
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"
|
|
```
|
|
|
|
Keep this lane opt-in for maintainers because it installs an external npm
|
|
package and may inspect plugin packages cloned outside the repo. The local repo
|
|
guards cover the SDK export map, compatibility registry metadata, deprecated
|
|
SDK-import burn-down, and bundled extension import boundaries; Testbox inspector
|
|
proof covers the package as external plugin authors consume it.
|
|
|
|
## Deprecation policy
|
|
|
|
OpenClaw should not remove a documented plugin contract in the same release
|
|
that introduces its replacement.
|
|
|
|
The migration sequence is:
|
|
|
|
1. Add the new contract.
|
|
2. Keep the old behavior wired through a named compatibility adapter.
|
|
3. Emit diagnostics or warnings when plugin authors can act.
|
|
4. Document the replacement and timeline.
|
|
5. Test both old and new paths.
|
|
6. Wait through the announced migration window.
|
|
7. Remove only with explicit breaking-release approval.
|
|
|
|
Deprecated records must include a warning start date, replacement, docs link,
|
|
and final removal date no more than three months after the warning starts. Do
|
|
not add a deprecated compatibility path with an open-ended removal window unless
|
|
maintainers explicitly decide it is permanent compatibility and mark it `active`
|
|
instead.
|
|
|
|
## Current compatibility areas
|
|
|
|
Current compatibility records include:
|
|
|
|
- legacy broad SDK imports such as `openclaw/plugin-sdk/compat`
|
|
- legacy hook-only plugin shapes and `before_agent_start`
|
|
- legacy `api.on("deactivate", ...)` cleanup hook names while plugins migrate to
|
|
`gateway_stop`
|
|
- legacy `activate(api)` plugin entrypoints while plugins migrate to
|
|
`register(api)`
|
|
- legacy SDK aliases such as `openclaw/extension-api`,
|
|
`openclaw/plugin-sdk/channel-runtime`, `openclaw/plugin-sdk/command-auth`
|
|
status builders, `openclaw/plugin-sdk/test-utils` (replaced by focused
|
|
`openclaw/plugin-sdk/*` test subpaths), and the `ClawdbotConfig` /
|
|
`OpenClawSchemaType` type aliases
|
|
- bundled plugin allowlist and enablement behavior
|
|
- legacy provider/channel env-var manifest metadata
|
|
- legacy provider plugin hooks and type aliases while providers move to
|
|
explicit catalog, auth, thinking, replay, and transport hooks
|
|
- legacy runtime aliases such as `api.runtime.taskFlow`,
|
|
`api.runtime.subagent.getSession`, `api.runtime.stt`, and deprecated
|
|
`api.runtime.config.loadConfig()` / `api.runtime.config.writeConfigFile(...)`
|
|
- WhatsApp `WebInboundMessage` flat callback fields such as `body`, `chatId`,
|
|
`reply(...)`, and `mediaPath` while callback consumers migrate to the nested
|
|
`WebInboundCallbackMessage` `event`, `payload`, `quote`, `group`, and
|
|
`platform` contexts
|
|
- WhatsApp `WebInboundMessage` top-level admission fields such as `from`,
|
|
`conversationId`, `accountId`, `accessControlPassed`, and `chatType` while
|
|
callback consumers migrate to the `admission` envelope
|
|
- legacy memory-plugin split registration while memory plugins move to
|
|
`registerMemoryCapability`
|
|
- legacy memory-specific embedding provider registration while embedding
|
|
providers move to `api.registerEmbeddingProvider(...)` and
|
|
`contracts.embeddingProviders`
|
|
- legacy channel SDK helpers for native message schemas, mention gating,
|
|
inbound envelope formatting, and approval capability nesting
|
|
- legacy channel route key and comparable-target helper aliases while plugins
|
|
move to `openclaw/plugin-sdk/channel-route`
|
|
- activation hints that are being replaced by manifest contribution ownership
|
|
- `setup-api` runtime fallback while setup descriptors move to cold
|
|
`setup.requiresRuntime: false` metadata
|
|
- provider `discovery` hooks while provider catalog hooks move to
|
|
`catalog.run(...)`
|
|
- channel `showConfigured` / `showInSetup` metadata while channel packages move
|
|
to `openclaw.channel.exposure`
|
|
- legacy runtime-policy config keys while doctor migrates operators to
|
|
`agentRuntime`
|
|
- generated bundled channel config metadata fallback while registry-first
|
|
`channelConfigs` metadata lands
|
|
- persisted plugin registry disable and install-migration env flags while
|
|
repair flows migrate operators to `openclaw plugins registry --refresh` and
|
|
`openclaw doctor --fix`
|
|
- legacy plugin-owned web search, web fetch, and x_search config paths while
|
|
doctor migrates them to `plugins.entries.<plugin>.config`
|
|
- legacy `plugins.installs` authored config and bundled plugin load-path
|
|
aliases while install metadata moves into the state-managed plugin ledger
|
|
|
|
New plugin code should prefer the replacement listed in the registry and in the
|
|
specific migration guide. Existing plugins can keep using a compatibility path
|
|
until the docs, diagnostics, and release notes announce a removal window.
|
|
|
|
### WhatsApp Inbound Callback Flat Aliases
|
|
|
|
WhatsApp runtime callbacks deliver `WebInboundMessage`: the canonical nested
|
|
`event`, `payload`, `quote`, `group`, and `platform` contexts plus deprecated
|
|
flat aliases for the shipped callback fields. New callback code should read the
|
|
nested contexts. Code that constructs clean nested callback messages can use
|
|
`WebInboundCallbackMessage`; compatibility listeners that still inject old flat
|
|
test or plugin messages should use `LegacyFlatWebInboundMessage` or
|
|
`WebInboundMessageInput`.
|
|
|
|
The flat aliases remain available until **2026-08-30**. That removal window
|
|
applies only to flat alias access; the nested callback shape is the canonical
|
|
runtime contract. The TypeScript `@deprecated` annotations on each flat alias
|
|
name its exact nested replacement. Common examples:
|
|
|
|
- `id`, `timestamp`, and `isBatched` move under `event`.
|
|
- `body`, `mediaPath`, `mediaType`, `mediaFileName`, `mediaUrl`, `location`, and
|
|
`untrustedStructuredContext` move under `payload`.
|
|
- `to`, `chatId`, sender/self fields, `sendComposing`, `reply(...)`, and
|
|
`sendMedia(...)` move under `platform`.
|
|
- `replyTo*` fields move under `quote`, and group subject/participant/mention
|
|
fields move under `group`.
|
|
|
|
`payload.untrustedStructuredContext` is extracted from inbound provider payloads.
|
|
Plugins should inspect the `label`, `source`, and `type` before treating its
|
|
`payload` as authoritative.
|
|
|
|
### WhatsApp Inbound Admission Fields
|
|
|
|
Accepted WhatsApp callback messages now carry `admission`, a public-safe
|
|
envelope for the access-control decision that admitted the message. New callback
|
|
code should read admission facts from `msg.admission` instead of the older
|
|
top-level admission fields.
|
|
|
|
The top-level fields remain available until **2026-08-30**. The TypeScript
|
|
`@deprecated` annotations name each replacement:
|
|
|
|
- `from` and `conversationId` move to `admission.conversation.id`.
|
|
- `accountId` moves to `admission.accountId`.
|
|
- `accessControlPassed` is a derived compatibility view of
|
|
`admission.ingress.decision === "allow"`; on messages that already carry
|
|
`admission`, writing the legacy boolean does not rewrite the ingress graph.
|
|
- `chatType` moves to `admission.conversation.kind`.
|
|
|
|
## Release notes
|
|
|
|
Release notes should include upcoming plugin deprecations with target dates and
|
|
links to migration docs. That warning needs to happen before a compatibility
|
|
path moves to `removal-pending` or `removed`.
|