4.2 KiB
title, sidebarTitle, summary, read_when
| title | sidebarTitle | summary | read_when | |||
|---|---|---|---|---|---|---|
| Plugin Entry Points | Entry Points | How to define plugin entry files for provider, tool, channel, and setup plugins |
|
Plugin Entry Points
OpenClaw has two main entry helpers:
definePluginEntry(...)for general pluginsdefineChannelPluginEntry(...)for native messaging channels
There is also defineSetupPluginEntry(...) for a separate setup-only module.
definePluginEntry(...)
Use this for providers, tools, commands, services, memory plugins, and context engines.
import { definePluginEntry, type OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-entry";
export default definePluginEntry({
id: "example-tools",
name: "Example Tools",
description: "Adds a command and a tool",
register(api: OpenClawPluginApi) {
api.registerCommand({
name: "example",
description: "Show plugin status",
handler: async () => ({ text: "example ok" }),
});
api.registerTool({
name: "example_lookup",
description: "Look up Example data",
parameters: {
type: "object",
properties: {
query: { type: "string" },
},
required: ["query"],
},
async execute(_callId, params) {
return {
content: [{ type: "text", text: `lookup: ${String(params.query)}` }],
};
},
});
},
});
defineChannelPluginEntry(...)
Use this for a plugin that registers a ChannelPlugin.
import { defineChannelPluginEntry } from "openclaw/plugin-sdk/core";
import { channelPlugin } from "./src/channel.js";
import { setRuntime } from "./src/runtime.js";
export default defineChannelPluginEntry({
id: "example-channel",
name: "Example Channel",
description: "Example messaging plugin",
plugin: channelPlugin,
setRuntime,
registerFull(api) {
api.registerTool({
name: "example_channel_status",
description: "Inspect Example Channel state",
parameters: { type: "object", properties: {} },
async execute() {
return { content: [{ type: "text", text: "ok" }] };
},
});
},
});
Why registerFull(...) exists
OpenClaw can load plugins in setup-focused registration modes. registerFull
lets a channel plugin skip extra runtime-only registrations such as tools while
still registering the channel capability itself.
Use it for:
- agent tools
- gateway-only routes
- runtime-only commands
Do not use it for the actual ChannelPlugin; that belongs in plugin: ....
defineSetupPluginEntry(...)
Use this when a channel ships a second module for setup flows.
import { defineSetupPluginEntry } from "openclaw/plugin-sdk/core";
import { exampleSetupPlugin } from "./src/channel.setup.js";
export default defineSetupPluginEntry(exampleSetupPlugin);
This keeps the setup entry shape explicit and matches the bundled channel pattern used in OpenClaw.
One plugin, many capabilities
A single entry file can register multiple capabilities:
import { definePluginEntry, type OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-entry";
export default definePluginEntry({
id: "example-hybrid",
name: "Example Hybrid",
description: "Provider plus tools",
register(api: OpenClawPluginApi) {
api.registerProvider({
id: "example",
label: "Example",
auth: [],
});
api.registerTool({
name: "example_ping",
description: "Simple health check",
parameters: { type: "object", properties: {} },
async execute() {
return { content: [{ type: "text", text: "pong" }] };
},
});
},
});
Entry-file checklist
- Give the plugin a stable
id. - Keep
nameanddescriptionhuman-readable. - Put schema at the entry level when the plugin has config.
- Register only public capabilities inside
register(api). - Keep channel plugins on
plugin-sdk/core. - Keep non-channel plugins on
plugin-sdk/plugin-entry.