What changed
Two wide-open import surfaces used to let plugins reach almost anything from a single entry point:openclaw/plugin-sdk/compat- re-exported dozens of helpers to keep older hook-based plugins working while the new architecture was built.openclaw/plugin-sdk/infra-runtime- a broad barrel mixing system events, heartbeat state, delivery queues, fetch/proxy helpers, file helpers, approval types, and unrelated utilities.openclaw/plugin-sdk/config-runtime- a broad config barrel still carrying deprecated direct load/write helpers during the migration window.openclaw/extension-api- a bridge giving plugins direct access to host-side helpers like the embedded agent runner.api.registerEmbeddedExtensionFactory(...)- a removed embedded-runner-only hook that observed embedded-runner events such astool_result. Use agent tool-result middleware instead (see Migrate embedded tool-result extensions to middleware).
registerEmbeddedExtensionFactory has already been removed;
legacy registrations no longer load.
OpenClaw does not remove or reinterpret documented plugin behavior in the same
change that introduces a replacement. Breaking contract changes go through a
compatibility adapter, diagnostics, docs, and a deprecation window first. That
applies to SDK imports, manifest fields, setup APIs, hooks, and runtime
registration behavior.
Why
- Slow startup - importing one helper loaded dozens of unrelated modules.
- Circular dependencies - broad re-exports made import cycles easy to create.
- Unclear API surface - no way to tell stable exports from internal ones.
openclaw/plugin-sdk/<subpath> is now a small, self-contained module with
a documented contract.
Legacy provider convenience seams for bundled channels are gone too -
channel-branded helper shortcuts were private mono-repo conveniences, not
stable plugin contracts. Use narrow generic SDK subpaths instead. Inside the
bundled plugin workspace, keep provider-owned helpers in that plugin’s own
api.ts or runtime-api.ts:
- Anthropic keeps Claude-specific stream helpers in its own
api.ts/contract-api.tsseam. - OpenAI keeps provider builders, default-model helpers, and realtime provider
builders in its own
api.ts. - OpenRouter keeps provider builder and onboarding/config helpers in its own
api.ts.
Compatibility policy
External-plugin compatibility work follows this order:- Add the new contract.
- Keep the old behavior wired through a compatibility adapter.
- Emit a diagnostic or warning naming the old path and replacement.
- Cover both paths in tests.
- Document the deprecation and migration path.
- Remove only after the announced migration window, usually in a major release.
pnpm plugins:boundary-report:
pnpm plugins:boundary-report:ci runs with all three fail flags. Each
compatibility record has an explicit removeAfter date (not a vague “next
major release”) - the report groups deprecated records by that date, counts
local code/doc references, surfaces cross-owner reserved SDK imports, and
summarizes the private memory-host SDK bridge. Reserved SDK subpaths must have
tracked owner usage; unused reserved exports should be removed from the public
SDK.
How to migrate
Migrate runtime config load/write helpers
api.runtime.config.loadConfig() and
api.runtime.config.writeConfigFile(...) directly. Prefer config already
passed into the active call path. Long-lived handlers that need the
current process snapshot can use api.runtime.config.current(). Long-lived
agent tools should read ctx.getRuntimeConfig() inside execute so a tool
created before a config write still sees the refreshed config.Config writes go through the transactional helper with an explicit
after-write policy:afterWrite: { mode: "restart", reason: "..." } when the change needs
a clean gateway restart, and afterWrite: { mode: "none", reason: "..." }
only when the caller owns the follow-up and deliberately suppresses the
reload planner. Mutation results include a typed followUp summary for
tests and logging; the gateway remains responsible for applying or
scheduling the restart.loadConfig and writeConfigFile remain as deprecated compatibility
helpers for external plugins and warn once with the
runtime-config-load-write compatibility code. Bundled plugins and repo
runtime code are guarded by pnpm check:deprecated-api-usage and
pnpm check:no-runtime-action-load-config: new production plugin usage
fails outright, direct config writes fail, gateway server methods must use
the request runtime snapshot, runtime channel send/action/client helpers
must receive config from their boundary, and long-lived runtime modules
allow zero ambient loadConfig() calls.New plugin code should avoid the broad openclaw/plugin-sdk/config-runtime
barrel. Use the narrow subpath for the job:Migrate embedded tool-result extensions to middleware
api.registerEmbeddedExtensionFactory(...) tool-result handlers with
runtime-neutral middleware:contracts.agentToolResultMiddleware. Undeclared installed middleware
registrations are rejected.Migrate approval-native handlers to capability facts
approvalCapability.nativeRuntime plus the shared runtime-context
registry:- Replace
approvalCapability.handler.loadRuntime(...)withapprovalCapability.nativeRuntime. - Move approval-specific auth/delivery off legacy
plugin.auth/plugin.approvalswiring and ontoapprovalCapability. ChannelPlugin.approvalshas been removed from the public channel-plugin contract; move delivery/native/render fields ontoapprovalCapability.plugin.authremains for channel login/logout flows only; core no longer reads approval auth hooks there.- Register channel-owned runtime objects (clients, tokens, Bolt apps)
through
openclaw/plugin-sdk/channel-runtime-context. - Do not send plugin-owned reroute notices from native approval handlers; core owns routed-elsewhere notices from actual delivery results.
- When passing
channelRuntimeintocreateChannelManager(...), provide a realcreatePluginRuntime().channelsurface - partial stubs are rejected.
Audit Windows wrapper fallback behavior
openclaw/plugin-sdk/windows-spawn, unresolved Windows
.cmd/.bat wrappers now fail closed unless you explicitly pass
allowShellFallback: true:allowShellFallback and handle the thrown error instead.Find deprecated imports
Replace with focused imports
Replace broad infra-runtime imports
openclaw/plugin-sdk/infra-runtime still exists for external
compatibility, but new code should import the focused surface it actually
needs:infra-runtime, so repo code
cannot regress to the broad barrel.Migrate channel route helpers
openclaw/plugin-sdk/channel-route. The older
route-key and comparable-target names remain as compatibility aliases:{ channel, to, accountId, threadId }
consistently across native approvals, reply suppression, inbound dedupe,
cron delivery, and session routing.Do not add new uses of ChannelMessagingAdapter.parseExplicitTarget, the
parser-backed loaded-route helpers (parseExplicitTargetForLoadedChannel,
resolveRouteTargetForLoadedChannel), or
resolveChannelRouteTargetWithParser(...) from plugin-sdk/channel-route -
those are deprecated and remain only for older plugins. New channel
plugins should use messaging.targetResolver.resolveTarget(...) for
target-id normalization and directory-miss fallback,
messaging.inferTargetChatType(...) when core needs an early peer kind,
and messaging.resolveOutboundSessionRoute(...) for provider-native
session and thread identity.Build and test
Import path reference
Common import path table
Common import path table
scripts/lib/plugin-sdk-entrypoints.json;
package exports are generated from the public subset.
Reserved bundled-plugin helper seams have been retired from the public SDK
export map except for explicitly documented compatibility facades such as the
deprecated plugin-sdk/discord shim retained for external plugins that still
import the published @openclaw/discord package directly. Owner-specific
helpers live inside the owning plugin package; shared host behavior moves
through generic SDK contracts such as plugin-sdk/gateway-runtime,
plugin-sdk/security-runtime, and plugin-sdk/plugin-config-runtime.
Use the narrowest import that matches the job. If you cannot find an export,
check the source at src/plugin-sdk/ or ask maintainers which generic
contract should own it.
Removed compatibility surfaces
Private testing barrel
openclaw/plugin-sdk/testing was repo-local and excluded from shipped package
artifacts, so it was removed before its 2026-07-28 removeAfter date. Repository
tests use focused subpaths such as plugin-sdk/plugin-test-runtime,
plugin-sdk/channel-test-helpers, plugin-sdk/channel-target-testing,
plugin-sdk/test-env, and plugin-sdk/test-fixtures.
Active deprecations
Narrower deprecations across the plugin SDK, provider contract, runtime surface, and manifest. Each still works today but will be removed in a future major release. Every entry maps the old API to its canonical replacement.command-auth help builders -> command-status
command-auth help builders -> command-status
openclaw/plugin-sdk/command-auth): buildCommandsMessage,
buildCommandsMessagePaginated, buildHelpMessage.New (openclaw/plugin-sdk/command-status): same signatures, same
exports - just imported from the narrower subpath. command-auth
re-exports them as compat stubs.Mention gating helpers -> resolveInboundMentionDecision
Mention gating helpers -> resolveInboundMentionDecision
resolveMentionGating(params) and
resolveMentionGatingWithBypass(params) from
openclaw/plugin-sdk/channel-inbound or
openclaw/plugin-sdk/channel-mention-gating.New: resolveInboundMentionDecision({ facts, policy }) - one decision
object instead of two split call shapes.Adopted across Discord, iMessage, Matrix, MS Teams, QQBot, Signal,
Telegram, WhatsApp, and Zalo. Slack’s own app_mention event model does
not use this helper.Channel runtime shim and channel actions helpers
Channel runtime shim and channel actions helpers
openclaw/plugin-sdk/channel-runtime is a compatibility shim for older
channel plugins. Do not import it from new code; use
openclaw/plugin-sdk/channel-runtime-context for registering runtime
objects.channelActions* helpers in openclaw/plugin-sdk/channel-actions are
deprecated alongside raw “actions” channel exports. Expose capabilities
through the semantic presentation surface instead - channel plugins
declare what they render (cards, buttons, selects) rather than which raw
action names they accept.Web search provider tool() helper -> createTool() on the plugin
Web search provider tool() helper -> createTool() on the plugin
tool() factory from openclaw/plugin-sdk/provider-web-search.New: implement createTool(...) directly on the provider plugin.
OpenClaw no longer needs the SDK helper to register the tool wrapper.Plaintext channel envelopes -> BodyForAgent
Plaintext channel envelopes -> BodyForAgent
api.runtime.channel.reply.formatInboundEnvelope(...) (and the
channelEnvelope field on inbound message objects) to build a flat
plaintext prompt envelope from inbound channel messages.New: BodyForAgent plus structured user-context blocks. Channel
plugins attach routing metadata (thread, topic, reply-to, reactions) as
typed fields instead of concatenating them into a prompt string. The
formatAgentEnvelope(...) helper is still supported for synthesized
assistant-facing envelopes, but inbound plaintext envelopes are on the way
out.Affected areas: inbound_claim, message_received, and any custom
channel plugin that post-processed the old envelope text.deactivate hook -> gateway_stop
deactivate hook -> gateway_stop
api.on("deactivate", handler).New: api.on("gateway_stop", handler). Same shutdown cleanup
contract; only the hook name changes.deactivate remains wired as a deprecated compatibility alias until it is
removed after 2026-08-16.subagent_spawning hook -> core thread binding
subagent_spawning hook -> core thread binding
api.on("subagent_spawning", handler) returning
threadBindingReady or deliveryOrigin.New: let core prepare thread: true subagent bindings through the
channel session-binding adapter. Use api.on("subagent_spawned", handler)
only for post-launch observation.subagent_spawning, PluginHookSubagentSpawningEvent,
PluginHookSubagentSpawningResult, and
SubagentLifecycleHookRunner.runSubagentSpawning(...) remain only as
deprecated compatibility surfaces while external plugins migrate, removed
after 2026-08-30.Provider discovery types -> provider catalog types
Provider discovery types -> provider catalog types
ProviderCapabilities static bag - provider plugins
should use explicit provider hooks such as buildReplayPolicy,
normalizeToolSchemas, and wrapStreamFn rather than a static object.Thinking policy hooks -> resolveThinkingProfile
Thinking policy hooks -> resolveThinkingProfile
ProviderThinkingPolicy):
isBinaryThinking(ctx), supportsXHighThinking(ctx), and
resolveDefaultThinkingLevel(ctx).New: a single resolveThinkingProfile(ctx) that returns a
ProviderThinkingProfile with the canonical id, optional label, and a
ranked level list. OpenClaw downgrades stale stored values by profile rank
automatically.The context includes provider, modelId, optional merged reasoning,
and optional merged model compat facts. Provider plugins can use those
catalog facts to expose a model-specific profile only when the configured
request contract supports it.Implement one hook instead of three. The legacy hooks keep working during
the deprecation window but are not composed with the profile result.External auth providers -> contracts.externalAuthProviders
External auth providers -> contracts.externalAuthProviders
contracts.externalAuthProviders in the plugin manifest
and implement resolveExternalAuthProfiles(...).Provider env-var lookup -> setup.providers[].envVars
Provider env-var lookup -> setup.providers[].envVars
providerAuthEnvVars: { anthropic: ["ANTHROPIC_API_KEY"] }.New: mirror the same env-var lookup into setup.providers[].envVars
on the manifest. This consolidates setup/status env metadata in one place
and avoids booting the plugin runtime just to answer env-var lookups.providerAuthEnvVars remains supported through a compatibility adapter
until the deprecation window closes.Memory plugin registration -> registerMemoryCapability
Memory plugin registration -> registerMemoryCapability
api.registerMemoryPromptSection(...),
api.registerMemoryFlushPlan(...), api.registerMemoryRuntime(...).New: one call on the memory-state API -
registerMemoryCapability(pluginId, { promptBuilder, flushPlanResolver, runtime }).Same slots, single registration call. Additive prompt and corpus helpers
(registerMemoryPromptSupplement, registerMemoryCorpusSupplement) are
not affected.Memory embedding provider API
Memory embedding provider API
api.registerMemoryEmbeddingProvider(...) plus
contracts.memoryEmbeddingProviders.New: api.registerEmbeddingProvider(...) plus
contracts.embeddingProviders.The generic embedding provider contract is reusable outside memory and is
the supported path for new providers. The memory-specific registration API
remains wired as deprecated compatibility while existing providers
migrate. Plugin inspection reports non-bundled usage as compatibility
debt.Raw channel send results -> OutboundDeliveryResult
Raw channel send results -> OutboundDeliveryResult
{ ok, messageId, error } through
ChannelSendRawResult and normalize it with
createRawChannelSendResultAdapter(...).New: return OutboundDeliveryResult fields and attach the channel with
createAttachedChannelResultAdapter(...). Failed sends should throw instead
of returning an error string. The raw result type remains available until
the next plugin-SDK major release.Subagent session messages types renamed
Subagent session messages types renamed
src/plugins/runtime/types.ts:readSession is deprecated in favor of
getSessionMessages. Same signature; the old method calls through to the
new one.Removed session and transcript file APIs
Removed session and transcript file APIs
sessions.json stores, JSONL transcript paths, or lists
of session files. Runtime plugins should use session identity and SDK runtime
helpers instead of resolving or mutating active files.v2026.7.1-beta.5 imported the four
deprecated helpers above. openclaw/plugin-sdk/session-store-runtime keeps
that exact bridge through 2026-10-12; new plugins must use the replacements.
resolveStorePath(...) remains a supported SDK helper and is not part of
this deprecation.openclaw plugins inspect --all --runtime reports non-bundled plugins whose
load errors or diagnostics still reference these removed file APIs. The
@openclaw/plugin-inspector advisory sweep must use version 0.3.17 or
newer so external package scans also flag whole-store session helpers,
session file-path helpers, legacy transcript file targets, and low-level
transcript helpers before release.runtime.tasks.flow -> runtime.tasks.managedFlows
runtime.tasks.flow -> runtime.tasks.managedFlows
runtime.tasks.flow (singular) returned a live task-flow
accessor.New: runtime.tasks.managedFlows keeps the managed TaskFlow mutation
runtime for plugins that create, update, cancel, or run child tasks from a
flow. Use runtime.tasks.flows when the plugin only needs DTO-based
reads.Embedded extension factories -> agent tool-result middleware
Embedded extension factories -> agent tool-result middleware
api.registerEmbeddedExtensionFactory(...) path is replaced by
api.registerAgentToolResultMiddleware(...) with an explicit runtime list
in contracts.agentToolResultMiddleware.OpenClawSchemaType alias -> OpenClawConfig
OpenClawSchemaType alias -> OpenClawConfig
OpenClawSchemaType re-exported from openclaw/plugin-sdk is now a
one-line alias for OpenClawConfig. Prefer the canonical name.extensions/) are tracked inside their own api.ts and runtime-api.ts
barrels. They do not affect third-party plugin contracts and are not listed
here. If you consume a bundled plugin’s local barrel directly, read the
deprecation comments in that barrel before upgrading.Talk and realtime voice migration
Realtime voice, telephony, meeting, and browser Talk code shares one Talk session controller exported byopenclaw/plugin-sdk/realtime-voice. The
controller owns the common Talk event envelope, active turn state, capture
state, output-audio state, recent event history, and stale-turn rejection.
Provider plugins own vendor-specific realtime sessions; surface plugins own
capture, playback, telephony, and meeting quirks.
All bundled surfaces run on the shared controller: browser relay,
managed-room handoff, voice-call realtime, voice-call streaming STT, Google
Meet realtime, and native push-to-talk. Gateway advertises one live Talk event
channel in hello-ok.features.events: talk.event.
New code should not call createTalkEventSequencer(...) directly unless
implementing a low-level adapter or test fixture. Use the shared controller so
turn-scoped events cannot be emitted without a turn id, stale turnEnd /
turnCancel calls cannot clear a newer active turn, and output-audio
lifecycle events stay consistent across telephony, meetings, browser relay,
managed-room handoff, and native Talk clients.
The public API shape:
talk.client.create,
because the browser owns provider negotiation and media transport while the
Gateway owns credentials, instructions, and tool policy. talk.session.* is
the common Gateway-managed surface for gateway-relay realtime, gateway-relay
transcription, and managed-room native STT/TTS sessions.
Legacy configs that place realtime selectors beside talk.provider /
talk.providers should be repaired with openclaw doctor --fix; runtime Talk
does not reinterpret speech/TTS provider config as realtime provider config.
The supported talk.session.create combinations are intentionally small:
talk.realtime.* /
talk.transcription.* / talk.handoff.* families (all removed):
Removal timeline
scripts/check-deprecated-api-usage.mjs only diagnoses imports from core
and bundled plugin source.
pnpm plugins:boundary-report to see which
compat records are due soonest for the surfaces your plugin uses.
Suppressing the warnings temporarily
Related
- Getting Started - build your first plugin
- SDK Overview - full subpath import reference
- Channel Plugins - building channel plugins
- Provider Plugins - building provider plugins
- Plugin Internals - architecture deep dive
- Plugin Manifest - manifest schema reference