Plugins extend OpenClaw with new capabilities: channels, model providers, speech, realtime transcription, realtime voice, media understanding, image generation, video generation, web fetch, web search, agent tools, or any combination. You do not need to add your plugin to the OpenClaw repository. Publish to ClawHub and users install withDocumentation Index
Fetch the complete documentation index at: https://docs.openclaw.ai/llms.txt
Use this file to discover all available pages before exploring further.
openclaw plugins install clawhub:<package-name>. Bare package specs still
install from npm during the launch cutover.
Prerequisites
- Node >= 22 and a package manager (npm or pnpm)
- Familiarity with TypeScript (ESM)
- For in-repo plugins: repository cloned and
pnpm installdone. Source checkout plugin development is pnpm-only because OpenClaw loads bundled plugins from theextensions/*workspace packages.
What kind of plugin?
Channel plugin
Connect OpenClaw to a messaging platform (Discord, IRC, etc.)
Provider plugin
Add a model provider (LLM, proxy, or custom endpoint)
Tool / hook plugin
Register agent tools, event hooks, or services — continue below
createOptionalChannelSetupSurface(...) from
openclaw/plugin-sdk/channel-setup. It produces a setup adapter + wizard pair
that advertises the install requirement and fails closed on real config writes
until the plugin is installed.
Quick start: tool plugin
This walkthrough creates a minimal plugin that registers an agent tool. Channel and provider plugins have dedicated guides linked above.Create the package and manifest
contracts.tools so OpenClaw can discover the owning
plugin without loading every plugin runtime. Plugins should also declare
activation.onStartup intentionally. This example sets it to true. See
Manifest for the full schema. The canonical ClawHub
publish snippets live in docs/snippets/plugin-publish/.Write the entry point
definePluginEntry is for non-channel plugins. For channels, use
defineChannelPluginEntry — see Channel Plugins.
For full entry point options, see Entry Points.Test and publish
External plugins: validate and publish with ClawHub, then install:Bare package specs like
@myorg/openclaw-my-plugin install from npm during
the launch cutover. Use clawhub: when you want ClawHub resolution.In-repo plugins: place under the bundled plugin workspace tree — automatically discovered.Plugin capabilities
A single plugin can register any number of capabilities via theapi object:
| Capability | Registration method | Detailed guide |
|---|---|---|
| Text inference (LLM) | api.registerProvider(...) | Provider Plugins |
| CLI inference backend | api.registerCliBackend(...) | CLI Backends |
| Channel / messaging | api.registerChannel(...) | Channel Plugins |
| Speech (TTS/STT) | api.registerSpeechProvider(...) | Provider Plugins |
| Realtime transcription | api.registerRealtimeTranscriptionProvider(...) | Provider Plugins |
| Realtime voice | api.registerRealtimeVoiceProvider(...) | Provider Plugins |
| Media understanding | api.registerMediaUnderstandingProvider(...) | Provider Plugins |
| Image generation | api.registerImageGenerationProvider(...) | Provider Plugins |
| Music generation | api.registerMusicGenerationProvider(...) | Provider Plugins |
| Video generation | api.registerVideoGenerationProvider(...) | Provider Plugins |
| Web fetch | api.registerWebFetchProvider(...) | Provider Plugins |
| Web search | api.registerWebSearchProvider(...) | Provider Plugins |
| Tool-result middleware | api.registerAgentToolResultMiddleware(...) | SDK Overview |
| Agent tools | api.registerTool(...) | Below |
| Custom commands | api.registerCommand(...) | Entry Points |
| Plugin hooks | api.on(...) | Plugin hooks |
| Internal event hooks | api.registerHook(...) | Entry Points |
| HTTP routes | api.registerHttpRoute(...) | Internals |
| CLI subcommands | api.registerCli(...) | Entry Points |
api.registerAgentToolResultMiddleware(...) when they
need async tool-result rewriting before the model sees the output. Declare the
targeted runtimes in contracts.agentToolResultMiddleware, for example
["pi", "codex"]. This is a trusted bundled-plugin seam; external
plugins should prefer regular OpenClaw plugin hooks unless OpenClaw grows an
explicit trust policy for this capability.
If your plugin registers custom gateway RPC methods, keep them on a
plugin-specific prefix. Core admin namespaces (config.*,
exec.approvals.*, wizard.*, update.*) stay reserved and always resolve to
operator.admin, even if a plugin asks for a narrower scope.
Hook guard semantics to keep in mind:
before_tool_call:{ block: true }is terminal and stops lower-priority handlers.before_tool_call:{ block: false }is treated as no decision.before_tool_call:{ requireApproval: true }pauses agent execution and prompts the user for approval via the exec approval overlay, Telegram buttons, Discord interactions, or the/approvecommand on any channel.before_install:{ block: true }is terminal and stops lower-priority handlers.before_install:{ block: false }is treated as no decision.message_sending:{ cancel: true }is terminal and stops lower-priority handlers.message_sending:{ cancel: false }is treated as no decision.message_received: prefer the typedthreadIdfield when you need inbound thread/topic routing. Keepmetadatafor channel-specific extras.message_sending: prefer typedreplyToId/threadIdrouting fields over channel-specific metadata keys.
/approve command handles both exec and plugin approvals with bounded fallback: when an exec approval id is not found, OpenClaw retries the same id through plugin approvals. Plugin approval forwarding can be configured independently via approvals.plugin in config.
If custom approval plumbing needs to detect that same bounded fallback case,
prefer isApprovalNotFoundError from openclaw/plugin-sdk/error-runtime
instead of matching approval-expiry strings manually.
See Plugin hooks for examples and the hook reference.
Registering agent tools
Tools are typed functions the LLM can call. They can be required (always available) or optional (user opt-in):api.registerTool(...) must also be declared in the
plugin manifest:
description or schema data in the manifest. The
manifest contract only declares ownership and discovery; execution still calls
the live registered tool implementation.
Set toolMetadata.<tool>.optional: true for tools registered with
api.registerTool(..., { optional: true }) so OpenClaw can avoid loading that
plugin runtime until the tool is explicitly allowlisted.
Users enable optional tools in config:
- Tool names must not clash with core tools (conflicts are skipped)
- Tools with malformed registration objects, including missing
parameters, are skipped and reported in plugin diagnostics instead of breaking agent runs - Use
optional: truefor tools with side effects or extra binary requirements - Users can enable all tools from a plugin by adding the plugin id to
tools.allow
Registering CLI commands
Plugins can add rootopenclaw command groups with api.registerCli. Provide
descriptors for every top-level command root so OpenClaw can show and route
the command without eagerly loading every plugin runtime.
Import conventions
Always import from focusedopenclaw/plugin-sdk/<subpath> paths:
api.ts, runtime-api.ts) for
internal imports — never import your own plugin through its SDK path.
For provider plugins, keep provider-specific helpers in those package-root
barrels unless the seam is truly generic. Current bundled examples:
- Anthropic: Claude stream wrappers and
service_tier/ beta helpers - OpenAI: provider builders, default-model helpers, realtime providers
- OpenRouter: provider builder plus onboarding/config helpers
openclaw/plugin-sdk/*.
Some generated openclaw/plugin-sdk/<bundled-id> helper seams still exist for
bundled-plugin maintenance when they have tracked owner usage. Treat those as
reserved surfaces, not as the default pattern for new third-party plugins.
Pre-submission checklist
package.json has correct
openclaw metadataopenclaw.plugin.json manifest is present and valid
Entry point uses
defineChannelPluginEntry or definePluginEntryAll imports use focused
plugin-sdk/<subpath> pathsInternal imports use local modules, not SDK self-imports
Tests pass (
pnpm test -- <bundled-plugin-root>/my-plugin/)pnpm check passes (in-repo plugins)Beta release testing
- Watch for GitHub release tags on openclaw/openclaw and subscribe via
Watch>Releases. Beta tags look likev2026.3.N-beta.1. You can also turn on notifications for the official OpenClaw X account @openclaw for release announcements. - Test your plugin against the beta tag as soon as it appears. The window before stable is typically only a few hours.
- Post in your plugin’s thread in the
plugin-forumDiscord channel after testing with eitherall goodor what broke. If you do not have a thread yet, create one. - If something breaks, open or update an issue titled
Beta blocker: <plugin-name> - <summary>and apply thebeta-blockerlabel. Put the issue link in your thread. - Open a PR to
maintitledfix(<plugin-id>): beta blocker - <summary>and link the issue in both the PR and your Discord thread. Contributors cannot label PRs, so the title is the PR-side signal for maintainers and automation. Blockers with a PR get merged; blockers without one might ship anyway. Maintainers watch these threads during beta testing. - Silence means green. If you miss the window, your fix likely lands in the next cycle.
Next steps
Channel Plugins
Build a messaging channel plugin
Provider Plugins
Build a model provider plugin
SDK Overview
Import map and registration API reference
Runtime Helpers
TTS, search, subagent via api.runtime
Testing
Test utilities and patterns
Plugin Manifest
Full manifest schema reference
Related
- Plugin Architecture — internal architecture deep dive
- SDK Overview — Plugin SDK reference
- Manifest — plugin manifest format
- Channel Plugins — building channel plugins
- Provider Plugins — building provider plugins