The plugin SDK is the typed contract between plugins and core. This page is the
reference for what to import and what you can register .
Always import from a specific subpath:
import { definePluginEntry } from " openclaw/plugin-sdk/plugin-entry " ;
import { defineChannelPluginEntry } from " openclaw/plugin-sdk/core " ;
Each subpath is a small, self-contained module. This keeps startup fast and
prevents circular dependency issues.
The most commonly used subpaths, grouped by purpose. The full list of 100+
subpaths is in scripts/lib/plugin-sdk-entrypoints.json.
Subpath Key exports plugin-sdk/plugin-entrydefinePluginEntryplugin-sdk/coredefineChannelPluginEntry, createChatChannelPlugin, createChannelPluginBase, defineSetupPluginEntry, buildChannelConfigSchema
Channel subpaths
Subpath Key exports plugin-sdk/channel-setupcreateOptionalChannelSetupSurfaceplugin-sdk/channel-pairingcreateChannelPairingControllerplugin-sdk/channel-reply-pipelinecreateChannelReplyPipelineplugin-sdk/channel-config-helperscreateHybridChannelConfigAdapterplugin-sdk/channel-config-schemaChannel config schema types plugin-sdk/channel-policyresolveChannelGroupRequireMentionplugin-sdk/channel-lifecyclecreateAccountStatusSinkplugin-sdk/channel-inboundDebounce, mention matching, envelope helpers plugin-sdk/channel-send-resultReply result types plugin-sdk/channel-actionscreateMessageToolButtonsSchema, createMessageToolCardSchemaplugin-sdk/channel-targetsTarget parsing/matching helpers plugin-sdk/channel-contractChannel contract types plugin-sdk/channel-feedbackFeedback/reaction wiring
Provider subpaths
Subpath Key exports plugin-sdk/cli-backendCLI backend defaults + watchdog constants plugin-sdk/provider-authcreateProviderApiKeyAuthMethod, ensureApiKeyFromOptionEnvOrPrompt, upsertAuthProfileplugin-sdk/provider-model-sharednormalizeModelCompatplugin-sdk/provider-catalog-sharedfindCatalogTemplate, buildSingleProviderApiKeyCatalogplugin-sdk/provider-usagefetchClaudeUsage and similarplugin-sdk/provider-streamStream wrapper types plugin-sdk/provider-onboardOnboarding config patch helpers plugin-sdk/global-singletonProcess-local singleton/map/cache helpers
Auth and security subpaths
Subpath Key exports plugin-sdk/command-authresolveControlCommandGateplugin-sdk/allow-fromformatAllowFromLowercaseplugin-sdk/secret-inputSecret input parsing helpers plugin-sdk/webhook-ingressWebhook request/target helpers plugin-sdk/webhook-request-guardsRequest body size/timeout helpers
Runtime and storage subpaths
Subpath Key exports plugin-sdk/runtime-storecreatePluginRuntimeStoreplugin-sdk/config-runtimeConfig load/write helpers plugin-sdk/approval-runtimeExec/plugin approval helpers, approval-capability builders, auth/profile helpers, native routing/runtime helpers plugin-sdk/infra-runtimeSystem event/heartbeat helpers plugin-sdk/collection-runtimeSmall bounded cache helpers plugin-sdk/diagnostic-runtimeDiagnostic flag and event helpers plugin-sdk/error-runtimeError graph and formatting helpers plugin-sdk/fetch-runtimeWrapped fetch, proxy, and pinned lookup helpers plugin-sdk/host-runtimeHostname and SCP host normalization helpers plugin-sdk/retry-runtimeRetry config and retry runner helpers plugin-sdk/agent-runtimeAgent dir/identity/workspace helpers plugin-sdk/directory-runtimeConfig-backed directory query/dedup plugin-sdk/keyed-async-queueKeyedAsyncQueue
Capability and testing subpaths
Subpath Key exports plugin-sdk/image-generationImage generation provider types plugin-sdk/media-understandingMedia understanding provider types plugin-sdk/speechSpeech provider types plugin-sdk/testinginstallCommonResolveTargetErrorCases, shouldAckReaction
The register(api) callback receives an OpenClawPluginApi object with these
methods:
Method What it registers api.registerProvider(...)Text inference (LLM) api.registerCliBackend(...)Local CLI inference backend api.registerChannel(...)Messaging channel api.registerSpeechProvider(...)Text-to-speech / STT synthesis api.registerMediaUnderstandingProvider(...)Image/audio/video analysis api.registerImageGenerationProvider(...)Image generation api.registerWebSearchProvider(...)Web search
Method What it registers api.registerTool(tool, opts?)Agent tool (required or { optional: true }) api.registerCommand(def)Custom command (bypasses the LLM)
Method What it registers api.registerHook(events, handler, opts?)Event hook api.registerHttpRoute(params)Gateway HTTP endpoint api.registerGatewayMethod(name, handler)Gateway RPC method api.registerCli(registrar, opts?)CLI subcommand api.registerService(service)Background service api.registerInteractiveHandler(registration)Interactive handler
api.registerCli(registrar, opts?) accepts two kinds of top-level metadata:
commands: explicit command roots owned by the registrar
descriptors: parse-time command descriptors used for root CLI help,
routing, and lazy plugin CLI registration
If you want a plugin command to stay lazy-loaded in the normal root CLI path,
provide descriptors that cover every top-level command root exposed by that
registrar.
const { registerMatrixCli } = await import ( " ./src/cli.js " );
registerMatrixCli ({ program });
description: " Manage Matrix accounts, verification, devices, and profile state " ,
Use commands by itself only when you do not need lazy root CLI registration.
That eager compatibility path remains supported, but it does not install
descriptor-backed placeholders for parse-time lazy loading.
api.registerCliBackend(...) lets a plugin own the default config for a local
AI CLI backend such as claude-cli or codex-cli.
The backend id becomes the provider prefix in model refs like claude-cli/opus.
The backend config uses the same shape as agents.defaults.cliBackends.<id>.
User config still wins. OpenClaw merges agents.defaults.cliBackends.<id> over the
plugin default before running the CLI.
Use normalizeConfig when a backend needs compatibility rewrites after merge
(for example normalizing old flag shapes).
Method What it registers api.registerContextEngine(id, factory)Context engine (one active at a time) api.registerMemoryPromptSection(builder)Memory prompt section builder api.registerMemoryFlushPlan(resolver)Memory flush plan resolver api.registerMemoryRuntime(runtime)Memory runtime adapter
Method What it registers api.registerMemoryEmbeddingProvider(adapter)Memory embedding adapter for the active plugin
registerMemoryPromptSection, registerMemoryFlushPlan, and
registerMemoryRuntime are exclusive to memory plugins.
registerMemoryEmbeddingProvider lets the active memory plugin register one
or more embedding adapter ids (for example openai, gemini, or a custom
plugin-defined id).
User config such as agents.defaults.memorySearch.provider and
agents.defaults.memorySearch.fallback resolves against those registered
adapter ids.
Method What it does api.on(hookName, handler, opts?)Typed lifecycle hook api.onConversationBindingResolved(handler)Conversation binding callback
before_tool_call: returning { block: true } is terminal. Once any handler sets it, lower-priority handlers are skipped.
before_tool_call: returning { block: false } is treated as no decision (same as omitting block), not as an override.
before_install: returning { block: true } is terminal. Once any handler sets it, lower-priority handlers are skipped.
before_install: returning { block: false } is treated as no decision (same as omitting block), not as an override.
message_sending: returning { cancel: true } is terminal. Once any handler sets it, lower-priority handlers are skipped.
message_sending: returning { cancel: false } is treated as no decision (same as omitting cancel), not as an override.
Field Type Description api.idstringPlugin id api.namestringDisplay name api.versionstring?Plugin version (optional) api.descriptionstring?Plugin description (optional) api.sourcestringPlugin source path api.rootDirstring?Plugin root directory (optional) api.configOpenClawConfigCurrent config snapshot api.pluginConfigRecord<string, unknown>Plugin-specific config from plugins.entries.<id>.config api.runtimePluginRuntimeRuntime helpers api.loggerPluginLoggerScoped logger (debug, info, warn, error) api.registrationModePluginRegistrationMode"full", "setup-only", "setup-runtime", or "cli-metadata"api.resolvePath(input)(string) => stringResolve path relative to plugin root
Within your plugin, use local barrel files for internal imports:
api.ts # Public exports for external consumers
runtime-api.ts # Internal-only runtime exports
index.ts # Plugin entry point
setup-entry.ts # Lightweight setup-only entry (optional)