* 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)
6.6 KiB
title, sidebarTitle, summary, read_when
| title | sidebarTitle | summary | read_when | |||
|---|---|---|---|---|---|---|
| Plugin Entry Points | Entry Points | Reference for definePluginEntry, defineChannelPluginEntry, and defineSetupPluginEntry |
|
Plugin Entry Points
Every plugin exports a default entry object. The SDK provides three helpers for creating them.
**Looking for a walkthrough?** See [Channel Plugins](/plugins/sdk-channel-plugins) or [Provider Plugins](/plugins/sdk-provider-plugins) for step-by-step guides.definePluginEntry
Import: openclaw/plugin-sdk/plugin-entry
For provider plugins, tool plugins, hook plugins, and anything that is not a messaging channel.
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
export default definePluginEntry({
id: "my-plugin",
name: "My Plugin",
description: "Short summary",
register(api) {
api.registerProvider({
/* ... */
});
api.registerTool({
/* ... */
});
},
});
Options
| Field | Type | Required | Default |
|---|---|---|---|
id |
string |
Yes | — |
name |
string |
Yes | — |
description |
string |
Yes | — |
kind |
string |
No | — |
configSchema |
OpenClawPluginConfigSchema | () => OpenClawPluginConfigSchema |
No | Empty object schema |
register |
(api: OpenClawPluginApi) => void |
Yes | — |
idmust match youropenclaw.plugin.jsonmanifest.kindis for exclusive slots:"memory"or"context-engine".configSchemacan be a function for lazy evaluation.
defineChannelPluginEntry
Import: openclaw/plugin-sdk/core
Wraps definePluginEntry with channel-specific wiring. Automatically calls
api.registerChannel({ plugin }) and gates registerFull on registration mode.
import { defineChannelPluginEntry } from "openclaw/plugin-sdk/core";
export default defineChannelPluginEntry({
id: "my-channel",
name: "My Channel",
description: "Short summary",
plugin: myChannelPlugin,
setRuntime: setMyRuntime,
registerFull(api) {
api.registerCli(/* ... */);
api.registerGatewayMethod(/* ... */);
},
});
Options
| Field | Type | Required | Default |
|---|---|---|---|
id |
string |
Yes | — |
name |
string |
Yes | — |
description |
string |
Yes | — |
plugin |
ChannelPlugin |
Yes | — |
configSchema |
OpenClawPluginConfigSchema | () => OpenClawPluginConfigSchema |
No | Empty object schema |
setRuntime |
(runtime: PluginRuntime) => void |
No | — |
registerFull |
(api: OpenClawPluginApi) => void |
No | — |
setRuntimeis called during registration so you can store the runtime reference (typically viacreatePluginRuntimeStore).registerFullonly runs whenapi.registrationMode === "full". It is skipped during setup-only loading.
defineSetupPluginEntry
Import: openclaw/plugin-sdk/core
For the lightweight setup-entry.ts file. Returns just { plugin } with no
runtime or CLI wiring.
import { defineSetupPluginEntry } from "openclaw/plugin-sdk/core";
export default defineSetupPluginEntry(myChannelPlugin);
OpenClaw loads this instead of the full entry when a channel is disabled, unconfigured, or when deferred loading is enabled. See Setup and Config for when this matters.
Registration mode
api.registrationMode tells your plugin how it was loaded:
| Mode | When | What to register |
|---|---|---|
"full" |
Normal gateway startup | Everything |
"setup-only" |
Disabled/unconfigured channel | Channel registration only |
"setup-runtime" |
Setup flow with runtime available | Channel + lightweight runtime |
defineChannelPluginEntry handles this split automatically. If you use
definePluginEntry directly for a channel, check mode yourself:
register(api) {
api.registerChannel({ plugin: myPlugin });
if (api.registrationMode !== "full") return;
// Heavy runtime-only registrations
api.registerCli(/* ... */);
api.registerService(/* ... */);
}
Plugin shapes
OpenClaw classifies loaded plugins by their registration behavior:
| Shape | Description |
|---|---|
| plain-capability | One capability type (e.g. provider-only) |
| hybrid-capability | Multiple capability types (e.g. provider + speech) |
| hook-only | Only hooks, no capabilities |
| non-capability | Tools/commands/services but no capabilities |
Use openclaw plugins inspect <id> to see a plugin's shape.
Related
- SDK Overview — registration API and subpath reference
- Runtime Helpers —
api.runtimeandcreatePluginRuntimeStore - Setup and Config — manifest, setup entry, deferred loading
- Channel Plugins — building the
ChannelPluginobject - Provider Plugins — provider registration and hooks