mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-23 16:01:17 +00:00
OpenClaw now tries ClawHub before npm for bare plugin specs. Update install examples and guidance across: - building-plugins.md: intro and publish step - sdk-setup.md: publishing section with clawhub:/npm: prefix examples - tools/plugin.md: CLI reference table - community.md: submission guidance and quality bar
240 lines
8.6 KiB
Markdown
240 lines
8.6 KiB
Markdown
---
|
|
title: "Building Plugins"
|
|
sidebarTitle: "Getting Started"
|
|
summary: "Create your first OpenClaw plugin in minutes"
|
|
read_when:
|
|
- You want to create a new OpenClaw plugin
|
|
- You need a quick-start for plugin development
|
|
- You are adding a new channel, provider, tool, or other capability to OpenClaw
|
|
---
|
|
|
|
# Building Plugins
|
|
|
|
Plugins extend OpenClaw with new capabilities: channels, model providers, speech,
|
|
image generation, web search, agent tools, or any combination.
|
|
|
|
You do not need to add your plugin to the OpenClaw repository. Publish to
|
|
[ClawHub](/tools/clawhub) or npm and users install with
|
|
`openclaw plugins install <package-name>`. OpenClaw tries ClawHub first and
|
|
falls back to npm automatically.
|
|
|
|
## Prerequisites
|
|
|
|
- Node >= 22 and a package manager (npm or pnpm)
|
|
- Familiarity with TypeScript (ESM)
|
|
- For in-repo plugins: repository cloned and `pnpm install` done
|
|
|
|
## What kind of plugin?
|
|
|
|
<CardGroup cols={3}>
|
|
<Card title="Channel plugin" icon="messages-square" href="/plugins/sdk-channel-plugins">
|
|
Connect OpenClaw to a messaging platform (Discord, IRC, etc.)
|
|
</Card>
|
|
<Card title="Provider plugin" icon="cpu" href="/plugins/sdk-provider-plugins">
|
|
Add a model provider (LLM, proxy, or custom endpoint)
|
|
</Card>
|
|
<Card title="Tool / hook plugin" icon="wrench">
|
|
Register agent tools, event hooks, or services — continue below
|
|
</Card>
|
|
</CardGroup>
|
|
|
|
## Quick start: tool plugin
|
|
|
|
This walkthrough creates a minimal plugin that registers an agent tool. Channel
|
|
and provider plugins have dedicated guides linked above.
|
|
|
|
<Steps>
|
|
<Step title="Create the package and manifest">
|
|
<CodeGroup>
|
|
```json package.json
|
|
{
|
|
"name": "@myorg/openclaw-my-plugin",
|
|
"version": "1.0.0",
|
|
"type": "module",
|
|
"openclaw": {
|
|
"extensions": ["./index.ts"]
|
|
}
|
|
}
|
|
```
|
|
|
|
```json openclaw.plugin.json
|
|
{
|
|
"id": "my-plugin",
|
|
"name": "My Plugin",
|
|
"description": "Adds a custom tool to OpenClaw",
|
|
"configSchema": {
|
|
"type": "object",
|
|
"additionalProperties": false
|
|
}
|
|
}
|
|
```
|
|
</CodeGroup>
|
|
|
|
Every plugin needs a manifest, even with no config. See
|
|
[Manifest](/plugins/manifest) for the full schema.
|
|
|
|
</Step>
|
|
|
|
<Step title="Write the entry point">
|
|
|
|
```typescript
|
|
// 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 a custom tool to OpenClaw",
|
|
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}` }] };
|
|
},
|
|
});
|
|
},
|
|
});
|
|
```
|
|
|
|
`definePluginEntry` is for non-channel plugins. For channels, use
|
|
`defineChannelPluginEntry` — see [Channel Plugins](/plugins/sdk-channel-plugins).
|
|
For full entry point options, see [Entry Points](/plugins/sdk-entrypoints).
|
|
|
|
</Step>
|
|
|
|
<Step title="Test and publish">
|
|
|
|
**External plugins:** publish to [ClawHub](/tools/clawhub) or npm, then install:
|
|
|
|
```bash
|
|
openclaw plugins install @myorg/openclaw-my-plugin
|
|
```
|
|
|
|
OpenClaw checks ClawHub first, then falls back to npm.
|
|
|
|
**In-repo plugins:** place under `extensions/` — automatically discovered.
|
|
|
|
```bash
|
|
pnpm test -- extensions/my-plugin/
|
|
```
|
|
|
|
</Step>
|
|
</Steps>
|
|
|
|
## Plugin capabilities
|
|
|
|
A single plugin can register any number of capabilities via the `api` object:
|
|
|
|
| Capability | Registration method | Detailed guide |
|
|
| -------------------- | --------------------------------------------- | ------------------------------------------------------------------------------- |
|
|
| Text inference (LLM) | `api.registerProvider(...)` | [Provider Plugins](/plugins/sdk-provider-plugins) |
|
|
| Channel / messaging | `api.registerChannel(...)` | [Channel Plugins](/plugins/sdk-channel-plugins) |
|
|
| Speech (TTS/STT) | `api.registerSpeechProvider(...)` | [Provider Plugins](/plugins/sdk-provider-plugins#step-5-add-extra-capabilities) |
|
|
| Media understanding | `api.registerMediaUnderstandingProvider(...)` | [Provider Plugins](/plugins/sdk-provider-plugins#step-5-add-extra-capabilities) |
|
|
| Image generation | `api.registerImageGenerationProvider(...)` | [Provider Plugins](/plugins/sdk-provider-plugins#step-5-add-extra-capabilities) |
|
|
| Web search | `api.registerWebSearchProvider(...)` | [Provider Plugins](/plugins/sdk-provider-plugins#step-5-add-extra-capabilities) |
|
|
| Agent tools | `api.registerTool(...)` | Below |
|
|
| Custom commands | `api.registerCommand(...)` | [Entry Points](/plugins/sdk-entrypoints) |
|
|
| Event hooks | `api.registerHook(...)` | [Entry Points](/plugins/sdk-entrypoints) |
|
|
| HTTP routes | `api.registerHttpRoute(...)` | [Internals](/plugins/architecture#gateway-http-routes) |
|
|
| CLI subcommands | `api.registerCli(...)` | [Entry Points](/plugins/sdk-entrypoints) |
|
|
|
|
For the full registration API, see [SDK Overview](/plugins/sdk-overview#registration-api).
|
|
|
|
## Registering agent tools
|
|
|
|
Tools are typed functions the LLM can call. They can be required (always
|
|
available) or optional (user opt-in):
|
|
|
|
```typescript
|
|
register(api) {
|
|
// Required tool — always available
|
|
api.registerTool({
|
|
name: "my_tool",
|
|
description: "Do a thing",
|
|
parameters: Type.Object({ input: Type.String() }),
|
|
async execute(_id, params) {
|
|
return { content: [{ type: "text", text: params.input }] };
|
|
},
|
|
});
|
|
|
|
// Optional tool — user must add to allowlist
|
|
api.registerTool(
|
|
{
|
|
name: "workflow_tool",
|
|
description: "Run a workflow",
|
|
parameters: Type.Object({ pipeline: Type.String() }),
|
|
async execute(_id, params) {
|
|
return { content: [{ type: "text", text: params.pipeline }] };
|
|
},
|
|
},
|
|
{ optional: true },
|
|
);
|
|
}
|
|
```
|
|
|
|
Users enable optional tools in config:
|
|
|
|
```json5
|
|
{
|
|
tools: { allow: ["workflow_tool"] },
|
|
}
|
|
```
|
|
|
|
- Tool names must not clash with core tools (conflicts are skipped)
|
|
- Use `optional: true` for tools with side effects or extra binary requirements
|
|
- Users can enable all tools from a plugin by adding the plugin id to `tools.allow`
|
|
|
|
## Import conventions
|
|
|
|
Always import from focused `openclaw/plugin-sdk/<subpath>` paths:
|
|
|
|
```typescript
|
|
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
|
|
import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store";
|
|
|
|
// Wrong: monolithic root (deprecated, will be removed)
|
|
import { ... } from "openclaw/plugin-sdk";
|
|
```
|
|
|
|
For the full subpath reference, see [SDK Overview](/plugins/sdk-overview).
|
|
|
|
Within your plugin, use local barrel files (`api.ts`, `runtime-api.ts`) for
|
|
internal imports — never import your own plugin through its SDK path.
|
|
|
|
## Pre-submission checklist
|
|
|
|
<Check>**package.json** has correct `openclaw` metadata</Check>
|
|
<Check>**openclaw.plugin.json** manifest is present and valid</Check>
|
|
<Check>Entry point uses `defineChannelPluginEntry` or `definePluginEntry`</Check>
|
|
<Check>All imports use focused `plugin-sdk/<subpath>` paths</Check>
|
|
<Check>Internal imports use local modules, not SDK self-imports</Check>
|
|
<Check>Tests pass (`pnpm test -- extensions/my-plugin/`)</Check>
|
|
<Check>`pnpm check` passes (in-repo plugins)</Check>
|
|
|
|
## Next steps
|
|
|
|
<CardGroup cols={2}>
|
|
<Card title="Channel Plugins" icon="messages-square" href="/plugins/sdk-channel-plugins">
|
|
Build a messaging channel plugin
|
|
</Card>
|
|
<Card title="Provider Plugins" icon="cpu" href="/plugins/sdk-provider-plugins">
|
|
Build a model provider plugin
|
|
</Card>
|
|
<Card title="SDK Overview" icon="book-open" href="/plugins/sdk-overview">
|
|
Import map and registration API reference
|
|
</Card>
|
|
<Card title="Runtime Helpers" icon="settings" href="/plugins/sdk-runtime">
|
|
TTS, search, subagent via api.runtime
|
|
</Card>
|
|
<Card title="Testing" icon="test-tubes" href="/plugins/sdk-testing">
|
|
Test utilities and patterns
|
|
</Card>
|
|
<Card title="Plugin Manifest" icon="file-json" href="/plugins/manifest">
|
|
Full manifest schema reference
|
|
</Card>
|
|
</CardGroup>
|