The Plugin SDK provides APIs for registering channels, tools, hooks, services, and HTTP handlers. Import from openclaw/plugin-sdk:
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
Plugin API
The OpenClawPluginApi is passed to your plugin’s register and activate functions.
Properties
Plugin identifier (e.g., "matrix", "my-plugin")
Plugin version from package.json
Absolute path to the plugin entry point
OpenClaw configuration object. Access via api.config.channels, api.config.agents, etc.
Plugin-specific configuration from config.json under plugins.entries[id].config
Scoped logger for plugin messages:api.logger.info("Plugin started");
api.logger.warn("Deprecation warning");
api.logger.error("Operation failed");
api.logger.debug?.("Verbose output");
Registration Methods
registerTool
(tool: AnyAgentTool | OpenClawPluginToolFactory, opts?: OpenClawPluginToolOptions) => void
Register an agent tool. Tools are exposed to the LLM and can be called during agent runs.api.registerTool(createMyTool());
api.registerTool(createMyTool(), { optional: true });
api.registerTool(toolFactory, { names: ["tool1", "tool2"] });
Options:
name?: string - Tool name override
names?: string[] - Multiple tool names (for tool factories)
optional?: boolean - Require explicit allowlisting in agent config
registerHook
(events: string | string[], handler: InternalHookHandler, opts?: OpenClawPluginHookOptions) => void
Register a lifecycle hook. Hooks intercept events at key points in the message lifecycle.api.registerHook("llm_input", async (event, ctx) => {
api.logger.info(`LLM call: ${event.provider}/${event.model}`);
});
api.registerHook(["message_received", "message_sent"], handler);
See Hooks for available events.
registerChannel
(registration: OpenClawPluginChannelRegistration | ChannelPlugin) => void
Register a channel plugin. Channel plugins integrate messaging platforms.api.registerChannel({ plugin: myChannelPlugin });
See Channels for details.
registerService
(service: OpenClawPluginService) => void
Register a background service. Services run persistent background tasks.api.registerService({
id: "my-service",
start: async (ctx) => {
// Start background task
},
stop: async (ctx) => {
// Clean up
}
});
registerHttpRoute
(params: { path: string; handler: OpenClawPluginHttpRouteHandler }) => void
Register an HTTP route for webhooks or custom endpoints.api.registerHttpRoute({
path: "/webhook/my-plugin",
handler: async (req, res) => {
res.writeHead(200, { "Content-Type": "application/json" });
res.end(JSON.stringify({ ok: true }));
}
});
Routes are automatically normalized to prevent conflicts.
registerHttpHandler
(handler: OpenClawPluginHttpHandler) => void
Register a global HTTP handler. Handlers are called for all requests.api.registerHttpHandler((req, res) => {
if (req.url?.startsWith("/my-prefix")) {
// Handle request
return true; // Handled
}
return false; // Pass to next handler
});
registerCli
(registrar: OpenClawPluginCliRegistrar, opts?: { commands?: string[] }) => void
Register CLI commands. Add custom commands to the openclaw CLI.api.registerCli((ctx) => {
ctx.program
.command("my-command")
.description("Custom command")
.action(() => {
ctx.logger.info("Command executed");
});
});
registerCommand
(command: OpenClawPluginCommandDefinition) => void
Register a plugin command. Plugin commands bypass the LLM agent and are processed before built-in commands.api.registerCommand({
name: "status",
description: "Check plugin status",
acceptsArgs: false,
requireAuth: true,
handler: async (ctx) => {
return { text: "Plugin is running" };
}
});
registerProvider
(provider: ProviderPlugin) => void
Register an authentication provider. Providers integrate with openclaw login.api.registerProvider({
id: "my-provider",
label: "My Provider",
auth: [/* auth methods */]
});
registerGatewayMethod
(method: string, handler: GatewayRequestHandler) => void
Register a custom gateway method. Gateway methods are JSON-RPC endpoints exposed via the gateway.api.registerGatewayMethod("my.method", async (params) => {
return { result: "success" };
});
Utility Methods
resolvePath
(input: string) => string
Resolve paths relative to the plugin source directory.const configPath = api.resolvePath("./config.json");
const srcPath = api.resolvePath("src/helper.ts");
on
<K extends PluginHookName>(hookName: K, handler: PluginHookHandlerMap[K], opts?: { priority?: number }) => void
Alternative API for registering lifecycle hooks with typed event handlers.api.on("llm_input", async (event, ctx) => {
api.logger.info(`Model: ${event.model}`);
});
Runtime Services
The api.runtime object provides access to OpenClaw’s core services.
Config
api.runtime.config.loadConfig();
api.runtime.config.writeConfigFile(config);
const media = await api.runtime.media.loadWebMedia(url);
const mime = api.runtime.media.detectMime(buffer);
const metadata = await api.runtime.media.getImageMetadata(buffer);
const jpeg = await api.runtime.media.resizeToJpeg(buffer, { maxWidth: 1024 });
Text Processing
const chunks = api.runtime.channel.text.chunkMarkdownText(text, limit);
const mode = api.runtime.channel.text.resolveChunkMode(config);
const hasCommand = api.runtime.channel.text.hasControlCommand(text);
Reply Dispatching
await api.runtime.channel.reply.dispatchReplyFromConfig({
config,
channelId: "telegram",
to: "123456789",
text: "Hello"
});
Logging
const childLogger = api.runtime.logging.getChildLogger(
{ component: "my-plugin" },
{ level: "info" }
);
if (api.runtime.logging.shouldLogVerbose()) {
childLogger.debug("Verbose log message");
}
State Directory
const stateDir = api.runtime.state.resolveStateDir(config);
Channel-Specific Services
The runtime provides channel-specific helpers:
// Discord
api.runtime.channel.discord.sendMessageDiscord(...);
api.runtime.channel.discord.probeDiscord(...);
// Slack
api.runtime.channel.slack.sendMessageSlack(...);
api.runtime.channel.slack.probeSlack(...);
// Telegram
api.runtime.channel.telegram.sendMessageTelegram(...);
api.runtime.channel.telegram.probeTelegram(...);
// WhatsApp
api.runtime.channel.whatsapp.sendMessageWhatsApp(...);
api.runtime.channel.whatsapp.loginWeb(...);
// Signal
api.runtime.channel.signal.sendMessageSignal(...);
// iMessage
api.runtime.channel.imessage.sendMessageIMessage(...);
// LINE
api.runtime.channel.line.sendMessageLine(...);
See the runtime types for the complete API.
Plugin SDK Exports
The openclaw/plugin-sdk package exports types and utilities:
Types
import type {
OpenClawPluginApi,
OpenClawPluginDefinition,
OpenClawPluginService,
PluginRuntime,
RuntimeLogger,
AnyAgentTool,
ChannelPlugin,
ChannelConfigSchema,
HookEntry,
OpenClawConfig,
ProviderAuthContext,
ProviderAuthResult
} from "openclaw/plugin-sdk";
Helper Functions
import {
emptyPluginConfigSchema,
normalizePluginHttpPath,
registerPluginHttpRoute,
normalizeWebhookPath,
resolveWebhookPath,
registerWebhookTarget,
buildAgentMediaPayload,
buildBaseChannelStatusSummary,
buildOauthProviderAuthResult,
acquireFileLock,
withFileLock
} from "openclaw/plugin-sdk";
Channel Helpers
import {
createAccountListHelpers,
buildChannelConfigSchema,
resolveChannelAccountConfigBasePath,
recordInboundSession,
createReplyPrefixContext,
createTypingCallbacks,
extractToolSend,
formatDocsLink
} from "openclaw/plugin-sdk";
Config Schemas (Zod)
import {
DiscordConfigSchema,
GoogleChatConfigSchema,
IMessageConfigSchema,
MSTeamsConfigSchema,
SignalConfigSchema,
SlackConfigSchema,
TelegramConfigSchema,
WhatsAppConfigSchema,
DmConfigSchema,
GroupPolicySchema,
MarkdownConfigSchema,
ToolPolicySchema
} from "openclaw/plugin-sdk";
Example: Complete Plugin
import type { OpenClawPluginApi, AnyAgentTool } from "openclaw/plugin-sdk";
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
import { Type } from "@sinclair/typebox";
function createExampleTool(api: OpenClawPluginApi): AnyAgentTool {
return {
name: "example",
description: "Example tool",
input: Type.Object({
message: Type.String()
}),
execute: async (args) => {
api.logger.info(`Tool called: ${args.message}`);
return { result: "success", details: { message: args.message } };
}
};
}
const plugin = {
id: "example",
name: "Example Plugin",
description: "Demonstrates plugin SDK features",
configSchema: emptyPluginConfigSchema(),
register(api: OpenClawPluginApi) {
// Register tool
api.registerTool(createExampleTool(api));
// Register hook
api.registerHook("llm_input", async (event, ctx) => {
api.logger.info(`LLM call: ${event.provider}/${event.model}`);
});
// Register HTTP route
api.registerHttpRoute({
path: "/webhook/example",
handler: async (req, res) => {
res.writeHead(200);
res.end("OK");
}
});
api.logger.info("Plugin registered");
},
activate(api: OpenClawPluginApi) {
api.logger.info("Plugin activated");
}
};
export default plugin;
Next Steps
- Hooks - Implement lifecycle hooks
- Tools - Build custom agent tools
- Channels - Create channel integrations
- Examples - Real-world plugin examples