OpenClaw plugins are where the platform stops being a fixed product and starts becoming infrastructure. They can add tools, channels, providers, hooks, commands, and background services. If prompts tell the agent how to think, plugins decide what it can actually do.
The useful mental model is this: a plugin is not a random script bolted onto the side. It is closer to adding a new circuit to a breaker panel. Done right, everything is labeled, isolated, and easy to debug. Done badly, one loose wire can waste an afternoon.
Start by choosing the right plugin type
OpenClaw supports several plugin shapes. The official plugin development docs call out four common starting points: channel plugins, provider plugins, CLI backend plugins, and tool or hook plugins.
- Tool or hook plugin: Best when you want to add a new agent tool, command, service, or workflow hook.
- Provider plugin: Best when you want OpenClaw to speak to a new model, speech, media, or search backend.
- Channel plugin: Best when you are connecting OpenClaw to a messaging surface like a chat platform.
- CLI backend plugin: Best when you are mapping a local coding or inference CLI into OpenClaw.
Most first plugins should be simple tool plugins. They are easier to reason about, easier to test, and they force you to learn the SDK without also owning a whole transport layer.
The manifest is your passport
Before OpenClaw trusts your runtime code, it reads openclaw.plugin.json. Think of that file as a passport plus cargo label. It tells the gateway who you are, what config shape you expect, which capabilities you claim, and whether it should load you at startup.
This is not paperwork for paperwork's sake. Browser extension history taught the whole software world the same lesson: extensibility without declared permissions becomes chaos fast. OpenClaw avoids that by validating plugin metadata before executing runtime code.
If you need the exact field reference, the official manifest reference is the right source. In practice, these fields matter first:
idfor the canonical plugin idconfigSchemafor validation and setup UXcontracts.toolswhen your plugin registers runtime toolsactivation.onStartupwhen the plugin should load intentionally at boot
Minimal tool plugin shape
A basic tool plugin needs three moving parts: package metadata, a manifest, and an entry file that calls the SDK registration API.
// index.ts
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
import { Type } from "@sinclair/typebox";
export default definePluginEntry({
id: "my-plugin",
name: "My Plugin",
description: "Adds one focused tool",
register(api) {
api.registerTool({
name: "my_tool",
description: "Do a thing",
parameters: Type.Object({
input: Type.String(),
}),
async execute(_id, params) {
return {
content: [{ type: "text", text: "Got: ${params.input}" }],
};
},
});
},
});Notice what is missing: no giant framework layer, no magic folder scanning, and no loose runtime side effects. Your job is to register a capability cleanly and keep its boundary obvious.
A practical build workflow
- Start with one job. If your first idea needs tools, hooks, background services, and a channel at once, split it.
- Create package metadata. Declare the OpenClaw extension entry in
package.json. - Write the manifest. Keep the config schema strict. Loose schemas become support debt later.
- Register one capability. A single tool is enough to prove the package works end to end.
- Test locally. Validate runtime registration before you think about publishing.
- Publish with intent. External plugins belong in ClawHub or another install path you can actually support.
There is a reason experienced plugin authors move this way. It follows the old carpenter rule, measure twice, cut once. In plugin work, your measurements are config schema, contracts, and runtime boundaries.
Bundled plugin or external plugin?
| Situation | Better choice | Why |
|---|---|---|
| Community feature or private team tool | External plugin | Faster iteration and cleaner ownership |
| Core platform capability used by many installs | Bundled plugin | Tighter lifecycle with the OpenClaw repo |
| Source checkout development | Bundled workspace flow | Repo plugins are loaded from workspace packages |
| Simple distribution to users | ClawHub package | Cleaner install path and discovery story |
Common mistakes that make plugins feel fragile
Forgetting static contracts
If you register a tool at runtime but forget to declare it in contracts.tools, discovery becomes muddier and debugging gets weird. OpenClaw is explicit here for a reason.
Importing the SDK too broadly
The SDK overview recommends specific subpath imports. That keeps startup lighter and avoids accidental dependency tangles. If you import huge barrels just because they are convenient, you are borrowing future pain.
Shipping TypeScript without runtime output
Local source checkouts can be forgiving. Published packages are not. If your npm package only ships source files and no compiled runtime output, installation may succeed while runtime loading still fails.
Trying to solve policy with code alone
Plugins can be powerful enough to touch external systems, approvals, and sensitive data. When something feels risky, the answer is usually a tighter contract, clearer config, or a narrower tool surface, not just more clever implementation.
When not to build a plugin
Not every extension idea needs one. If you only need a one-off workflow inside a single environment, a skill, a standing order, or an MCP server may be cheaper to maintain. Build a plugin when you need a reusable capability with a clean install story and a stable boundary.
Security mindset for plugin authors
- Keep the surface area small. Narrow tools are easier to trust than swiss-army tools.
- Validate inputs hard. Config schema and tool parameters are part of the product, not clerical work.
- Declare ownership clearly. Channels, providers, tools, and commands should be obvious from metadata.
- Fail closed. If config is missing or invalid, do not pretend the plugin is half-working.
- Treat packaging as part of reliability. Installation, upgrades, and inspection matter just as much as the happy-path demo.
Good plugin development in OpenClaw is boring in the best way. The package installs cleanly, the manifest explains itself, the runtime registers exactly what it owns, and the operator does not need detective work to trust it.
Need help from people who already use this stuff?
Building your first plugin?
Bring your plugin idea, manifest draft, or SDK questions into the community and get practical feedback before you publish something brittle.
FAQ
Do I need to fork OpenClaw to build a plugin?
No. External plugins can live in their own package and be published through ClawHub or installed from npm, git, or a local path. You only need the main repo when you are working on bundled plugins inside the source checkout.
What file is mandatory for every native plugin?
Every native OpenClaw plugin needs an openclaw.plugin.json file in the plugin root. OpenClaw reads it before loading plugin code, which is why it is the place for identity, config schema, activation hints, and declared contracts.
When should I use definePluginEntry versus defineChannelPluginEntry?
Use definePluginEntry for non-channel plugins such as tools, hooks, commands, or providers that do not implement a messaging channel. Use defineChannelPluginEntry when the plugin itself owns a channel integration.
Why does OpenClaw ask me to list tools in contracts.tools?
Because the gateway wants to know which plugin owns which runtime tool without loading every plugin first. Declaring contracts.tools keeps discovery fast and avoids blind runtime imports.
What is the most common packaging mistake?
Publishing TypeScript source without the compiled JavaScript runtime is a classic one. Source checkouts can work with pnpm in the repo, but packaged installs still need real runtime output that OpenClaw can load.