Skip to main content

Plugin SDK Overview

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.
Looking for a how-to guide?

Import convention

Always import from a specific subpath:
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
import { defineChannelPluginEntry } from "openclaw/plugin-sdk/channel-core";
Each subpath is a small, self-contained module. This keeps startup fast and prevents circular dependency issues. For channel-specific entry/build helpers, prefer openclaw/plugin-sdk/channel-core; keep openclaw/plugin-sdk/core for the broader umbrella surface and shared helpers such as buildChannelConfigSchema. Do not add or depend on provider-named convenience seams such as openclaw/plugin-sdk/slack, openclaw/plugin-sdk/discord, openclaw/plugin-sdk/signal, openclaw/plugin-sdk/whatsapp, or channel-branded helper seams. Bundled plugins should compose generic SDK subpaths inside their own api.ts or runtime-api.ts barrels, and core should either use those plugin-local barrels or add a narrow generic SDK contract when the need is truly cross-channel. The generated export map still contains a small set of bundled-plugin helper seams such as plugin-sdk/feishu, plugin-sdk/feishu-setup, plugin-sdk/zalo, plugin-sdk/zalo-setup, and plugin-sdk/matrix*. Those subpaths exist for bundled-plugin maintenance and compatibility only; they are intentionally omitted from the common table below and are not the recommended import path for new third-party plugins.

Subpath reference

The most commonly used subpaths, grouped by purpose. The generated full list of 200+ subpaths lives in scripts/lib/plugin-sdk-entrypoints.json. Reserved bundled-plugin helper subpaths still appear in that generated list. Treat those as implementation detail/compatibility surfaces unless a doc page explicitly promotes one as public.

Plugin entry

SubpathKey exports
plugin-sdk/plugin-entrydefinePluginEntry
plugin-sdk/coredefineChannelPluginEntry, createChatChannelPlugin, createChannelPluginBase, defineSetupPluginEntry, buildChannelConfigSchema
plugin-sdk/config-schemaOpenClawSchema
plugin-sdk/provider-entrydefineSingleProviderPluginEntry
SubpathKey exports
plugin-sdk/channel-coredefineChannelPluginEntry, defineSetupPluginEntry, createChatChannelPlugin, createChannelPluginBase
plugin-sdk/config-schemaRoot openclaw.json Zod schema export (OpenClawSchema)
plugin-sdk/channel-setupcreateOptionalChannelSetupSurface, createOptionalChannelSetupAdapter, createOptionalChannelSetupWizard, plus DEFAULT_ACCOUNT_ID, createTopLevelChannelDmPolicy, setSetupChannelEnabled, splitSetupEntries
plugin-sdk/setupShared setup wizard helpers, allowlist prompts, setup status builders
plugin-sdk/setup-runtimecreatePatchedAccountSetupAdapter, createEnvPatchedAccountSetupAdapter, createSetupInputPresenceValidator, noteChannelLookupFailure, noteChannelLookupSummary, promptResolvedAllowFrom, splitSetupEntries, createAllowlistSetupWizardProxy, createDelegatedSetupWizardProxy
plugin-sdk/setup-adapter-runtimecreateEnvPatchedAccountSetupAdapter
plugin-sdk/setup-toolsformatCliCommand, detectBinary, extractArchive, resolveBrewExecutable, formatDocsLink, CONFIG_DIR
plugin-sdk/account-coreMulti-account config/action-gate helpers, default-account fallback helpers
plugin-sdk/account-idDEFAULT_ACCOUNT_ID, account-id normalization helpers
plugin-sdk/account-resolutionAccount lookup + default-fallback helpers
plugin-sdk/account-helpersNarrow account-list/account-action helpers
plugin-sdk/channel-pairingcreateChannelPairingController
plugin-sdk/channel-reply-pipelinecreateChannelReplyPipeline
plugin-sdk/channel-config-helperscreateHybridChannelConfigAdapter
plugin-sdk/channel-config-schemaChannel config schema types
plugin-sdk/telegram-command-configTelegram custom-command normalization/validation helpers with bundled-contract fallback
plugin-sdk/channel-policyresolveChannelGroupRequireMention
plugin-sdk/channel-lifecyclecreateAccountStatusSink
plugin-sdk/inbound-envelopeShared inbound route + envelope builder helpers
plugin-sdk/inbound-reply-dispatchShared inbound record-and-dispatch helpers
plugin-sdk/messaging-targetsTarget parsing/matching helpers
plugin-sdk/outbound-mediaShared outbound media loading helpers
plugin-sdk/outbound-runtimeOutbound identity/send delegate helpers
plugin-sdk/thread-bindings-runtimeThread-binding lifecycle and adapter helpers
plugin-sdk/agent-media-payloadLegacy agent media payload builder
plugin-sdk/conversation-runtimeConversation/thread binding, pairing, and configured-binding helpers
plugin-sdk/runtime-config-snapshotRuntime config snapshot helper
plugin-sdk/runtime-group-policyRuntime group-policy resolution helpers
plugin-sdk/channel-statusShared channel status snapshot/summary helpers
plugin-sdk/channel-config-primitivesNarrow channel config-schema primitives
plugin-sdk/channel-config-writesChannel config-write authorization helpers
plugin-sdk/channel-plugin-commonShared channel plugin prelude exports
plugin-sdk/allowlist-config-editAllowlist config edit/read helpers
plugin-sdk/group-accessShared group-access decision helpers
plugin-sdk/direct-dmShared direct-DM auth/guard helpers
plugin-sdk/interactive-runtimeInteractive reply payload normalization/reduction helpers
plugin-sdk/channel-inboundDebounce, mention matching, envelope helpers
plugin-sdk/channel-send-resultReply result types
plugin-sdk/channel-actionscreateMessageToolButtonsSchema, createMessageToolCardSchema
plugin-sdk/channel-targetsTarget parsing/matching helpers
plugin-sdk/channel-contractChannel contract types
plugin-sdk/channel-feedbackFeedback/reaction wiring
SubpathKey exports
plugin-sdk/provider-entrydefineSingleProviderPluginEntry
plugin-sdk/provider-setupCurated local/self-hosted provider setup helpers
plugin-sdk/self-hosted-provider-setupFocused OpenAI-compatible self-hosted provider setup helpers
plugin-sdk/cli-backendCLI backend defaults + watchdog constants
plugin-sdk/provider-auth-runtimeRuntime API-key resolution helpers for provider plugins
plugin-sdk/provider-auth-api-keyAPI-key onboarding/profile-write helpers
plugin-sdk/provider-auth-resultStandard OAuth auth-result builder
plugin-sdk/provider-auth-loginShared interactive login helpers for provider plugins
plugin-sdk/provider-env-varsProvider auth env-var lookup helpers
plugin-sdk/provider-authcreateProviderApiKeyAuthMethod, ensureApiKeyFromOptionEnvOrPrompt, upsertAuthProfile
plugin-sdk/provider-model-sharedProviderReplayFamily, buildProviderReplayFamilyHooks, normalizeModelCompat, shared replay-policy builders, provider-endpoint helpers, and model-id normalization helpers such as normalizeNativeXaiModelId
plugin-sdk/provider-catalog-sharedfindCatalogTemplate, buildSingleProviderApiKeyCatalog, supportsNativeStreamingUsageCompat, applyProviderNativeStreamingUsageCompat
plugin-sdk/provider-httpGeneric provider HTTP/endpoint capability helpers
plugin-sdk/provider-web-fetchWeb-fetch provider registration/cache helpers
plugin-sdk/provider-web-searchWeb-search provider registration/cache/config helpers
plugin-sdk/provider-toolsProviderToolCompatFamily, buildProviderToolCompatFamilyHooks, Gemini schema cleanup + diagnostics, and xAI compat helpers such as resolveXaiModelCompatPatch / applyXaiModelCompat
plugin-sdk/provider-usagefetchClaudeUsage and similar
plugin-sdk/provider-streamProviderStreamFamily, buildProviderStreamFamilyHooks, composeProviderStreamWrappers, stream wrapper types, and shared Anthropic/Bedrock/Google/Kilocode/Moonshot/OpenAI/OpenRouter/Z.A.I/MiniMax/Copilot wrapper helpers
plugin-sdk/provider-onboardOnboarding config patch helpers
plugin-sdk/global-singletonProcess-local singleton/map/cache helpers
SubpathKey exports
plugin-sdk/command-authresolveControlCommandGate, command registry helpers, sender-authorization helpers
plugin-sdk/approval-auth-runtimeApprover resolution and same-chat action-auth helpers
plugin-sdk/approval-client-runtimeNative exec approval profile/filter helpers
plugin-sdk/approval-delivery-runtimeNative approval capability/delivery adapters
plugin-sdk/approval-native-runtimeNative approval target + account-binding helpers
plugin-sdk/approval-reply-runtimeExec/plugin approval reply payload helpers
plugin-sdk/command-auth-nativeNative command auth + native session-target helpers
plugin-sdk/command-detectionShared command detection helpers
plugin-sdk/command-surfaceCommand-body normalization and command-surface helpers
plugin-sdk/allow-fromformatAllowFromLowercase
plugin-sdk/security-runtimeShared trust, DM gating, external-content, and secret-collection helpers
plugin-sdk/ssrf-policyHost allowlist and private-network SSRF policy helpers
plugin-sdk/ssrf-runtimePinned-dispatcher, SSRF-guarded fetch, and SSRF policy helpers
plugin-sdk/secret-inputSecret input parsing helpers
plugin-sdk/webhook-ingressWebhook request/target helpers
plugin-sdk/webhook-request-guardsRequest body size/timeout helpers
SubpathKey exports
plugin-sdk/runtimeBroad runtime/logging/backup/plugin-install helpers
plugin-sdk/runtime-envNarrow runtime env, logger, timeout, retry, and backoff helpers
plugin-sdk/runtime-storecreatePluginRuntimeStore
plugin-sdk/plugin-runtimeShared plugin command/hook/http/interactive helpers
plugin-sdk/hook-runtimeShared webhook/internal hook pipeline helpers
plugin-sdk/lazy-runtimeLazy runtime import/binding helpers such as createLazyRuntimeModule, createLazyRuntimeMethod, and createLazyRuntimeSurface
plugin-sdk/process-runtimeProcess exec helpers
plugin-sdk/cli-runtimeCLI formatting, wait, and version helpers
plugin-sdk/gateway-runtimeGateway client and channel-status patch helpers
plugin-sdk/config-runtimeConfig load/write helpers
plugin-sdk/telegram-command-configTelegram command-name/description normalization and duplicate/conflict checks, even when the bundled Telegram contract surface is unavailable
plugin-sdk/approval-runtimeExec/plugin approval helpers, approval-capability builders, auth/profile helpers, native routing/runtime helpers
plugin-sdk/reply-runtimeShared inbound/reply runtime helpers, chunking, dispatch, heartbeat, reply planner
plugin-sdk/reply-dispatch-runtimeNarrow reply dispatch/finalize helpers
plugin-sdk/reply-historyShared short-window reply-history helpers such as buildHistoryContext, recordPendingHistoryEntry, and clearHistoryEntriesIfEnabled
plugin-sdk/reply-referencecreateReplyReferencePlanner
plugin-sdk/reply-chunkingNarrow text/markdown chunking helpers
plugin-sdk/session-store-runtimeSession store path + updated-at helpers
plugin-sdk/state-pathsState/OAuth dir path helpers
plugin-sdk/routingRoute/session-key/account binding helpers such as resolveAgentRoute, buildAgentSessionKey, and resolveDefaultAgentBoundAccountId
plugin-sdk/status-helpersShared channel/account status summary helpers, runtime-state defaults, and issue metadata helpers
plugin-sdk/target-resolver-runtimeShared target resolver helpers
plugin-sdk/string-normalization-runtimeSlug/string normalization helpers
plugin-sdk/request-urlExtract string URLs from fetch/request-like inputs
plugin-sdk/run-commandTimed command runner with normalized stdout/stderr results
plugin-sdk/param-readersCommon tool/CLI param readers
plugin-sdk/tool-sendExtract canonical send target fields from tool args
plugin-sdk/temp-pathShared temp-download path helpers
plugin-sdk/logging-coreSubsystem logger and redaction helpers
plugin-sdk/markdown-table-runtimeMarkdown table mode helpers
plugin-sdk/json-storeSmall JSON state read/write helpers
plugin-sdk/file-lockRe-entrant file-lock helpers
plugin-sdk/persistent-dedupeDisk-backed dedupe cache helpers
plugin-sdk/acp-runtimeACP runtime/session helpers
plugin-sdk/agent-config-primitivesNarrow agent runtime config-schema primitives
plugin-sdk/boolean-paramLoose boolean param reader
plugin-sdk/dangerous-name-runtimeDangerous-name matching resolution helpers
plugin-sdk/device-bootstrapDevice bootstrap and pairing token helpers
plugin-sdk/extension-sharedShared passive-channel and status helper primitives
plugin-sdk/models-provider-runtime/models command/provider reply helpers
plugin-sdk/skill-commands-runtimeSkill command listing helpers
plugin-sdk/native-command-registryNative command registry/build/serialize helpers
plugin-sdk/provider-zai-endpointZ.AI endpoint detection 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, formatting, shared error classification helpers, isApprovalNotFoundError
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
SubpathKey exports
plugin-sdk/media-runtimeShared media fetch/transform/store helpers plus media payload builders
plugin-sdk/media-understandingMedia understanding provider types plus provider-facing image/audio helper exports
plugin-sdk/text-runtimeShared text/markdown/logging helpers such as assistant-visible-text stripping, markdown render/chunking/table helpers, redaction helpers, directive-tag helpers, and safe-text utilities
plugin-sdk/text-chunkingOutbound text chunking helper
plugin-sdk/speechSpeech provider types plus provider-facing directive, registry, and validation helpers
plugin-sdk/speech-coreShared speech provider types, registry, directive, and normalization helpers
plugin-sdk/realtime-transcriptionRealtime transcription provider types and registry helpers
plugin-sdk/realtime-voiceRealtime voice provider types and registry helpers
plugin-sdk/image-generationImage generation provider types
plugin-sdk/image-generation-coreShared image-generation types, failover, auth, and registry helpers
plugin-sdk/video-generationVideo generation provider/request/result types
plugin-sdk/video-generation-coreShared video-generation types, failover helpers, provider lookup, and model-ref parsing
plugin-sdk/webhook-targetsWebhook target registry and route-install helpers
plugin-sdk/webhook-pathWebhook path normalization helpers
plugin-sdk/web-mediaShared remote/local media loading helpers
plugin-sdk/zodRe-exported zod for plugin SDK consumers
plugin-sdk/testinginstallCommonResolveTargetErrorCases, shouldAckReaction
SubpathKey exports
plugin-sdk/memory-coreBundled memory-core helper surface for manager/config/file/CLI helpers
plugin-sdk/memory-core-engine-runtimeMemory index/search runtime facade
plugin-sdk/memory-core-host-engine-foundationMemory host foundation engine exports
plugin-sdk/memory-core-host-engine-embeddingsMemory host embedding engine exports
plugin-sdk/memory-core-host-engine-qmdMemory host QMD engine exports
plugin-sdk/memory-core-host-engine-storageMemory host storage engine exports
plugin-sdk/memory-core-host-multimodalMemory host multimodal helpers
plugin-sdk/memory-core-host-queryMemory host query helpers
plugin-sdk/memory-core-host-secretMemory host secret helpers
plugin-sdk/memory-core-host-statusMemory host status helpers
plugin-sdk/memory-core-host-runtime-cliMemory host CLI runtime helpers
plugin-sdk/memory-core-host-runtime-coreMemory host core runtime helpers
plugin-sdk/memory-core-host-runtime-filesMemory host file/runtime helpers
plugin-sdk/memory-lancedbBundled memory-lancedb helper surface
FamilyCurrent subpathsIntended use
Browserplugin-sdk/browser-config-support, plugin-sdk/browser-supportBundled browser plugin support helpers
Matrixplugin-sdk/matrix, plugin-sdk/matrix-helper, plugin-sdk/matrix-runtime-heavy, plugin-sdk/matrix-runtime-shared, plugin-sdk/matrix-runtime-surface, plugin-sdk/matrix-surface, plugin-sdk/matrix-thread-bindingsBundled Matrix helper/runtime surface
Lineplugin-sdk/line, plugin-sdk/line-core, plugin-sdk/line-runtime, plugin-sdk/line-surfaceBundled LINE helper/runtime surface
IRCplugin-sdk/irc, plugin-sdk/irc-surfaceBundled IRC helper surface
Channel-specific helpersplugin-sdk/googlechat, plugin-sdk/zalouser, plugin-sdk/bluebubbles, plugin-sdk/bluebubbles-policy, plugin-sdk/mattermost, plugin-sdk/mattermost-policy, plugin-sdk/feishu-conversation, plugin-sdk/msteams, plugin-sdk/nextcloud-talk, plugin-sdk/nostr, plugin-sdk/tlon, plugin-sdk/twitchBundled channel compatibility/helper seams
Auth/plugin-specific helpersplugin-sdk/github-copilot-login, plugin-sdk/github-copilot-token, plugin-sdk/diagnostics-otel, plugin-sdk/diffs, plugin-sdk/llm-task, plugin-sdk/thread-ownership, plugin-sdk/voice-callBundled feature/plugin helper seams; plugin-sdk/github-copilot-token currently exports DEFAULT_COPILOT_API_BASE_URL, deriveCopilotApiBaseUrlFromToken, and resolveCopilotApiToken

Registration API

The register(api) callback receives an OpenClawPluginApi object with these methods:

Capability registration

MethodWhat 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.registerRealtimeTranscriptionProvider(...)Streaming realtime transcription
api.registerRealtimeVoiceProvider(...)Duplex realtime voice sessions
api.registerMediaUnderstandingProvider(...)Image/audio/video analysis
api.registerImageGenerationProvider(...)Image generation
api.registerVideoGenerationProvider(...)Video generation
api.registerWebFetchProvider(...)Web fetch / scrape provider
api.registerWebSearchProvider(...)Web search

Tools and commands

MethodWhat it registers
api.registerTool(tool, opts?)Agent tool (required or { optional: true })
api.registerCommand(def)Custom command (bypasses the LLM)

Infrastructure

MethodWhat 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
Reserved core admin namespaces (config.*, exec.approvals.*, wizard.*, update.*) always stay operator.admin, even if a plugin tries to assign a narrower gateway method scope. Prefer plugin-specific prefixes for plugin-owned methods.

CLI registration metadata

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.
api.registerCli(
  async ({ program }) => {
    const { registerMatrixCli } = await import("./src/cli.js");
    registerMatrixCli({ program });
  },
  {
    descriptors: [
      {
        name: "matrix",
        description: "Manage Matrix accounts, verification, devices, and profile state",
        hasSubcommands: true,
      },
    ],
  },
);
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.

CLI backend registration

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).

Exclusive slots

MethodWhat 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

Memory embedding adapters

MethodWhat 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.

Events and lifecycle

MethodWhat it does
api.on(hookName, handler, opts?)Typed lifecycle hook
api.onConversationBindingResolved(handler)Conversation binding callback

Hook decision semantics

  • 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.

API object fields

FieldTypeDescription
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 (active in-memory runtime snapshot when available)
api.pluginConfigRecord<string, unknown>Plugin-specific config from plugins.entries.<id>.config
api.runtimePluginRuntimeRuntime helpers
api.loggerPluginLoggerScoped logger (debug, info, warn, error)
api.registrationModePluginRegistrationModeCurrent load mode; "setup-runtime" is the lightweight pre-full-entry startup/setup window
api.resolvePath(input)(string) => stringResolve path relative to plugin root

Internal module convention

Within your plugin, use local barrel files for internal imports:
my-plugin/
  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)
Never import your own plugin through openclaw/plugin-sdk/<your-plugin> from production code. Route internal imports through ./api.ts or ./runtime-api.ts. The SDK path is the external contract only.
Facade-loaded bundled plugin public surfaces (api.ts, runtime-api.ts, index.ts, setup-entry.ts, and similar public entry files) now prefer the active runtime config snapshot when OpenClaw is already running. If no runtime snapshot exists yet, they fall back to the resolved config file on disk. Provider plugins can also expose a narrow plugin-local contract barrel when a helper is intentionally provider-specific and does not belong in a generic SDK subpath yet. Current bundled example: the Anthropic provider keeps its Claude stream helpers in its own public api.ts / contract-api.ts seam instead of promoting Anthropic beta-header and service_tier logic into a generic plugin-sdk/* contract. Other current bundled examples:
  • @openclaw/openai-provider: api.ts exports provider builders, default-model helpers, and realtime provider builders
  • @openclaw/openrouter-provider: api.ts exports the provider builder plus onboarding/config helpers
Extension production code should also avoid openclaw/plugin-sdk/<other-plugin> imports. If a helper is truly shared, promote it to a neutral SDK subpath such as openclaw/plugin-sdk/speech, .../provider-model-shared, or another capability-oriented surface instead of coupling two plugins together.