Skip to content

Plugin SDK Migration

OpenClaw has moved from a broad backwards-compatibility layer to a modern plugin architecture with focused, documented imports. If your plugin was built before the new architecture, this guide helps you migrate.

The old plugin system provided two wide-open surfaces that let plugins import anything they needed from a single entry point:

  • openclaw/plugin-sdk/compat — a single import that re-exported dozens of helpers. It was introduced to keep older hook-based plugins working while the new plugin architecture was being built.
  • openclaw/extension-api — a bridge that gave plugins direct access to host-side helpers like the embedded agent runner.

Both surfaces are now deprecated. They still work at runtime, but new plugins must not use them, and existing plugins should migrate before the next major release removes them.

The old approach caused problems:

  • Slow startup — importing one helper loaded dozens of unrelated modules
  • Circular dependencies — broad re-exports made it easy to create import cycles
  • Unclear API surface — no way to tell which exports were stable vs internal

The modern plugin SDK fixes this: each import path (openclaw/plugin-sdk/\<subpath\>) is a small, self-contained module with a clear purpose and documented contract.

  1. Audit Windows wrapper fallback behavior

    If your plugin uses openclaw/plugin-sdk/windows-spawn, unresolved Windows .cmd/.bat wrappers now fail closed unless you explicitly pass allowShellFallback: true.

    // Before
    const program = applyWindowsSpawnProgramPolicy({ candidate });
    // After
    const program = applyWindowsSpawnProgramPolicy({
    candidate,
    // Only set this for trusted compatibility callers that intentionally
    // accept shell-mediated fallback.
    allowShellFallback: true,
    });

    If your caller does not intentionally rely on shell fallback, do not set allowShellFallback and handle the thrown error instead.

  2. Find deprecated imports

    Search your plugin for imports from either deprecated surface:

    Terminal window
    grep -r "plugin-sdk/compat" my-plugin/
    grep -r "openclaw/extension-api" my-plugin/
  3. Replace with focused imports

    Each export from the old surface maps to a specific modern import path:

    // Before (deprecated backwards-compatibility layer)
    import {
    createChannelReplyPipeline,
    createPluginRuntimeStore,
    resolveControlCommandGate,
    } from "openclaw/plugin-sdk/compat";
    // After (modern focused imports)
    import { createChannelReplyPipeline } from "openclaw/plugin-sdk/channel-reply-pipeline";
    import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store";
    import { resolveControlCommandGate } from "openclaw/plugin-sdk/command-auth";

    For host-side helpers, use the injected plugin runtime instead of importing directly:

    // Before (deprecated extension-api bridge)
    import { runEmbeddedPiAgent } from "openclaw/extension-api";
    const result = await runEmbeddedPiAgent({ sessionId, prompt });
    // After (injected runtime)
    const result = await api.runtime.agent.runEmbeddedPiAgent({ sessionId, prompt });

    The same pattern applies to other legacy bridge helpers:

    Old importModern equivalent
    resolveAgentDirapi.runtime.agent.resolveAgentDir
    resolveAgentWorkspaceDirapi.runtime.agent.resolveAgentWorkspaceDir
    resolveAgentIdentityapi.runtime.agent.resolveAgentIdentity
    resolveThinkingDefaultapi.runtime.agent.resolveThinkingDefault
    resolveAgentTimeoutMsapi.runtime.agent.resolveAgentTimeoutMs
    ensureAgentWorkspaceapi.runtime.agent.ensureAgentWorkspace
    session store helpersapi.runtime.agent.session.*
  4. Build and test

    Terminal window
    pnpm build
    pnpm test -- my-plugin/
Full import path table
Import pathPurposeKey exports
plugin-sdk/plugin-entryCanonical plugin entry helperdefinePluginEntry
plugin-sdk/coreChannel entry definitions, channel builders, base typesdefineChannelPluginEntry, createChatChannelPlugin
plugin-sdk/channel-setupSetup wizard adapterscreateOptionalChannelSetupSurface
plugin-sdk/channel-pairingDM pairing primitivescreateChannelPairingController
plugin-sdk/channel-reply-pipelineReply prefix + typing wiringcreateChannelReplyPipeline
plugin-sdk/channel-config-helpersConfig adapter factoriescreateHybridChannelConfigAdapter
plugin-sdk/channel-config-schemaConfig schema buildersChannel config schema types
plugin-sdk/channel-policyGroup/DM policy resolutionresolveChannelGroupRequireMention
plugin-sdk/channel-lifecycleAccount status trackingcreateAccountStatusSink
plugin-sdk/channel-runtimeRuntime wiring helpersChannel runtime utilities
plugin-sdk/channel-send-resultSend result typesReply result types
plugin-sdk/runtime-storePersistent plugin storagecreatePluginRuntimeStore
plugin-sdk/approval-runtimeApproval prompt helpersExec/plugin approval payload, approval capability/profile helpers, native approval routing/runtime helpers
plugin-sdk/collection-runtimeBounded cache helperspruneMapToMaxSize
plugin-sdk/diagnostic-runtimeDiagnostic gating helpersisDiagnosticFlagEnabled, isDiagnosticsEnabled
plugin-sdk/error-runtimeError formatting helpersformatUncaughtError, error graph helpers
plugin-sdk/fetch-runtimeWrapped fetch/proxy helpersresolveFetch, proxy helpers
plugin-sdk/host-runtimeHost normalization helpersnormalizeHostname, normalizeScpRemoteHost
plugin-sdk/retry-runtimeRetry helpersRetryConfig, retryAsync, policy runners
plugin-sdk/allow-fromAllowlist formattingformatAllowFromLowercase
plugin-sdk/allowlist-resolutionAllowlist input mappingmapAllowlistResolutionInputs
plugin-sdk/command-authCommand gatingresolveControlCommandGate
plugin-sdk/secret-inputSecret input parsingSecret input helpers
plugin-sdk/webhook-ingressWebhook request helpersWebhook target utilities
plugin-sdk/webhook-request-guardsWebhook body guard helpersRequest body read/limit helpers
plugin-sdk/reply-payloadMessage reply typesReply payload types
plugin-sdk/provider-onboardProvider onboarding patchesOnboarding config helpers
plugin-sdk/keyed-async-queueOrdered async queueKeyedAsyncQueue
plugin-sdk/testingTest utilitiesTest helpers and mocks

Use the narrowest import that matches the job. If you cannot find an export, check the source at src/plugin-sdk/ or ask in Discord.

WhenWhat happens
NowDeprecated surfaces emit runtime warnings
Next major releaseDeprecated surfaces will be removed; plugins still using them will fail

All core plugins have already been migrated. External plugins should migrate before the next major release.

Set these environment variables while you work on migrating:

Terminal window
OPENCLAW_SUPPRESS_PLUGIN_SDK_COMPAT_WARNING=1 openclaw gateway run
OPENCLAW_SUPPRESS_EXTENSION_API_WARNING=1 openclaw gateway run

This is a temporary escape hatch, not a permanent solution.