OpenClaw Reference (Mirrored)

Plugin Entry Points

Mirrored from OpenClaw (MIT)
This mirror is provided for convenience. OpenClawdBots is not affiliated with or endorsed by OpenClaw.

Plugin Entry Points

Every plugin exports a default entry object. The SDK provides three helpers for creating them.

TIP

Looking for a walkthrough? See Channel Plugins or 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({
      /* ... */
    });
  },
});
FieldTypeRequiredDefault
idstringYes
namestringYes
descriptionstringYes
kindstringNo
configSchemaOpenClawPluginConfigSchema | () => OpenClawPluginConfigSchemaNoEmpty object schema
register(api: OpenClawPluginApi) => voidYes
  • id must match your openclaw.plugin.json manifest.
  • kind is for exclusive slots: "memory" or "context-engine".
  • configSchema can be a function for lazy evaluation.
  • OpenClaw resolves and memoizes that schema on first access, so expensive schema builders only run once.

defineChannelPluginEntry

Import: openclaw/plugin-sdk/channel-core

Wraps definePluginEntry with channel-specific wiring. Automatically calls api.registerChannel({ plugin }), exposes an optional root-help CLI metadata seam, and gates registerFull on registration mode.

import { defineChannelPluginEntry } from "openclaw/plugin-sdk/channel-core";

export default defineChannelPluginEntry({
  id: "my-channel",
  name: "My Channel",
  description: "Short summary",
  plugin: myChannelPlugin,
  setRuntime: setMyRuntime,
  registerCliMetadata(api) {
    api.registerCli(/* ... */);
  },
  registerFull(api) {
    api.registerGatewayMethod(/* ... */);
  },
});
FieldTypeRequiredDefault
idstringYes
namestringYes
descriptionstringYes
pluginChannelPluginYes
configSchemaOpenClawPluginConfigSchema | () => OpenClawPluginConfigSchemaNoEmpty object schema
setRuntime(runtime: PluginRuntime) => voidNo
registerCliMetadata(api: OpenClawPluginApi) => voidNo
registerFull(api: OpenClawPluginApi) => voidNo
  • setRuntime is called during registration so you can store the runtime reference (typically via createPluginRuntimeStore). It is skipped during CLI metadata capture.
  • registerCliMetadata runs during both api.registrationMode === "cli-metadata" and api.registrationMode === "full". Use it as the canonical place for channel-owned CLI descriptors so root help stays non-activating while normal CLI command registration remains compatible with full plugin loads.
  • registerFull only runs when api.registrationMode === "full". It is skipped during setup-only loading.
  • Like definePluginEntry, configSchema can be a lazy factory and OpenClaw memoizes the resolved schema on first access.
  • For plugin-owned root CLI commands, prefer api.registerCli(..., { descriptors: [...] }) when you want the command to stay lazy-loaded without disappearing from the root CLI parse tree. For channel plugins, prefer registering those descriptors from registerCliMetadata(...) and keep registerFull(...) focused on runtime-only work.
  • If registerFull(...) also registers gateway RPC methods, keep them on a plugin-specific prefix. Reserved core admin namespaces (config.*, exec.approvals.*, wizard.*, update.*) are always coerced to operator.admin.

defineSetupPluginEntry

Import: openclaw/plugin-sdk/channel-core

For the lightweight setup-entry.ts file. Returns just { plugin } with no runtime or CLI wiring.

import { defineSetupPluginEntry } from "openclaw/plugin-sdk/channel-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.

In practice, pair defineSetupPluginEntry(...) with the narrow setup helper families:

  • openclaw/plugin-sdk/setup-runtime for runtime-safe setup helpers such as import-safe setup patch adapters, lookup-note output, promptResolvedAllowFrom, splitSetupEntries, and delegated setup proxies
  • openclaw/plugin-sdk/channel-setup for optional-install setup surfaces
  • openclaw/plugin-sdk/setup-tools for setup/install CLI/archive/docs helpers

Keep heavy SDKs, CLI registration, and long-lived runtime services in the full entry.

Registration mode

api.registrationMode tells your plugin how it was loaded:

ModeWhenWhat to register
"full"Normal gateway startupEverything
"setup-only"Disabled/unconfigured channelChannel registration only
"setup-runtime"Setup flow with runtime availableChannel registration plus only the lightweight runtime needed before the full entry loads
"cli-metadata"Root help / CLI metadata captureCLI descriptors only

defineChannelPluginEntry handles this split automatically. If you use definePluginEntry directly for a channel, check mode yourself:

register(api) {
  if (api.registrationMode === "cli-metadata" || api.registrationMode === "full") {
    api.registerCli(/* ... */);
    if (api.registrationMode === "cli-metadata") return;
  }

  api.registerChannel({ plugin: myPlugin });
  if (api.registrationMode !== "full") return;

  // Heavy runtime-only registrations
  api.registerService(/* ... */);
}

Treat "setup-runtime" as the window where setup-only startup surfaces must exist without re-entering the full bundled channel runtime. Good fits are channel registration, setup-safe HTTP routes, setup-safe gateway methods, and delegated setup helpers. Heavy background services, CLI registrars, and provider/client SDK bootstraps still belong in "full".

For CLI registrars specifically:

  • use descriptors when the registrar owns one or more root commands and you want OpenClaw to lazy-load the real CLI module on first invocation
  • make sure those descriptors cover every top-level command root exposed by the registrar
  • use commands alone only for eager compatibility paths

Plugin shapes

OpenClaw classifies loaded plugins by their registration behavior:

ShapeDescription
plain-capabilityOne capability type (e.g. provider-only)
hybrid-capabilityMultiple capability types (e.g. provider + speech)
hook-onlyOnly hooks, no capabilities
non-capabilityTools/commands/services but no capabilities

Use openclaw plugins inspect <id> to see a plugin's shape.