Building Plugins
Plugins extend OpenClaw with new capabilities: channels, model providers, speech, image generation, web search, agent tools, or any combination. A single plugin can register multiple capabilities. OpenClaw encourages external plugin development. You do not need to add your plugin to the OpenClaw repository. Publish your plugin on npm, and users install it withopenclaw plugins install <npm-spec>. OpenClaw also maintains a set of
core plugins in-repo, but the plugin system is designed for independent ownership
and distribution.
Prerequisites
- Node >= 22 and a package manager (npm or pnpm)
- Familiarity with TypeScript (ESM)
- For in-repo plugins: OpenClaw repository cloned and
pnpm installdone
Plugin capabilities
A plugin can register one or more capabilities. The capability you register determines what your plugin provides to OpenClaw:| Capability | Registration method | What it adds |
|---|---|---|
| Text inference | api.registerProvider(...) | Model provider (LLM) |
| Channel / messaging | api.registerChannel(...) | Chat channel (e.g. Slack, IRC) |
| Speech | api.registerSpeechProvider(...) | Text-to-speech / STT |
| Media understanding | api.registerMediaUnderstandingProvider(...) | Image/audio/video analysis |
| Image generation | api.registerImageGenerationProvider(...) | Image generation |
| Web search | api.registerWebSearchProvider(...) | Web search provider |
| Agent tools | api.registerTool(...) | Tools callable by the agent |
Plugin structure
Plugins follow this layout (whether in-repo or standalone):Create a plugin
Create the package
Create Provider plugin example:The
package.json with the openclaw metadata block. The structure
depends on what capabilities your plugin provides.Channel plugin example:openclaw field tells the plugin system what your plugin provides.
A plugin can declare both channel and providers if it provides multiple
capabilities.Define the entry point
The entry point registers your capabilities with the plugin API.Channel plugin:Provider plugin:Multi-capability plugin (provider + tool):Use
defineChannelPluginEntry for channel plugins and definePluginEntry
for everything else. A single plugin can register as many capabilities as needed.Import from focused SDK subpaths
Always import from specific
Use the narrowest subpath that matches the job.
openclaw/plugin-sdk/\<subpath\> paths. The old
monolithic import is deprecated (see SDK Migration).If older plugin code still imports openclaw/extension-api, treat that as a
temporary compatibility bridge only. New code should use injected runtime
helpers such as api.runtime.agent.* instead of importing host-side agent
helpers directly.Common subpaths reference
Common subpaths reference
| Subpath | Purpose |
|---|---|
plugin-sdk/core | Plugin entry definitions and base types |
plugin-sdk/channel-setup | Setup wizard adapters |
plugin-sdk/channel-pairing | DM pairing primitives |
plugin-sdk/channel-reply-pipeline | Reply prefix + typing wiring |
plugin-sdk/channel-config-schema | Config schema builders |
plugin-sdk/channel-policy | Group/DM policy helpers |
plugin-sdk/secret-input | Secret input parsing/helpers |
plugin-sdk/webhook-ingress | Webhook request/target helpers |
plugin-sdk/runtime-store | Persistent plugin storage |
plugin-sdk/allow-from | Allowlist resolution |
plugin-sdk/reply-payload | Message reply types |
plugin-sdk/provider-oauth | OAuth login + PKCE helpers |
plugin-sdk/provider-onboard | Provider onboarding config patches |
plugin-sdk/testing | Test utilities |
Use local modules for internal imports
Within your plugin, create local module files for internal code sharing
instead of re-importing through the plugin SDK:
Add a plugin manifest
Create For channel plugins, set
openclaw.plugin.json in your plugin root:"kind": "channel" and add "channels": ["my-channel"].See Plugin Manifest for the full schema.Test your plugin
External plugins: run your own test suite against the plugin SDK contracts.In-repo plugins: OpenClaw runs contract tests against all registered plugins:For unit tests, import test helpers from the testing surface:
Registering agent tools
Plugins can register agent tools — typed functions the LLM can call. Tools can be required (always available) or optional (users opt in via allowlists).- Tool names must not clash with core tool names (conflicts are skipped)
- Use
optional: truefor tools that trigger side effects or require extra binaries - Users can enable all tools from a plugin by adding the plugin id to
tools.allow
Lint enforcement (in-repo plugins)
Three scripts enforce SDK boundaries for plugins in the OpenClaw repository:- No monolithic root imports —
openclaw/plugin-sdkroot is rejected - No direct src/ imports — plugins cannot import
../../src/directly - No self-imports — plugins cannot import their own
plugin-sdk/\<name\>subpath
pnpm check to verify all boundaries before committing.
External plugins are not subject to these lint rules, but following the same
patterns is strongly recommended.
Pre-submission checklist
package.json has correct
openclaw metadataEntry point uses
defineChannelPluginEntry or definePluginEntryAll imports use focused
plugin-sdk/\<subpath\> pathsInternal imports use local modules, not SDK self-imports
openclaw.plugin.json manifest is present and validTests pass
pnpm check passes (in-repo plugins)Related
- Plugin SDK Migration — migrating from deprecated compat surfaces
- Plugin Architecture — internals and capability model
- Plugin Manifest — full manifest schema
- Plugin Agent Tools — adding agent tools in a plugin
- Community Plugins — listing and quality bar