Jump to content

Connect Leeroopedia MCP: Equip your AI agents to search best practices, build plans, verify code, diagnose failures, and look up hyperparameter defaults.

Implementation:Openclaw Openclaw LoadOpenClawPlugins

From Leeroopedia


loadOpenClawPlugins and discoverOpenClawPlugins

loadOpenClawPlugins is the main entry point for the plugin verification pipeline. It discovers installed plugins, loads their manifests, validates configuration, imports modules, executes registration callbacks, and produces a PluginRegistry. discoverOpenClawPlugins handles the discovery phase: scanning multiple directories for plugin candidates.

Principle:Openclaw_Openclaw_Extension_Verification

Source Location

Function File Lines
loadOpenClawPlugins src/plugins/loader.ts 169-453
discoverOpenClawPlugins src/plugins/discovery.ts 301-364

Repository: github.com/openclaw/openclaw

loadOpenClawPlugins

Signature

export function loadOpenClawPlugins(options: PluginLoadOptions = {}): PluginRegistry

Options Type

export type PluginLoadOptions = {
  config?: OpenClawConfig;
  workspaceDir?: string;
  logger?: PluginLogger;
  coreGatewayHandlers?: Record<string, GatewayRequestHandler>;
  cache?: boolean;
  mode?: "full" | "validate";
};

Parameters

Parameter Type Default Description
config OpenClawConfig? {} The full OpenClaw configuration.
workspaceDir string? undefined Workspace root for workspace-local plugins.
logger PluginLogger? subsystem logger Logger for plugin load messages.
coreGatewayHandlers Record<string, GatewayRequestHandler>? undefined Core gateway handlers (plugins cannot override these).
cache boolean? true Whether to cache and reuse the registry.
mode "validate" "full" In "validate" mode, plugins are loaded but their register() callbacks are not called.

Return Value

Returns PluginRegistry:

export type PluginRegistry = {
  plugins: PluginRecord[];
  tools: PluginToolRegistration[];
  hooks: PluginHookRegistration[];
  typedHooks: TypedPluginHookRegistration[];
  channels: PluginChannelRegistration[];
  providers: PluginProviderRegistration[];
  gatewayHandlers: GatewayRequestHandlers;
  httpHandlers: PluginHttpRegistration[];
  httpRoutes: PluginHttpRouteRegistration[];
  cliRegistrars: PluginCliRegistration[];
  services: PluginServiceRegistration[];
  commands: PluginCommandRegistration[];
  diagnostics: PluginDiagnostic[];
};

Behavior

The function proceeds through these stages:

1. Cache check. Computes a cache key from the workspace dir and normalized plugins config. Returns the cached registry if available.

2. Setup. Clears previously registered plugin commands. Creates a fresh PluginRuntime and PluginRegistry.

3. Discovery. Calls discoverOpenClawPlugins() to find all plugin candidates.

4. Manifest loading. Calls loadPluginManifestRegistry() to read and parse package manifests.

5. SDK alias resolution. Resolves the openclaw/plugin-sdk path for the jiti TypeScript loader.

6. Per-candidate processing loop. For each candidate:

Step Check On Failure
Manifest lookup Candidate must have a manifest record Skip candidate
Deduplication Plugin ID must not already be seen Record as disabled ("overridden by ...")
Enable state Check allow/deny lists and per-entry config Record as disabled with reason
Config schema Manifest must declare a config schema Record as error ("missing config schema")
Module import jiti(candidate.source) must succeed Record as error with import error
ID mismatch Module export ID vs manifest ID Diagnostic warning (non-fatal)
Memory slot Memory-kind plugins check slot assignment Disable if not the selected memory plugin
Config validation Per-plugin config validated against JSON schema Record as error ("invalid config")
Validate-only mode Skip registration in validate mode Record as loaded (no registration)
Registration Call register(api) Record as error if registration throws

7. Memory slot check. After the loop, warns if the configured memory slot plugin was not found.

8. Finalization. Caches the registry, sets it as the active registry, and initializes the global hook runner.

Plugin Record Status Values

Status Meaning
"loaded" Plugin loaded and registered successfully.
"disabled" Plugin is disabled by config, allowlist, denylist, deduplication, or memory slot logic.
"error" Plugin encountered an error during loading, validation, or registration.

discoverOpenClawPlugins

Signature

export function discoverOpenClawPlugins(params: {
  workspaceDir?: string;
  extraPaths?: string[];
}): PluginDiscoveryResult

Parameters

Parameter Type Description
workspaceDir string? Workspace root directory for workspace-local plugin discovery.
extraPaths string[]? Additional filesystem paths to scan (from plugins.load.paths).

Return Value

export type PluginDiscoveryResult = {
  candidates: PluginCandidate[];
  diagnostics: PluginDiagnostic[];
};

Where each candidate contains:

export type PluginCandidate = {
  idHint: string;
  source: string;
  rootDir: string;
  origin: PluginOrigin;
  workspaceDir?: string;
  packageName?: string;
  packageVersion?: string;
  packageDescription?: string;
  packageDir?: string;
  packageManifest?: OpenClawPackageManifest;
};

Discovery Order

The function scans in this specific order:

  1. Extra paths (origin: "config") -- each path is analyzed: if it is a file, it becomes a single candidate; if it is a directory with package.json, its extensions are resolved; otherwise, it is scanned recursively.
  2. Workspace extensions (origin: "workspace") -- scans <workspaceDir>/.openclaw/extensions/.
  3. Global extensions (origin: "global") -- scans ~/.openclaw/extensions/.
  4. Bundled extensions (origin: "bundled") -- scans the built-in plugins directory.

A seen set prevents the same resolved file from appearing as multiple candidates.

Directory Scanning Logic

For each directory, the scanner (discoverInDirectory) checks:

  • Top-level files with extension .ts, .js, .mts, .cts, .mjs, .cjs (excluding .d.ts).
  • Subdirectories with package.json declaring openclaw.extensions.
  • Subdirectories with an index.ts or index.js entry point.

ID Hint Derivation

The idHint is derived from the package name (unscoped) or the filename:

  • Scoped packages: @openclaw/voice-call becomes voice-call.
  • Multi-extension packages: voice-call/main (package name + base filename).
  • Bare files: the filename without extension.

Integration Flow

loadOpenClawPlugins()
  |
  +--> discoverOpenClawPlugins()     --> PluginCandidate[]
  |
  +--> loadPluginManifestRegistry()  --> manifest records
  |
  +--> for each candidate:
  |      resolveEnableState()
  |      jiti(source)
  |      validatePluginConfig()
  |      register(api)
  |
  +--> cache + setActivePluginRegistry()
  |
  +--> initializeGlobalHookRunner()
  |
  v
  PluginRegistry

Caching

The registry is cached by a composite key of the workspace directory and the serialized normalized plugins config. The cache can be bypassed by setting cache: false. When the cache is used, no discovery or loading occurs; the cached registry is returned directly.

Related Pages

Requires Environment

Uses Heuristic

Page Connections

Double-click a node to navigate. Hold to expand connections.
Principle
Implementation
Heuristic
Environment