Skip to main content

Plugin System

Plugins add code to the Gateway: messaging channels, model and speech providers, agent tools, hooks, memory backends, Control UI pages. Where a skill is Markdown that tells the agent how to use existing tools, a plugin is a TypeScript module that runs inside the Gateway process with the Gateway's privileges.

The official references are Plugins, openclaw plugins and Building plugins.

Security advisories

The June 30, 2026 advisory batch included two plugin-install flaws: GHSA-7vrr-rp4x-4g76 (High, CVSS 8.8: install commands could allow non-owner persistence) and GHSA-wgq8-x5wm-g4rw (Medium, CVSS 4.9: install wrappers could skip install policy). Both were fixed in v2026.6.9. Run the latest stable release and openclaw plugins update --all.


Plugins vs Skills​

SkillsPlugins
FormatFolder with SKILL.mdPackage with openclaw.plugin.json and a JS/TS entry, or a compatible Codex/Claude/Cursor bundle
What it changesWhat the agent knows how to doWhat the Gateway can do
How it is usedThe model reads it when the task matchesLoaded by the Gateway, registers tools, hooks, channels, providers
Runs codeNo (the agent may run commands it describes)Yes, in process
Location<workspace>/skills/, ~/.openclaw/skills/Managed install roots, plugins.load.paths
SourcesClawHub, skills.sh, git, localBundled, ClawHub, npm, git, local path or archive, marketplace

Rule of thumb: if it changes what the agent knows, it is a skill. If it changes what the Gateway can do, it is a plugin. Plugins can also ship skills, listed in openclaw.plugin.json.


CLI Commands​

CommandWhat it does
openclaw plugins list [--enabled] [--verbose] [--json]Installed plugins and their status
openclaw plugins search <query>Search ClawHub for plugins
openclaw plugins inspect <id> [--runtime] [--json]Manifest, config and (with --runtime) live registrations
openclaw plugins install <source>Install from ClawHub, npm, git, a path, an archive or a marketplace
openclaw plugins enable <ids...> / disable <ids...>Turn plugins on or off, keeping config
openclaw plugins reload <ids...> [--wait]Reload a plugin in the running Gateway
openclaw plugins update <ids...> / --allUpdate named plugins, or all of them
openclaw plugins uninstall <ids...> [--dry-run]Remove plugins
openclaw plugins registry [--refresh]Inspect or rebuild the plugin index
openclaw plugins doctorDiagnose plugin problems
openclaw plugins marketplace entriesBrowse the hosted marketplace feed
openclaw plugins marketplace list <source>List a specific marketplace source
openclaw plugins init / build / validate / packAuthor a plugin (see Building a Plugin)

install, enable, disable and reload go through the running Gateway when there is one, so most changes apply without a restart.

Install sources​

openclaw plugins search "calendar"
openclaw plugins install clawhub:<package> # ClawHub only
openclaw plugins install npm:<package> # npm only
openclaw plugins install npm:<package>@1.2.3 --pin # exact npm version
openclaw plugins install ./my-plugin # local directory or archive
openclaw plugins install --link ./my-plugin --force # link a dev checkout

Git sources use git:github.com/<owner>/<repo> with an optional @<ref>. Claude-compatible marketplaces use <plugin>@<marketplace> or --marketplace <source>.

In v2026.10.4, a bare name (openclaw plugins install some-plugin) installs from npm, unless it matches a bundled or official plugin id. Upstream main has switched bare names to ClawHub with no npm fallback (PR #173669). That change merged after 2026.10.10-beta.1 and beta.2 were cut, so it is in no release yet and may or may not ship in 2026.10.10. Use an explicit clawhub: or npm: prefix so the command means the same thing on both sides.

ClawHub packages and OpenClaw's bundled and official catalogue are trusted sources. Arbitrary npm packages, git, local paths and marketplaces warn and ask first; non-interactive installs need --force after you have reviewed the source. --force does not bypass security.installPolicy.


Official Plugins​

Bundled​

Bundled plugins ship with OpenClaw. Many, mostly model and speech providers, are on by default; others need enabling or relevant config. openclaw plugins list --verbose shows which. Two you are likely to touch:

PluginPurposeDefault
workboardKanban-style task board for agent coordinationoff
memory-coreBuilt-in memory tools and Dreaming; the plugin in plugins.slots.memoryselected via the memory slot
openclaw plugins enable workboard
openclaw plugins list --enabled --verbose

See the Workboard guide and Monitoring.

External official plugins​

OpenClaw-owned @openclaw/* packages are on npm and ClawHub:

PackagePlugin idPurpose
@openclaw/copilotcopilotGitHub Copilot SDK agent harness
@openclaw/tokenjuicetokenjuiceCompacts noisy exec/bash tool output before it reaches the model
@openclaw/diagnostics-oteldiagnostics-otelOpenTelemetry exporter for metrics, traces and logs
@openclaw/diagnostics-prometheusdiagnostics-prometheusPrometheus exporter for runtime metrics
openclaw plugins install @openclaw/copilot

Configure a plugin under its plugin id (copilot), not its npm name. The current list is in the plugin inventory.

Community plugins​

These are third-party. Read the source before installing; they run with full Gateway privileges.

PluginPurpose
@xquik/tweetclawX/Twitter search, posting, DMs and monitors
OpenClaw Observability (@henrikrexed/openclaw-otel-observability)OpenTelemetry tracing for Dynatrace or Grafana Cloud
Knostic OpenClaw TelemetryLocal-only telemetry with hash-chained logs

For most observability needs, start with the official @openclaw/diagnostics-otel plugin.


Configuration​

Plugin config lives under plugins in openclaw.json. The schema is strict: unknown keys stop the config from loading.

~/.openclaw/openclaw.json
{
plugins: {
enabled: true,
allow: ["copilot", "memory-core", "workboard"],
deny: ["untrusted-plugin"],
load: { paths: ["~/dev/my-plugin"] },
slots: { memory: "memory-core" },
entries: {
workboard: { enabled: true },
"memory-core": {
config: {
dreaming: { enabled: true, frequency: "0 3 * * *", timezone: "Europe/Berlin" },
},
},
"my-plugin": {
enabled: true,
hooks: { allowConversationAccess: true, timeoutMs: 10000 },
config: {},
},
},
},
}
KeyWhat it does
enabledfalse disables all plugins
allowExclusive allowlist of plugin ids. Tools from plugins outside it stay unavailable even if tools.allow has "*".
denyPlugin ids that never load. Wins over allow and per-plugin enabled.
load.pathsExtra local plugin files or directories
slots.memory, slots.contextEnginePick one plugin for an exclusive role
entries.<id>.enabledTurn one plugin on or off, keeping its config
entries.<id>.configThe plugin's own settings, checked against the configSchema in its manifest
entries.<id>.hooksallowPromptInjection, allowConversationAccess, timeoutMs, timeouts
entries.<id>.subagent, entries.<id>.llmWhether the plugin may override models or agents for subagent runs and completion calls; leave unset unless the plugin needs it

Secrets​

Plugins do not declare secrets in their manifest, and there is no secrets key in plugin config. Use SecretRefs, { source, provider, id }, in whichever config field the plugin documents as accepting one, or ${ENV_VAR} substitution. See Secrets.


Security​

Native plugins are not sandboxed. They run in the Gateway process and can do anything the Gateway's OS user can do. The controls are about what gets loaded:

  • Pin plugins.allow. When allow is unset and the Gateway discovers non-bundled plugins, they may load automatically; startup logs plugins.allow is empty; discovered non-bundled plugins may auto-load: ... with a suggested snippet. Inspect each id (openclaw plugins inspect <id>) before adding it.
  • Workspace plugins are off by default. Plugins found in an agent workspace must be enabled or allowlisted explicitly.
  • Capability consent. Plugins from local or unverified sources must be approved with --accept-capabilities on install, enable or reload when they request capabilities.
  • ClawHub security audit. ClawHub plugin installs show the release's audit; blocked releases are refused.
  • Conversation hooks are opt-in. Non-bundled plugins only see raw conversation content in hooks such as llm_input, llm_output or agent_end when entries.<id>.hooks.allowConversationAccess is true.
  • Install policy. security.installPolicy runs your own command before every plugin (and skill) install or update and can block it. See ClawHub — Locking down installs.
warning

A plugin that registers tools for shell, email, messaging, browser or payments gives every agent that can call those tools that power. Combine plugin allowlists with tool policy, sandboxing and approvals; see Security hardening.


Hooks​

Plugins register hooks in code, not in config. The typed API is api.on(name, handler, options):

AreaHooks
Model and promptbefore_model_resolve, before_prompt_build, before_agent_run, before_agent_reply, before_agent_finalize, agent_end, llm_input, llm_output
Toolsbefore_tool_call (rewrite, block or require approval), after_tool_call, resolve_exec_env, tool_result_persist
Messagesmessage_received, message_sending, message_sent, reply_payload_sending, before_dispatch, inbound_claim
Sessionssession_start, session_end, before_compaction, after_compaction, before_reset
Gateway and installsgateway_start, gateway_stop, cron_changed, before_install, skill_changed, skill_proposal_evaluate, skill_proposal_changed

api.registerHook(...) is a separate, coarser system for internal events such as command:new. Full list and contracts: Hook reference.

Example: ask for approval before a plugin-owned deploy tool runs.

index.ts
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";

export default definePluginEntry({
id: "deploy-policy",
name: "Deploy Policy",
description: "Require approval before production deploys.",
register(api) {
api.on("before_tool_call", async (event) => {
if (event.toolName !== "deploy_service") return;
const env = typeof event.params.environment === "string" ? event.params.environment : "unknown";
return {
requireApproval: {
title: "Deploy service",
description: `Deploy service to ${env}.`,
severity: env === "production" ? "critical" : "warning",
allowedDecisions: ["allow-once", "deny"],
timeoutMs: 120_000,
},
};
});
},
});

Building a Plugin​

Requirements: Node 24.16+ or 26.1+, TypeScript ESM. The plugin API is marked experimental, so pin the OpenClaw version you test against.

Scaffold​

openclaw plugins init my-plugin --type tool --directory ./my-plugin

--type is tool, provider or feature. A tool plugin needs three files.

package.json
{
"name": "@myorg/openclaw-my-plugin",
"version": "1.0.0",
"type": "module",
"dependencies": { "typebox": "1.3.34" },
"peerDependencies": { "openclaw": ">=2026.10.4" },
"openclaw": {
"extensions": ["./dist/index.js"],
"compat": { "pluginApi": ">=2026.10.4" },
"build": { "openclawVersion": "2026.10.4" }
}
}
openclaw.plugin.json
{
"id": "my-plugin",
"name": "My Plugin",
"description": "Adds a custom tool to OpenClaw",
"categories": ["other"],
"contracts": { "tools": ["my_tool"] },
"activation": { "onStartup": true },
"configSchema": { "type": "object", "additionalProperties": false }
}
index.ts
import { Type } from "typebox";
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";

export default definePluginEntry({
id: "my-plugin",
name: "My Plugin",
description: "Adds a custom tool to OpenClaw",
register(api) {
api.registerTool({
name: "my_tool",
description: "Echo one input value",
parameters: Type.Object({ input: Type.String() }),
async execute(_id, params) {
return { content: [{ type: "text", text: `Got: ${params.input}` }] };
},
});
},
});

Points that trip people up:

  • Every plugin needs openclaw.plugin.json with a configSchema, even an empty one.
  • Every tool the plugin registers must be listed in contracts.tools.
  • The SDK is imported from the openclaw package itself (openclaw/plugin-sdk/plugin-entry, openclaw/plugin-sdk/core for channels). There is no separate @openclaw/plugin-sdk package on npm.
  • Deprecated synchronous SQLite-backed SDK members stay compatible through 2026-12-31; upstream plans to remove them in the first January 2027 stable release. Move to the async replacements before then (plugin compatibility, as documented in the 2026.10.10-beta.1 docs; the 2026.10.4 docs do not give the date yet).
  • Runtime imports go in dependencies; devDependencies are not installed for the plugin at runtime.
  • Published plugins point openclaw.extensions at built JavaScript, not .ts source.

Test​

openclaw plugins validate --root ./my-plugin
openclaw plugins build --root ./my-plugin --check

# Install exactly what users will get
cd my-plugin && npm pack --pack-destination /tmp && cd ..
openclaw plugins install npm-pack:/tmp/myorg-openclaw-my-plugin-1.0.0.tgz --force
openclaw plugins inspect my-plugin --runtime --json

During development, openclaw plugins install --link ./my-plugin --force and openclaw plugins reload my-plugin avoid repacking. Set OPENCLAW_PLUGIN_LIFECYCLE_TRACE=1 to see phase timings for slow installs or loads.

Publish​

Publishing uses the standalone clawhub CLI. Plugins are packages, not skills:

npm i -g clawhub
clawhub login
clawhub package validate ./my-plugin
clawhub package publish ./my-plugin --family code-plugin --dry-run
clawhub package publish ./my-plugin --family code-plugin

openclaw.compat.pluginApi and openclaw.build.openclawVersion are required for publishing. Users then install with openclaw plugins install clawhub:@myorg/openclaw-my-plugin. See ClawHub CLI — package publish.


Troubleshooting​

Plugin does not load:

openclaw plugins inspect <id> --runtime --json
openclaw plugins doctor
openclaw doctor --lint # read-only; plain `openclaw doctor` may migrate config and state

Plugin is listed but its tools are missing: check plugins.allow (an exclusive list), plugins.deny, and that each tool is in contracts.tools.

Stale plugin ids after an upgrade or uninstall: openclaw doctor --fix removes them and repairs legacy paths.

Change not picked up: openclaw plugins reload <id> --wait. plugins list and plain inspect read config on disk; inspect --runtime shows what the running Gateway loaded.

Config rejected: the plugins block is strict. Keys such as allowlist, sandbox_level or secrets do not exist and make validation fail. Run openclaw config validate.


See Also​