{"id":625,"date":"2026-03-21T22:52:57","date_gmt":"2026-03-21T14:52:57","guid":{"rendered":"https:\/\/pa.yingzhi8.cn\/index.php\/2026\/03\/21\/plugins-sdk-migration\/"},"modified":"2026-03-21T23:30:48","modified_gmt":"2026-03-21T15:30:48","slug":"plugins-sdk-migration","status":"publish","type":"post","link":"https:\/\/pa.yingzhi8.cn\/index.php\/2026\/03\/21\/plugins-sdk-migration\/","title":{"rendered":"\u63d2\u4ef6 SDK \u8fc1\u79fb"},"content":{"rendered":"<h1>Plugin SDK Migration<\/h1>\n<p>OpenClaw has moved from a broad backwards-compatibility layer to a modern plugin<br \/>\narchitecture with focused, documented imports. If your plugin was built before<br \/>\nthe new architecture, this guide helps you migrate.<\/p>\n<h2>What is changing<\/h2>\n<p>The old plugin system provided two wide-open surfaces that let plugins import<br \/>\nanything they needed from a single entry point:<\/p>\n<ul>\n<li><strong><code>openclaw\/plugin-sdk\/compat<\/code><\/strong> \u2014 a single import that re-exported dozens of<br \/>\n  helpers. It was introduced to keep older hook-based plugins working while the<br \/>\n  new plugin architecture was being built.<\/li>\n<li><strong><code>openclaw\/extension-api<\/code><\/strong> \u2014 a bridge that gave plugins direct access to<br \/>\n  host-side helpers like the embedded agent runner.<\/li>\n<\/ul>\n<p>Both surfaces are now <strong>deprecated<\/strong>. They still work at runtime, but new<br \/>\nplugins must not use them, and existing plugins should migrate before the next<br \/>\nmajor release removes them.<\/p>\n<p>\n  The backwards-compatibility layer will be removed in a future major release.<br \/>\n  Plugins that still import from these surfaces will break when that happens.\n<\/p>\n<h2>Why this changed<\/h2>\n<p>The old approach caused problems:<\/p>\n<ul>\n<li><strong>Slow startup<\/strong> \u2014 importing one helper loaded dozens of unrelated modules<\/li>\n<li><strong>Circular dependencies<\/strong> \u2014 broad re-exports made it easy to create import cycles<\/li>\n<li><strong>Unclear API surface<\/strong> \u2014 no way to tell which exports were stable vs internal<\/li>\n<\/ul>\n<p>The modern plugin SDK fixes this: each import path (<code>openclaw\/plugin-sdk\/&lt;subpath&gt;<\/code>)<br \/>\nis a small, self-contained module with a clear purpose and documented contract.<\/p>\n<h2>How to migrate<\/h2>\n<p>    Search your plugin for imports from either deprecated surface:<\/p>\n<pre><code>```bash  theme={\"theme\":{\"light\":\"min-light\",\"dark\":\"min-dark\"}}\ngrep -r \"plugin-sdk\/compat\" my-plugin\/\ngrep -r \"openclaw\/extension-api\" my-plugin\/\n```\n<\/code><\/pre>\n<\/p>\n<p>\n    Each export from the old surface maps to a specific modern import path:<\/p>\n<pre><code>```typescript  theme={\"theme\":{\"light\":\"min-light\",\"dark\":\"min-dark\"}}\n\/\/ Before (deprecated backwards-compatibility layer)\nimport {\n  createChannelReplyPipeline,\n  createPluginRuntimeStore,\n  resolveControlCommandGate,\n} from \"openclaw\/plugin-sdk\/compat\";\n\n\/\/ After (modern focused imports)\nimport { createChannelReplyPipeline } from \"openclaw\/plugin-sdk\/channel-reply-pipeline\";\nimport { createPluginRuntimeStore } from \"openclaw\/plugin-sdk\/runtime-store\";\nimport { resolveControlCommandGate } from \"openclaw\/plugin-sdk\/command-auth\";\n```\n\nFor host-side helpers, use the injected plugin runtime instead of importing\ndirectly:\n\n```typescript  theme={\"theme\":{\"light\":\"min-light\",\"dark\":\"min-dark\"}}\n\/\/ Before (deprecated extension-api bridge)\nimport { runEmbeddedPiAgent } from \"openclaw\/extension-api\";\nconst result = await runEmbeddedPiAgent({ sessionId, prompt });\n\n\/\/ After (injected runtime)\nconst result = await api.runtime.agent.runEmbeddedPiAgent({ sessionId, prompt });\n```\n\nThe same pattern applies to other legacy bridge helpers:\n\n| Old import                 | Modern equivalent                            |\n| -------------------------- | -------------------------------------------- |\n| `resolveAgentDir`          | `api.runtime.agent.resolveAgentDir`          |\n| `resolveAgentWorkspaceDir` | `api.runtime.agent.resolveAgentWorkspaceDir` |\n| `resolveAgentIdentity`     | `api.runtime.agent.resolveAgentIdentity`     |\n| `resolveThinkingDefault`   | `api.runtime.agent.resolveThinkingDefault`   |\n| `resolveAgentTimeoutMs`    | `api.runtime.agent.resolveAgentTimeoutMs`    |\n| `ensureAgentWorkspace`     | `api.runtime.agent.ensureAgentWorkspace`     |\n| session store helpers      | `api.runtime.agent.session.*`                |\n<\/code><\/pre>\n<\/p>\n<p>\n    <code>bash  theme={\"theme\":{\"light\":\"min-light\",\"dark\":\"min-dark\"}}<br \/>\n    pnpm build<br \/>\n    pnpm test -- my-plugin\/<\/code><\/p>\n<h2>Import path reference<\/h2>\n<p>\n  | Import path                         | Purpose                              | Key exports                                     |<br \/>\n  | &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211; | &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212; | &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211; |<br \/>\n  | <code>plugin-sdk\/core<\/code>                   | Plugin entry definitions, base types | <code>defineChannelPluginEntry<\/code>, <code>definePluginEntry<\/code> |<br \/>\n  | <code>plugin-sdk\/channel-setup<\/code>          | Setup wizard adapters                | <code>createOptionalChannelSetupSurface<\/code>             |<br \/>\n  | <code>plugin-sdk\/channel-pairing<\/code>        | DM pairing primitives                | <code>createChannelPairingController<\/code>                |<br \/>\n  | <code>plugin-sdk\/channel-reply-pipeline<\/code> | Reply prefix + typing wiring         | <code>createChannelReplyPipeline<\/code>                    |<br \/>\n  | <code>plugin-sdk\/channel-config-helpers<\/code> | Config adapter factories             | <code>createHybridChannelConfigAdapter<\/code>              |<br \/>\n  | <code>plugin-sdk\/channel-config-schema<\/code>  | Config schema builders               | Channel config schema types                     |<br \/>\n  | <code>plugin-sdk\/channel-policy<\/code>         | Group\/DM policy resolution           | <code>resolveChannelGroupRequireMention<\/code>             |<br \/>\n  | <code>plugin-sdk\/channel-lifecycle<\/code>      | Account status tracking              | <code>createAccountStatusSink<\/code>                       |<br \/>\n  | <code>plugin-sdk\/channel-runtime<\/code>        | Runtime wiring helpers               | Channel runtime utilities                       |<br \/>\n  | <code>plugin-sdk\/channel-send-result<\/code>    | Send result types                    | Reply result types                              |<br \/>\n  | <code>plugin-sdk\/runtime-store<\/code>          | Persistent plugin storage            | <code>createPluginRuntimeStore<\/code>                      |<br \/>\n  | <code>plugin-sdk\/allow-from<\/code>             | Allowlist formatting                 | <code>formatAllowFromLowercase<\/code>                      |<br \/>\n  | <code>plugin-sdk\/allowlist-resolution<\/code>   | Allowlist input mapping              | <code>mapAllowlistResolutionInputs<\/code>                  |<br \/>\n  | <code>plugin-sdk\/command-auth<\/code>           | Command gating                       | <code>resolveControlCommandGate<\/code>                     |<br \/>\n  | <code>plugin-sdk\/secret-input<\/code>           | Secret input parsing                 | Secret input helpers                            |<br \/>\n  | <code>plugin-sdk\/webhook-ingress<\/code>        | Webhook request helpers              | Webhook target utilities                        |<br \/>\n  | <code>plugin-sdk\/reply-payload<\/code>          | Message reply types                  | Reply payload types                             |<br \/>\n  | <code>plugin-sdk\/provider-onboard<\/code>       | Provider onboarding patches          | Onboarding config helpers                       |<br \/>\n  | <code>plugin-sdk\/keyed-async-queue<\/code>      | Ordered async queue                  | <code>KeyedAsyncQueue<\/code>                               |<br \/>\n  | <code>plugin-sdk\/testing<\/code>                | Test utilities                       | Test helpers and mocks                          |\n<\/p>\n<p>Use the narrowest import that matches the job. If you cannot find an export,<br \/>\ncheck the source at <code>src\/plugin-sdk\/<\/code> or ask in Discord.<\/p>\n<h2>Removal timeline<\/h2>\n<table>\n<thead>\n<tr>\n<th>When<\/th>\n<th>What happens<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><strong>Now<\/strong><\/td>\n<td>Deprecated surfaces emit runtime warnings<\/td>\n<\/tr>\n<tr>\n<td><strong>Next major release<\/strong><\/td>\n<td>Deprecated surfaces will be removed; plugins still using them will fail<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>All core plugins have already been migrated. External plugins should migrate<br \/>\nbefore the next major release.<\/p>\n<h2>Suppressing the warnings temporarily<\/h2>\n<p>Set these environment variables while you work on migrating:<\/p>\n<p><code>bash  theme={\"theme\":{\"light\":\"min-light\",\"dark\":\"min-dark\"}}<br \/>\nOPENCLAW_SUPPRESS_PLUGIN_SDK_COMPAT_WARNING=1 openclaw gateway run<br \/>\nOPENCLAW_SUPPRESS_EXTENSION_API_WARNING=1 openclaw gateway run<\/code><\/p>\n<p>This is a temporary escape hatch, not a permanent solution.<\/p>\n<h2>Related<\/h2>\n<ul>\n<li><a href=\"\/plugins\/building-plugins\">Building Plugins<\/a><\/li>\n<li><a href=\"\/plugins\/architecture\">Plugin Internals<\/a><\/li>\n<li><a href=\"\/plugins\/manifest\">Plugin Manifest<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Plugin SDK Migration OpenClaw has moved from a broad ba [&hellip;]<\/p>\n","protected":false},"author":0,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[],"class_list":["post-625","post","type-post","status-publish","format-standard","hentry","category-docs"],"_links":{"self":[{"href":"https:\/\/pa.yingzhi8.cn\/index.php\/wp-json\/wp\/v2\/posts\/625","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/pa.yingzhi8.cn\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/pa.yingzhi8.cn\/index.php\/wp-json\/wp\/v2\/types\/post"}],"replies":[{"embeddable":true,"href":"https:\/\/pa.yingzhi8.cn\/index.php\/wp-json\/wp\/v2\/comments?post=625"}],"version-history":[{"count":3,"href":"https:\/\/pa.yingzhi8.cn\/index.php\/wp-json\/wp\/v2\/posts\/625\/revisions"}],"predecessor-version":[{"id":884,"href":"https:\/\/pa.yingzhi8.cn\/index.php\/wp-json\/wp\/v2\/posts\/625\/revisions\/884"}],"wp:attachment":[{"href":"https:\/\/pa.yingzhi8.cn\/index.php\/wp-json\/wp\/v2\/media?parent=625"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/pa.yingzhi8.cn\/index.php\/wp-json\/wp\/v2\/categories?post=625"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/pa.yingzhi8.cn\/index.php\/wp-json\/wp\/v2\/tags?post=625"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}