Files
openclaw/docs/plugins/building-plugins.md
Vincent Koc 28838802d4 docs(plugins): add SDK reference and how-to guide pages (#52366)
* docs(plugins): add SDK reference and how-to guide pages

Create 7 new plugin SDK documentation pages:
- sdk-overview: import map, registration API reference
- sdk-entrypoints: definePluginEntry/defineChannelPluginEntry reference
- sdk-runtime: api.runtime namespace reference
- sdk-setup: packaging, manifests, config schemas reference
- sdk-channel-plugins: step-by-step channel plugin how-to
- sdk-provider-plugins: step-by-step provider plugin how-to
- sdk-testing: test utilities and patterns reference

Restructure plugin docs navigation with nested groups:
- Top-level: user-facing pages (Install, Community, Bundles)
- Building Plugins: Getting Started, Channel, Provider
- SDK Reference: Overview, Entry Points, Runtime, Setup, Testing, Migration, Manifest, Internals

Revise existing pages for new IA:
- building-plugins.md: tightened as quick-start, routes to detailed guides
- architecture.md: updated info box with links to new guides
- sdk-migration.md: expanded Related section

* docs(plugins): add Mintlify components (Steps, CodeGroup, Tabs, Accordion, CardGroup)

- Channel plugin guide: wrap walkthrough in Steps, use CodeGroup for
  package.json/manifest, Accordion for createChatChannelPlugin details,
  CardGroup for advanced topics
- Provider plugin guide: wrap walkthrough in Steps, use CodeGroup for
  package files, Tabs for hook examples, Accordion for all-hooks reference
- Getting started: use CardGroup for plugin-type picker and next steps,
  CodeGroup for package/manifest
- SDK Overview: wrap subpath tables in AccordionGroup for scannability

* fix(docs): address PR review feedback on plugin SDK pages

- Remove nonexistent api.runtime.channel.handleInboundMessage call,
  replace with realistic webhook pattern and note about channel-specific
  inbound handling (issue a)
- Fix registrationMode values: 'setup' -> 'setup-only' and 'setup-runtime'
  matching actual PluginRegistrationMode type (issue b)
- Fix createOptionalChannelSetupSurface params: channelId -> channel,
  add required label field (issue c)
- Fix broken anchor links: #multi-capability-providers ->
  #step-5-add-extra-capabilities, #plugin-kinds -> #registration-api (issue d)
- Add missing acmeChatApi import in channel plugin example (issue e)
- Fix undefined provider variable in provider test example (issue f)

* fix(docs): use correct createProviderApiKeyAuthMethod options

Replace incorrect params (provider, validate) with actual required fields
(providerId, methodId, optionKey, flagName, promptMessage) matching
src/plugins/provider-api-key-auth.ts.

* fix(docs): address second round of PR review feedback

- Add required model fields (reasoning, input, cost, contextWindow,
  maxTokens) to catalog example (issue b)
- Fix buildChannelConfigSchema to take a Zod schema argument (issue c)
- Replace fabricated setupWizard steps/run with real ChannelSetupWizard
  contract (channel, status, credentials) (issue d)
- Add required sessionFile/workspaceDir to runEmbeddedPiAgent (issue e)
- Fix wrapStreamFn to return StreamFn from ctx.streamFn (issue f)
2026-03-22 11:35:53 -07:00

237 lines
8.4 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 on npm
and users install with `openclaw plugins install <npm-spec>`.
## 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="message" href="/plugins/sdk-channel-plugins">
Connect OpenClaw to a messaging platform (Discord, IRC, etc.)
</Card>
<Card title="Provider plugin" icon="microchip" 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:**
```bash
npm publish
openclaw plugins install @myorg/openclaw-my-plugin
```
**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="message" href="/plugins/sdk-channel-plugins">
Build a messaging channel plugin
</Card>
<Card title="Provider Plugins" icon="microchip" href="/plugins/sdk-provider-plugins">
Build a model provider plugin
</Card>
<Card title="SDK Overview" icon="book" href="/plugins/sdk-overview">
Import map and registration API reference
</Card>
<Card title="Runtime Helpers" icon="gear" href="/plugins/sdk-runtime">
TTS, search, subagent via api.runtime
</Card>
<Card title="Testing" icon="flask" href="/plugins/sdk-testing">
Test utilities and patterns
</Card>
<Card title="Plugin Manifest" icon="file-code" href="/plugins/manifest">
Full manifest schema reference
</Card>
</CardGroup>