Plugin SDK migration
기준일: 2026-07-26
공식 기준: Plugin SDK migration
Plugin SDK migration 문서는 OpenClaw 공식 문서(plugins/sdk-migration)를 한국어로 정리한 가이드입니다. Migrate from the legacy backwards-compatibility layer to the modern plugin SDK 명령·설정 키·코드 예시는 공식 문서를 그대로 보존하며, 해석과 절차 안내는 한국어로 제공합니다. 최종 동작은 설치된 CLI 버전과 공식 원문을 확인하세요.
핵심 요약
Migrate from the legacy backwards-compatibility layer to the modern plugin SDK
한국어 가이드 범위: plugins/sdk-migration 경로의 설정·명령·제약·예시를 학습용으로 재구성합니다.
문서 구성
공식 문서의 주요 섹션은 다음과 같습니다.
- What changed
- Why
- Compatibility policy
- Published channel setup compatibility
- Channel setup input field compatibility
- Media legacy projection
- How to migrate
- Import path reference
- Removed compatibility surfaces
- Process-global API-provider publication
- Private testing barrel
- Migration reference
- Talk and realtime voice migration
- Removal timeline
- Suppressing the warnings temporarily
- 관련 문서
상세 내용
본문
OpenClaw replaced a broad backwards-compatibility layer with a modern plugin architecture built from small, focused imports. If your plugin predates that change, this guide gets it onto the current contracts.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
What changed
Several wide-open import surfaces used to let plugins reach almost anything from a single entry point:
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
주요 항목:
openclaw/plugin-sdkandopenclaw/plugin-sdk/compat- re-exportedopenclaw/plugin-sdk/infra-runtime- a broad barrel mixing systemopenclaw/plugin-sdk/config-runtime- a broad config barrel retainedopenclaw/extension-api- a removed bridge that gave plugins directapi.registerEmbeddedExtensionFactory(...)- a removed embedded-runner-only
Why
Each openclaw/plugin-sdk/ is now a small, self-contained module with a documented contract.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
주요 항목:
- Slow startup - importing one helper loaded dozens of unrelated modules.
- Circular dependencies - broad re-exports made import cycles easy to
- Unclear API surface - no way to tell stable exports from internal ones.
- Anthropic keeps Claude-specific stream helpers in its own
api.ts/ - OpenAI keeps provider builders, default-model helpers, and realtime provider
- OpenRouter keeps provider builder and onboarding/config helpers in its own
Compatibility policy
External-plugin compatibility work follows this order:
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
Published channel setup compatibility
Slack, Discord, Signal, and Microsoft Teams packages published through 2026.7.1 import channel-specific config schemas from openclaw/plugin-sdk/bundled-channel-config-schema. The published Slack and Discord packages also import createLegacyCompatChannelDmPolicy and promptLegacyChannelAllowFromForAccount from openclaw/plugin-sdk/setup-runtime.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
Channel setup input field compatibility
ChannelSetupInput now keeps only the cross-channel setup envelope typed permanently. Channel-specific fields remain typed in a deprecated compatibility tier so existing external plugins still compile while plugin authors move those fields into plugin-local setup input types.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
code |
owner |
replacement |
Removal condition |
|---|---|---|---|
plugin-sdk-channel-setup-input-fields |
channel |
Intersect ChannelSetupInput with a plugin-local type that declares the owning channel's fields |
Delete a field when the published-plugin registry sweep has no reader |
| Flag | Effect |
|---|---|
--summary (or pnpm plugins:boundary-report:summary) |
Compact counts instead of full detail. |
--json |
Machine-readable report. |
--owner <id> |
Filter to one plugin or compatibility owner. |
--fail-on-cross-owner |
Exit non-zero on cross-owner reserved SDK imports. |
--fail-on-eligible-compat |
Exit non-zero when a deprecated compat record's removeAfter date has passed. |
--fail-on-unclassified-unused-reserved |
Exit non-zero on unused reserved SDK shims. |
Media legacy projection
The media-legacy-projection compatibility record covers the old parallel media fields, payload builders, hook metadata aliases, and media template names. Its approved removeAfter date is 2026-10-01 (two release trains after the facts-first replacements shipped). Removal additionally requires a clean published-plugin artifact sweep at that time; migrate before the date.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
const media = toInboundMediaFacts([
{ path: saved.path, url: nativeUrl, contentType: saved.contentType, messageId },
]);
const ctx = finalizeInboundContext({ Body: caption, media });
How to migrate
Bundled plugins should stop calling 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.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
주요 항목:
- Replace
approvalCapability.handler.loadRuntime(...)with - Move approval-specific auth/delivery off legacy
plugin.auth/ ChannelPlugin.approvalshas been removed from the publicplugin.authremains for channel login/logout flows only; core no- Register channel-owned runtime objects (clients, tokens, Bolt apps)
- Do not send plugin-owned reroute notices from native approval handlers;
- When passing
channelRuntimeintocreateChannelManager(...), provide a
await api.runtime.config.mutateConfigFile({
afterWrite: { mode: "auto" },
mutate(draft) {
draft.plugins ??= {};
},
});
// OpenClaw runtime tools and Codex runtime dynamic tools (result may be
// transformed). Codex-native tool results are also relayed for observation,
// but their transformed output never reaches the model: the Codex
// PostToolUse hook contract cannot replace a native tool response.
api.registerAgentToolResultMiddleware(async (event) => {
return compactToolResult(event);
}, {
runtimes: ["openclaw", "codex"],
});
{
"contracts": {
"agentToolResultMiddleware": ["openclaw", "codex"]
}
}
// 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,
});
Import path reference
The public package export map is the source of truth for importable SDK subpaths. Use the topical SDK guides linked from SDK overview and prefer the narrowest documented public subpath. The compiler inventory in scripts/lib/plugin-sdk-entrypoints.json also contains private-local entries used to build bundled plugins; their presence there does not make them public package exports.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
Removed compatibility surfaces
The July 2026 sweep removed the root SDK and compat barrels, the extension API bridge, the expired SDK subpath aliases, unused SDK subpaths, and the public exports for bundled-only SDK modules. Bundled-only modules remain available to their repository owners through private-local build mappings; they are not importable from the published package.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
Process-global API-provider publication
registerApiProvider(...) and unregisterApiProviders(...) were removed from openclaw/plugin-sdk/llm. They published API transports into process-global state, which lifecycle-owned model runtimes then had to copy into each prepared registry.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
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.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
Migration reference
These mappings cover both removed July 2026 surfaces and later-window active deprecations. A mapping is migration guidance, not evidence that the old surface remains available; consult the compatibility registry and removal timeline for current status.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
// Before
import { buildHelpMessage } from "openclaw/plugin-sdk/command-auth";
// After
import { buildHelpMessage } from "openclaw/plugin-sdk/command-status";
// Before
api.on("deactivate", async (event, ctx) => {
await stopPluginService(ctx);
});
// After
api.on("gateway_stop", async (event, ctx) => {
await stopPluginService(ctx);
});
// Before
api.on("subagent_spawning", async () => ({
status: "ok",
threadBindingReady: true,
deliveryOrigin: { channel: "discord", to: "channel:123", threadId: "456" },
}));
// After
api.on("subagent_spawned", async (event) => {
await observeSubagentLaunch(event);
});
{
"contracts": {
"externalAuthProviders": ["anthropic", "openai"]
}
}
Talk and realtime voice migration
Realtime voice, telephony, meeting, and browser Talk code shares one Talk session controller exported by openclaw/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. Browser-meeting plugins use openclaw/plugin-sdk/meeting-runtime for session, browser, audio, node-host, agent-consult, and voice-call mechanics, then implement MeetingPlatformAdapter for URL rules, DOM scripts, manual-action mapping, captions, creation, and dial-in plans. Platform REST APIs, OAuth, artifacts, selectors, and wire names remain in the plugin. Browser permission plans receive the requested meeting URL so each platform can grant only its exact supported origins. Session runtimes must also normalize platform-specific live health after confirmed browser departure; historical transcript fields may remain, but caption and audio readiness must not stay active after leave.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
| Mode | Transport | Brain | Owner | Notes |
|---|---|---|---|---|
realtime |
gateway-relay |
agent-consult |
Gateway | Full-duplex provider audio bridged through the Gateway; tool calls route through the agent-consult tool. |
transcription |
gateway-relay |
none |
Gateway | Streaming STT only; callers send input audio and receive transcript events. |
stt-tts |
managed-room |
agent-consult |
Native/client room | Push-to-talk and walkie-talkie style rooms where the client owns capture/playback and the Gateway owns turn state. |
stt-tts |
managed-room |
direct-tools |
Native/client room | Admin-only room mode for trusted first-party surfaces that execute Gateway tool actions directly. |
| Old | New |
|---|---|
talk.realtime.session |
talk.client.create |
talk.realtime.toolCall |
talk.client.toolCall |
talk.realtime.relayAudio |
talk.session.appendAudio |
talk.realtime.relayCancel |
talk.session.cancelOutput or talk.session.cancelTurn |
talk.realtime.relayToolResult |
talk.session.submitToolResult |
talk.realtime.relayStop |
talk.session.close |
talk.transcription.session |
talk.session.create({ mode: "transcription" }) |
talk.transcription.relayAudio |
talk.session.appendAudio |
talk.transcription.relayCancel |
talk.session.cancelTurn |
talk.transcription.relayStop |
talk.session.close |
talk.handoff.create |
talk.session.create({ transport: "managed-room" }) |
talk.handoff.join |
talk.session.join |
talk.handoff.revoke |
talk.session.close |
| Method | Applies to | Contract |
|---|---|---|
talk.session.appendAudio |
realtime/gateway-relay, transcription/gateway-relay |
Append a base64 PCM audio chunk to the provider session owned by the same Gateway connection. |
talk.session.startTurn |
stt-tts/managed-room |
Start a managed-room user turn. |
talk.session.endTurn |
stt-tts/managed-room |
End the active turn after stale-turn validation. |
talk.session.cancelTurn |
all Gateway-owned sessions | Cancel active capture/provider/agent/TTS work for a turn. |
talk.session.cancelOutput |
realtime/gateway-relay |
Stop assistant audio output without necessarily ending the user turn. |
talk.session.submitToolResult |
realtime/gateway-relay |
Complete a provider tool call after any asynchronous completion exposed by its bridge; pass options.willContinue for interim output or, when supported, options.suppressResponse to avoid another assistant response. |
talk.session.steer |
agent-backed Talk sessions | Send spoken status, steer, cancel, or followup control to the active embedded run resolved from the Talk session. |
talk.session.close |
all unified sessions | Stop relay sessions or revoke managed-room state, then forget the unified session id. |
// Gateway-owned Talk session API.
await gateway.request("talk.session.create", {
mode: "realtime",
transport: "gateway-relay",
brain: "agent-consult",
sessionKey: "main",
});
await gateway.request("talk.session.appendAudio", { sessionId, audioBase64 });
await gateway.request("talk.session.cancelOutput", { sessionId, reason: "barge-in" });
await gateway.request("talk.session.submitToolResult", {
sessionId,
callId,
result: { status: "working" },
options: { willContinue: true },
});
await gateway.request("talk.session.submitToolResult", {
sessionId,
callId,
result: { status: "already_delivered" },
options: { suppressResponse: true },
});
await gateway.request("talk.session.submitToolResult", { sessionId, callId, result });
await gateway.request("talk.session.close", { sessionId });
// Client-owned provider session API.
await gateway.request("talk.client.create", {
mode: "realtime",
transport: "webrtc",
brain: "agent-consult",
sessionKey: "main",
});
await gateway.request("talk.client.toolCall", { sessionKey, callId, name, args });
await gateway.request("talk.client.steer", { sessionKey, text, mode: "steer" });
Removal timeline
The remaining public SDK subpaths below have registry-backed removal windows. The July 30 rows were removed after their early maintainer-authorized sweep: unused subpaths were deleted, earlier compatibility aliases were deleted, and bundled-only modules were demoted to private-local build mappings.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
| When | What happens |
|---|---|
| Now | Warning-capable deprecated surfaces emit runtime warnings; repository guards reject deprecated SDK imports from core and bundled plugins. |
| Pending owner decision | Date-less records remain deprecated and ineligible for removal until their owner publishes a removeAfter date. |
Each compat record's removeAfter date |
That specific surface is eligible for removal; pnpm plugins:boundary-report --fail-on-eligible-compat fails CI once the date passes. |
| Next major release | Dated surfaces may be removed only after their removeAfter date; date-less records still require owner approval and a published date. |
removeAfter |
Tier | SDK subpaths |
|---|---|---|
2026-08-15 |
Earlier compatibility deprecations | agent-config-primitives, channel-logging, channel-secret-runtime, channel-streaming, group-access, inbound-reply-dispatch, matrix, text-runtime, zod |
2026-09-01 |
Earlier compatibility deprecations | channel-lifecycle, channel-message, channel-reply-pipeline, config-runtime, infra-runtime |
2026-10-01 |
Media legacy projection | agent-media-payload, plus the non-subpath MsgContext Media* fields, channel inbound media payload builders, buildMediaPayload, hook media aliases, and {{Media*}} templates |
Suppressing the warnings temporarily
This is a temporary escape hatch, not a permanent solution.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
OPENCLAW_SUPPRESS_PLUGIN_SDK_COMPAT_WARNING=1 openclaw gateway run
OPENCLAW_SUPPRESS_EXTENSION_API_WARNING=1 openclaw gateway run
관련 문서
주요 항목:
- 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
실습 체크리스트
- 공식 문서와 로컬 버전을 대조합니다:
https://docs.openclaw.ai/plugins/sdk-migration - 관련 CLI는
openclaw --help및 하위 명령--help로 옵션을 확인합니다. - 설정 변경 시
openclaw config/openclaw doctor로 유효성을 검사합니다. - Gateway·채널·플러그인 변경 후에는 필요 시 Gateway를 재시작합니다.
자주 쓰는 명령·설정 예시
const media = toInboundMediaFacts([
{ path: saved.path, url: nativeUrl, contentType: saved.contentType, messageId },
]);
const ctx = finalizeInboundContext({ Body: caption, media });
await api.runtime.config.mutateConfigFile({
afterWrite: { mode: "auto" },
mutate(draft) {
draft.plugins ??= {};
},
});
// OpenClaw runtime tools and Codex runtime dynamic tools (result may be
// transformed). Codex-native tool results are also relayed for observation,
// but their transformed output never reaches the model: the Codex
// PostToolUse hook contract cannot replace a native tool response.
api.registerAgentToolResultMiddleware(async (event) => {
return compactToolResult(event);
}, {
runtimes: ["openclaw", "codex"],
});
{
"contracts": {
"agentToolResultMiddleware": ["openclaw", "codex"]
}
}
// 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,
});
grep -r "plugin-sdk/compat" my-plugin/
grep -r "plugin-sdk/infra-runtime" my-plugin/
grep -r "plugin-sdk/config-runtime" my-plugin/
grep -r "openclaw/extension-api" my-plugin/
관련 링크
이 가이드는 공식 문서를 한국어 학습용으로 재구성한 것입니다. 옵션 기본값·플래그 이름은 설치 버전에 따라 달라질 수 있습니다.