docs: consolidate plugin install docs (#81167)

* docs: consolidate plugin install docs

* docs: align plugin getting started page

* snap

* docs: add reusable audit viewer tooling

* docs: add audit viewer doc mode

* docs: add audit viewer diff mode

* docs: strengthen plugin docs audit coverage

* docs: preserve plugin scan order reference

* docs: resolve plugin audit coverage gaps

* docs: strengthen audit line mappings

* docs: narrow plugin docs refactor scope

* docs: preserve plugin audit facts

* docs: keep audit skill local

* docs: remove audit skill from pr

* fix: satisfy plugin scan lint

* docs: address plugin docs review
This commit is contained in:
Kevin Lin
2026-05-13 13:17:39 -07:00
committed by GitHub
parent 308b39efd5
commit 6a23e26a27
9 changed files with 269 additions and 642 deletions
+8 -4
View File
@@ -42,16 +42,20 @@ Choose the page type before writing:
Use this default topic page structure:
1. Title: name the major entity or surface.
2. Overview: explain what it is, what it owns, and what it does not own.
2. Opening overview: start with a few unheaded sentences that explain what it
is, what it owns, and what it does not own. Do not add a `## Overview`
heading unless the page is itself an overview index.
3. Requirements: include only when setup needs specific accounts, versions,
permissions, plugins, operating systems, or credentials.
4. Quickstart: show the recommended setup path and smallest reliable verification.
5. Configuration: show the minimum configuration needed to use the surface,
common variants users must choose between, and where each option is set:
CLI, config file, environment variable, plugin manifest, dashboard, or API.
6. Subtopics: organize the entity's major concepts, workflows, and decisions by
reader intent.
7. Troubleshooting: diagnose common observable failures.
6. Major subtopics: organize the entity's major concepts, workflows, and
decisions by reader intent. Put each major subtopic under its own heading;
do not wrap them in a generic `## Subtopics` section.
7. Troubleshooting: diagnose common observable failures under an explicit
`## Troubleshooting` heading.
8. Related: link to guides, references, commands, concepts, and adjacent topics.
Topic pages may be longer than quickstarts, but they should not become exhaustive
+20
View File
@@ -651,6 +651,26 @@
"source": "Manage plugins",
"target": "管理插件"
},
{
"source": "Plugin inventory",
"target": "插件清单"
},
{
"source": "Plugin reference",
"target": "插件参考"
},
{
"source": "Community plugins",
"target": "社区插件"
},
{
"source": "ClawHub publishing",
"target": "ClawHub 发布"
},
{
"source": "Plugin dependency resolution",
"target": "插件依赖解析"
},
{
"source": "Plugin path ownership",
"target": "插件路径所有权"
+4 -2
View File
@@ -131,9 +131,11 @@ is available, then fall back to `latest`.
<Accordion title="--dangerously-force-unsafe-install">
`--dangerously-force-unsafe-install` is a break-glass option for false positives in the built-in dangerous-code scanner. It allows the install to continue even when the built-in scanner reports `critical` findings, but it does **not** bypass plugin `before_install` hook policy blocks and does **not** bypass scan failures.
Install scans ignore common test files and directories such as `tests/`, `__tests__/`, `*.test.*`, and `*.spec.*` to avoid blocking packaged test mocks; declared plugin runtime entrypoints are still scanned even if they use one of those names.
This CLI flag applies to plugin install/update flows. Gateway-backed skill dependency installs use the matching `dangerouslyForceUnsafeInstall` request override, while `openclaw skills install` remains a separate ClawHub skill download/install flow.
If a plugin you published on ClawHub is blocked by a registry scan, use the publisher steps in [ClawHub](/clawhub/security).
If a plugin you published on ClawHub is hidden or blocked by a registry scan, use the publisher steps in [ClawHub](/clawhub/security). `--dangerously-force-unsafe-install` only affects installs on your own machine; it does not ask ClawHub to rescan the plugin or make a blocked release public.
</Accordion>
<Accordion title="Hook packs and npm specs">
@@ -282,7 +284,7 @@ directory remains inert so normal packaged installs still use compiled dist.
For runtime hook debugging:
- `openclaw plugins inspect <id> --runtime --json` shows registered hooks and diagnostics from a module-loaded inspection pass. Runtime inspection never installs dependencies; use `openclaw doctor --fix` to clean legacy dependency state or recover missing downloadable plugins that are referenced by config.
- `openclaw gateway status --deep --require-rpc` confirms the reachable Gateway, service/process hints, config path, and RPC health.
- `openclaw gateway status --deep --require-rpc` confirms the reachable Gateway URL/profile, service/process hints, config path, and RPC health.
- Non-bundled conversation hooks (`llm_input`, `llm_output`, `before_model_resolve`, `before_agent_reply`, `before_agent_run`, `before_agent_finalize`, `agent_end`) require `plugins.entries.<id>.hooks.allowConversationAccess=true`.
Use `--link` to avoid copying a local directory (adds to `plugins.load.paths`):
+13 -1
View File
@@ -148,6 +148,18 @@ observation-only.
- `cron_changed` - observe gateway-owned cron lifecycle changes (added, updated, removed, started, finished, scheduled)
- **`before_install`** - inspect skill or plugin install scans and optionally block
## Debug runtime hooks
Use `before_model_resolve` when a plugin needs to switch the provider or model
for an agent turn. It runs before model resolution; `llm_output` only runs after
a model attempt produces assistant output.
For proof of the effective session model, inspect runtime registrations, then
use `openclaw sessions` or the Gateway session/status surfaces. When debugging
provider payloads, start the Gateway with `--raw-stream` and
`--raw-stream-path <path>`; those flags write raw model stream events to a jsonl
file.
## Tool call policy
`before_tool_call` receives:
@@ -184,7 +196,7 @@ type BeforeToolCallResult = {
};
```
Rules:
Hook guard behavior for typed lifecycle hooks:
- `block: true` is terminal and skips lower-priority handlers.
- `block: false` is treated as no decision.
+5 -1
View File
@@ -1266,7 +1266,11 @@ hook instead.
## Discovery precedence (duplicate plugin ids)
OpenClaw discovers plugins from several roots (bundled, global install, workspace, explicit config-selected paths). If two discoveries share the same `id`, only the **highest-precedence** manifest is kept; lower-precedence duplicates are dropped instead of loading beside it.
OpenClaw discovers plugins from several roots. For the raw filesystem scan
order, see [Plugin scan
order](/gateway/configuration-reference#plugin-scan-order). If two discoveries
share the same `id`, only the **highest-precedence** manifest is kept;
lower-precedence duplicates are dropped instead of loading beside it.
Precedence, highest to lowest:
+6 -5
View File
@@ -40,11 +40,12 @@ openclaw gateway restart
openclaw plugins inspect discord --runtime --json
```
Bare package specs try ClawHub first, then npm fallback. To force a source, use
`clawhub:@openclaw/discord` or `npm:@openclaw/discord`. After install, follow
the plugin's setup doc, such as [Discord](/channels/discord), to add credentials
and channel config. See [Manage plugins](/plugins/manage-plugins) for update,
uninstall, and publishing commands.
During the launch cutover, ordinary bare package specs still install from npm.
Use `clawhub:@openclaw/discord` or `npm:@openclaw/discord` when you need an
explicit source. After install, follow the plugin's setup doc, such as
[Discord](/channels/discord), to add credentials and channel config. See
[Manage plugins](/plugins/manage-plugins) for update, uninstall, and publishing
commands.
## Core npm package
+206 -623
View File
@@ -5,49 +5,81 @@ read_when:
- Understanding plugin discovery and load rules
- Working with Codex/Claude-compatible plugin bundles
title: "Plugins"
sidebarTitle: "Install and Configure"
sidebarTitle: "Getting Started"
doc-schema-version: 1
---
Plugins extend OpenClaw with new capabilities: channels, model providers,
agent harnesses, tools, skills, speech, realtime transcription, realtime
voice, media-understanding, image generation, video generation, web fetch, web
search, and more. Some plugins are **core** (shipped with OpenClaw), others
are **external**. Most external plugins are published and discovered through
[ClawHub](/clawhub). Npm remains supported for direct installs and for a
temporary set of OpenClaw-owned plugin packages while that migration finishes.
Plugins extend OpenClaw with channels, model providers, agent harnesses, tools,
skills, speech, realtime transcription, voice, media understanding, generation,
web fetch, web search, and other runtime capabilities.
Use this page when you want to install a plugin, restart the Gateway, verify
that the runtime loaded it, and route common setup failures. For command-only
examples, see [Manage plugins](/plugins/manage-plugins). For the full generated
inventory of bundled, official external, and source-only plugins, see
[Plugin inventory](/plugins/plugin-inventory).
## Requirements
Before installing a plugin, make sure you have:
- an OpenClaw checkout or installation with the `openclaw` CLI available
- network access to the selected source, such as ClawHub, npm, or a git host
- any plugin-specific credentials, config keys, or operating-system tools named
by that plugin's setup docs
- permission to restart the Gateway that serves your channels
## Quick start
For copy-paste install, list, uninstall, update, and publishing examples, see
[Manage plugins](/plugins/manage-plugins).
<Steps>
<Step title="See what is loaded">
<Step title="Find the plugin">
Search [ClawHub](/clawhub) for public plugin packages:
```bash
openclaw plugins list
openclaw plugins search "calendar"
```
ClawHub is the primary discovery surface for community plugins. During the
launch cutover, ordinary bare package specs still install from npm. Use an
explicit prefix when you need one source.
</Step>
<Step title="Install a plugin">
<Step title="Install the plugin">
```bash
# Search ClawHub plugins
openclaw plugins search "calendar"
# From ClawHub.
openclaw plugins install clawhub:<package>
# From ClawHub
openclaw plugins install clawhub:openclaw-codex-app-server
# From npm.
openclaw plugins install npm:<package>
# From npm
openclaw plugins install npm:@acme/openclaw-plugin
openclaw plugins install npm-pack:./openclaw-plugin-1.2.3.tgz
# From git.
openclaw plugins install git:github.com/<owner>/<repo>@<ref>
# From git
openclaw plugins install git:github.com/acme/openclaw-plugin@v1.0.0
# From a local directory or archive
# From a local development checkout.
openclaw plugins install ./my-plugin
openclaw plugins install ./my-plugin.tgz
openclaw plugins install --link ./my-plugin
```
Treat plugin installs like running code. Prefer pinned versions when you
need reproducible production installs.
</Step>
<Step title="Configure and enable it">
Configure plugin-specific settings under `plugins.entries.<id>.config`.
Enable the plugin when it is not already enabled:
```bash
openclaw plugins enable <plugin-id>
```
If your config uses a restrictive `plugins.allow` list, the installed plugin
id must be present there before the plugin can load.
`openclaw plugins install` adds the installed id to an existing
`plugins.allow` list and removes the same id from `plugins.deny` so the
explicit install can load after restart.
</Step>
<Step title="Restart the Gateway">
@@ -55,78 +87,155 @@ For copy-paste install, list, uninstall, update, and publishing examples, see
openclaw gateway restart
```
Then configure under `plugins.entries.\<id\>.config` in your config file.
Installing, updating, or uninstalling plugin code requires a Gateway
restart. Enable and disable operations update config and refresh the cold
registry, but a restart is still the clearest verification path for live
runtime surfaces.
</Step>
<Step title="Chat-native management">
In a running Gateway, owner-only `/plugins enable` and `/plugins disable`
trigger the Gateway config reloader. The Gateway reloads plugin runtime
surfaces in process, and new agent turns rebuild their tool list from the
refreshed registry. `/plugins install` changes plugin source code, so the
Gateway requests a restart instead of pretending the current process can
safely reload already-imported modules.
</Step>
<Step title="Verify the plugin">
<Step title="Verify runtime registration">
```bash
openclaw plugins inspect <plugin-id> --runtime --json
# If the plugin registered a CLI root, run one command from that root.
openclaw <plugin-command> --help
```
Use `--runtime` when you need to prove registered tools, services, gateway
methods, hooks, or plugin-owned CLI commands. Plain `inspect` is a cold
manifest/registry check and intentionally avoids importing plugin runtime.
Use `--runtime` when you need to prove registered tools, hooks, services,
Gateway methods, or plugin-owned CLI commands. Plain `inspect` is a cold
manifest and registry check.
</Step>
</Steps>
If you prefer chat-native control, enable `commands.plugins: true` and use:
## Configuration
```text
/plugin install clawhub:<package>
/plugin show <plugin-id>
/plugin enable <plugin-id>
### Choose an install source
| Source | Use when | Example |
| ----------- | ------------------------------------------------------------------------------ | -------------------------------------------------------------- |
| ClawHub | You want OpenClaw-native discovery, scans, version metadata, and install hints | `openclaw plugins install clawhub:<package>` |
| npm | You need direct npm registry or dist-tag workflows | `openclaw plugins install npm:<package>` |
| git | You need a branch, tag, or commit from a repository | `openclaw plugins install git:github.com/<owner>/<repo>@<ref>` |
| local path | You are developing or testing a plugin on the same machine | `openclaw plugins install --link ./my-plugin` |
| marketplace | You are installing a Claude-compatible marketplace plugin | `openclaw plugins install <plugin> --marketplace <source>` |
Bare package specs have special compatibility behavior. If the bare name matches
a bundled plugin id, OpenClaw uses that bundled source. If it matches an
official external plugin id, OpenClaw uses the official package catalog. Other
ordinary bare package specs install through npm during the launch cutover. Use
`clawhub:`, `npm:`, `git:`, or `npm-pack:` when you need deterministic source
selection. See [`openclaw plugins`](/cli/plugins#install) for the full command
contract.
### Configure plugin policy
The common plugin config shape is:
```json5
{
plugins: {
enabled: true,
allow: ["voice-call"],
deny: ["untrusted-plugin"],
load: { paths: ["~/Projects/oss/voice-call-plugin"] },
slots: { memory: "memory-core" },
entries: {
"voice-call": { enabled: true, config: { provider: "twilio" } },
},
},
}
```
The install path uses the same resolver as the CLI: local path/archive, explicit
`clawhub:<pkg>`, explicit `npm:<pkg>`, explicit `npm-pack:<path.tgz>`,
explicit `git:<repo>`, or bare package spec through npm.
Key policy rules:
If config is invalid, install normally fails closed and points you at
`openclaw doctor --fix`. The only recovery exception is a narrow bundled-plugin
reinstall path for plugins that opt into
`openclaw.install.allowInvalidConfigRecovery`.
During Gateway startup, invalid plugin config fails closed like any other invalid
config. Run `openclaw doctor --fix` to quarantine the bad plugin config by
disabling that plugin entry and removing its invalid config payload; the normal
config backup keeps the previous values.
When a channel config references a plugin that is no longer discoverable but the
same stale plugin id remains in plugin config or install records, Gateway startup
logs warnings and skips that channel instead of blocking every other channel.
Run `openclaw doctor --fix` to remove the stale channel/plugin entries; unknown
channel keys without stale-plugin evidence still fail validation so typos stay
visible.
If `plugins.enabled: false` is set, stale plugin references are treated as inert:
Gateway startup skips plugin discovery/load work and `openclaw doctor` preserves
the disabled plugin config instead of auto-removing it. Re-enable plugins before
running doctor cleanup if you want stale plugin ids removed.
- `plugins.enabled: false` disables all plugins and skips plugin discovery/load
work. Stale plugin references are inert while this is active; re-enable
plugins before running doctor cleanup when you want stale ids removed.
- `plugins.deny` wins over allow and per-plugin enablement.
- `plugins.allow` is an exclusive allowlist. Plugin-owned tools outside the
allowlist stay unavailable, even when `tools.allow` includes `"*"`.
- `plugins.entries.<id>.enabled: false` disables one plugin while preserving its
config.
- `plugins.load.paths` adds explicit local plugin files or directories.
- Workspace-origin plugins are disabled by default; explicitly enable or
allowlist them before using local workspace code.
- Bundled plugins follow their built-in default-on/default-off metadata unless
config explicitly overrides them.
- `plugins.slots.<slot>` chooses one plugin for exclusive categories such as
memory and context engines. Slot selection force-enables the selected plugin
for that slot by counting as explicit activation; it can load even when it
would otherwise be opt-in. `plugins.deny` and
`plugins.entries.<id>.enabled: false` still block it.
- Bundled opt-in plugins can auto-activate when config names one of their owned
surfaces, such as a provider/model ref, channel config, CLI backend, or agent
harness runtime.
- OpenAI-family Codex routing keeps provider and runtime plugin boundaries
separate: `openai-codex/*` is legacy OpenAI-provider config, while the bundled
`codex` plugin owns Codex app-server runtime for canonical `openai/*` agent
refs, explicit `agentRuntime.id: "codex"`, and legacy `codex/*` refs.
Plugin dependency installation happens only during explicit install/update or
doctor repair flows. Gateway startup, config reload, and runtime inspection do
not run package managers or repair dependency trees. Local plugins must already
have their dependencies installed, while npm, git, and ClawHub plugins are
installed under OpenClaw's managed plugin roots. npm dependencies may be hoisted
within OpenClaw's managed npm root; install/update scans that managed root before
trust and uninstall removes npm-managed packages through npm. External plugins
and custom load paths must still be installed through `openclaw plugins install`.
Use `openclaw plugins list --json` to see the static `dependencyStatus` for each
visible plugin without importing runtime code or repairing dependencies.
See [Plugin dependency resolution](/plugins/dependency-resolution) for the
install-time lifecycle.
Run `openclaw doctor` or `openclaw doctor --fix` when config validation reports
stale plugin ids, allowlist/tool mismatches, or legacy bundled plugin paths.
## Understand plugin formats
OpenClaw recognizes two plugin formats:
| Format | How it loads | Use when |
| ---------------------- | ---------------------------------------------------------------------------- | ---------------------------------------------------------------------- |
| Native OpenClaw plugin | `openclaw.plugin.json` plus a runtime module loaded in process | You are installing or building OpenClaw-specific runtime capabilities |
| Compatible bundle | Codex, Claude, or Cursor plugin layout mapped into OpenClaw plugin inventory | You are reusing compatible skills, commands, hooks, or bundle metadata |
Both formats appear in `openclaw plugins list`, `openclaw plugins inspect`,
`openclaw plugins enable`, and `openclaw plugins disable`. See
[Plugin bundles](/plugins/bundles) for the bundle compatibility boundary and
[Building plugins](/plugins/building-plugins) for native plugin authoring.
## Verify the active Gateway
`openclaw plugins list` and plain `openclaw plugins inspect` read cold config,
manifest, and registry state. They do not prove that an already-running Gateway
has imported the same plugin code.
When a plugin appears installed but live chat traffic does not use it:
```bash
openclaw gateway status --deep --require-rpc
openclaw plugins inspect <plugin-id> --runtime --json
openclaw gateway restart
```
On VPS or container installs, make sure the process you restart is the actual
`openclaw gateway run` child that serves your channels, not only a wrapper or
supervisor.
## Troubleshooting
| Symptom | Check | Fix |
| -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------- |
| Plugin appears in `plugins list` but runtime hooks do not run | Use `openclaw plugins inspect <id> --runtime --json` and confirm the active Gateway with `gateway status --deep --require-rpc` | Restart the live Gateway after install, update, config, or source changes |
| Duplicate channel or tool ownership diagnostics appear | Run `openclaw plugins list --enabled --verbose`, inspect each suspected plugin with `--runtime --json`, and compare channel/tool ownership | Disable one owner, remove stale installs, or use manifest `preferOver` for intentional replacement |
| Config says a plugin is missing | Check [Plugin inventory](/plugins/plugin-inventory) for whether it is bundled, official external, or source-only | Install the external package, enable the bundled plugin, or remove stale config |
| Config is invalid during install | Read the validation message and run `openclaw doctor --fix` when it points to stale plugin state | Doctor can quarantine invalid plugin config by disabling the entry and removing the invalid payload |
| Plugin path is blocked for suspicious ownership or permissions | Inspect the diagnostic before the config error | Fix filesystem ownership/permissions, then run `openclaw plugins registry --refresh` |
| `OPENCLAW_NIX_MODE=1` blocks lifecycle commands | Confirm the install is managed by Nix | Change plugin selection in the Nix source instead of using plugin mutator commands |
| Dependency import fails at runtime | Check whether the plugin was installed through npm/git/ClawHub or loaded from a local path | Run `openclaw plugins update <id>`, reinstall the source, or install local plugin dependencies yourself |
When stale plugin config still names a no-longer-discoverable channel plugin,
Gateway startup skips that plugin-backed channel instead of blocking every
other channel. Run `openclaw doctor --fix` to remove stale plugin and channel
entries. Unknown channel keys without stale-plugin evidence still fail
validation so typos stay visible.
For intentional channel replacement, the preferred plugin should declare
`channelConfigs.<channel-id>.preferOver` with the legacy or lower-priority
plugin id. If both plugins are explicitly enabled, OpenClaw keeps that request
and reports duplicate channel or tool diagnostics instead of silently choosing
one owner.
If an installed package reports that it `requires compiled runtime output for
TypeScript entry ...`, the package was published without the JavaScript files
OpenClaw needs at runtime. Update or reinstall after the publisher ships
compiled JavaScript, or disable/uninstall the plugin until then.
### Blocked plugin path ownership
@@ -156,273 +265,6 @@ After fixing ownership, rerun `openclaw doctor --fix` or
`openclaw plugins registry --refresh` so the persisted plugin registry matches
the repaired files.
For npm installs, mutable selectors such as `latest` or a dist-tag are resolved
before installation and then pinned to the exact verified version in OpenClaw's
managed npm root. After npm finishes, OpenClaw verifies the installed
`package-lock.json` entry still matches the resolved version and integrity. If
npm writes different package metadata, the install fails and the managed package
is rolled back instead of accepting a different plugin artifact.
Managed npm roots also inherit OpenClaw's package-level npm `overrides`, so
security pins that protect the packaged host also apply to hoisted external
plugin dependencies.
Source checkouts are pnpm workspaces. If you clone OpenClaw to hack on bundled
plugins, run `pnpm install`; OpenClaw then loads bundled plugins from
`extensions/<id>` so edits and package-local dependencies are used directly.
Plain npm root installs are for packaged OpenClaw, not source checkout
development.
## Plugin types
OpenClaw recognizes two plugin formats:
| Format | How it works | Examples |
| ---------- | ------------------------------------------------------------------ | ------------------------------------------------------ |
| **Native** | `openclaw.plugin.json` + runtime module; executes in-process | Official plugins, community npm packages |
| **Bundle** | Codex/Claude/Cursor-compatible layout; mapped to OpenClaw features | `.codex-plugin/`, `.claude-plugin/`, `.cursor-plugin/` |
Both show up under `openclaw plugins list`. See [Plugin Bundles](/plugins/bundles) for bundle details.
If you are writing a native plugin, start with [Building Plugins](/plugins/building-plugins)
and the [Plugin SDK Overview](/plugins/sdk-overview).
## Package entrypoints
Native plugin npm packages must declare `openclaw.extensions` in `package.json`.
Each entry must stay inside the package directory and resolve to a readable
runtime file, or to a TypeScript source file with an inferred built JavaScript
peer such as `src/index.ts` to `dist/index.js`.
Packaged installs must ship that JavaScript runtime output. The TypeScript
source fallback is for source checkouts and local development paths, not for
npm packages installed into OpenClaw's managed plugin root.
Untracked directories dropped into the global extension root are treated as
local source checkouts and may load TypeScript entries directly. Directories
still named by an install record, including `installPath` or `sourcePath`, stay
managed and keep the compiled-output requirement even when the global scan sees
them. If you intentionally convert a managed install into an untracked local
checkout, remove the stale install record first with uninstall or doctor cleanup.
If a managed package warning says it `requires compiled runtime output for
TypeScript entry ...`, the package was published without the JavaScript files
OpenClaw needs at runtime. That is a plugin packaging issue, not a local config
problem. Update or reinstall the plugin after the publisher republishes compiled
JavaScript, or disable/uninstall that plugin until a fixed package is available.
Use `openclaw.runtimeExtensions` when published runtime files do not live at the
same paths as the source entries. When present, `runtimeExtensions` must contain
exactly one entry for every `extensions` entry. Mismatched lists fail install and
plugin discovery rather than silently falling back to source paths. If you also
publish `openclaw.setupEntry`, use `openclaw.runtimeSetupEntry` for its built
JavaScript peer; that file is required when declared.
```json
{
"name": "@acme/openclaw-plugin",
"openclaw": {
"extensions": ["./src/index.ts"],
"runtimeExtensions": ["./dist/index.js"]
}
}
```
## Official plugins
### OpenClaw-owned npm packages during migration
ClawHub is the primary distribution path for most plugins. Current packaged
OpenClaw releases already bundle many official plugins, so those do not need
separate npm installs in normal setups. Until every OpenClaw-owned plugin has
migrated to ClawHub, OpenClaw still ships some `@openclaw/*` plugin packages on
npm for older/custom installs and direct npm workflows.
If npm reports an `@openclaw/*` plugin package as deprecated, that package
version is from an older external package train. Use the bundled plugin from
current OpenClaw or a local checkout until a newer npm package is published.
| Plugin | Package | Docs |
| --------------- | -------------------------- | ------------------------------------------ |
| Discord | `@openclaw/discord` | [Discord](/channels/discord) |
| Feishu | `@openclaw/feishu` | [Feishu](/channels/feishu) |
| Matrix | `@openclaw/matrix` | [Matrix](/channels/matrix) |
| Mattermost | `@openclaw/mattermost` | [Mattermost](/channels/mattermost) |
| Microsoft Teams | `@openclaw/msteams` | [Microsoft Teams](/channels/msteams) |
| Nextcloud Talk | `@openclaw/nextcloud-talk` | [Nextcloud Talk](/channels/nextcloud-talk) |
| Nostr | `@openclaw/nostr` | [Nostr](/channels/nostr) |
| Synology Chat | `@openclaw/synology-chat` | [Synology Chat](/channels/synology-chat) |
| Tlon | `@openclaw/tlon` | [Tlon](/channels/tlon) |
| WhatsApp | `@openclaw/whatsapp` | [WhatsApp](/channels/whatsapp) |
| Zalo | `@openclaw/zalo` | [Zalo](/channels/zalo) |
| Zalo Personal | `@openclaw/zalouser` | [Zalo Personal](/plugins/zalouser) |
### Core (shipped with OpenClaw)
<AccordionGroup>
<Accordion title="Model providers (enabled by default)">
`anthropic`, `byteplus`, `cloudflare-ai-gateway`, `github-copilot`, `google`,
`huggingface`, `kilocode`, `kimi-coding`, `minimax`, `mistral`, `qwen`,
`moonshot`, `nvidia`, `openai`, `opencode`, `opencode-go`, `openrouter`,
`qianfan`, `synthetic`, `together`, `venice`,
`vercel-ai-gateway`, `volcengine`, `xiaomi`, `zai`
</Accordion>
<Accordion title="Memory plugins">
- `memory-core` - bundled memory search (default via `plugins.slots.memory`)
- `memory-lancedb` - LanceDB-backed long-term memory with auto-recall/capture (set `plugins.slots.memory = "memory-lancedb"`)
See [Memory LanceDB](/plugins/memory-lancedb) for OpenAI-compatible
embedding setup, Ollama examples, recall limits, and troubleshooting.
</Accordion>
<Accordion title="Speech providers (enabled by default)">
`elevenlabs`, `microsoft`
</Accordion>
<Accordion title="Other">
- `browser` - bundled browser plugin for the browser tool, `openclaw browser` CLI, `browser.request` gateway method, browser runtime, and default browser control service (enabled by default; disable before replacing it)
- `copilot-proxy` - VS Code Copilot Proxy bridge (disabled by default)
</Accordion>
</AccordionGroup>
Looking for third-party plugins? See [ClawHub](/clawhub).
## Configuration
```json5
{
plugins: {
enabled: true,
allow: ["voice-call"],
deny: ["untrusted-plugin"],
load: { paths: ["~/Projects/oss/voice-call-plugin"] },
entries: {
"voice-call": { enabled: true, config: { provider: "twilio" } },
},
},
}
```
| Field | Description |
| ------------------ | --------------------------------------------------------- |
| `enabled` | Master toggle (default: `true`) |
| `allow` | Plugin allowlist (optional) |
| `bundledDiscovery` | Bundled plugin discovery mode (`allowlist` by default) |
| `deny` | Plugin denylist (optional; deny wins) |
| `load.paths` | Extra plugin files/directories |
| `slots` | Exclusive slot selectors (e.g. `memory`, `contextEngine`) |
| `entries.\<id\>` | Per-plugin toggles + config |
`plugins.allow` is exclusive. When it is non-empty, only listed plugins can load
or expose tools, even if `tools.allow` contains `"*"` or a specific plugin-owned
tool name. If a tool allowlist references plugin tools, add the owning plugin ids
to `plugins.allow` or remove `plugins.allow`; `openclaw doctor` warns about this
shape.
`plugins.bundledDiscovery` defaults to `"allowlist"` for new configs, so a
restrictive `plugins.allow` inventory also blocks omitted bundled provider
plugins, including runtime web-search provider discovery. Doctor stamps older
restrictive allowlist configs with `"compat"` during migration so upgrades keep
legacy bundled provider behavior until the operator opts into the stricter mode.
An empty `plugins.allow` is still treated as unset/open.
Config changes made through `/plugins enable` or `/plugins disable` trigger an
in-process Gateway plugin reload. New agent turns rebuild their tool list from
the refreshed plugin registry. Source-changing operations such as install,
update, and uninstall still restart the Gateway process because already-imported
plugin modules cannot be safely replaced in place.
`openclaw plugins list` is a local plugin registry/config snapshot. An
`enabled` plugin there means the persisted registry and current config allow the
plugin to participate. It does not prove that an already-running remote Gateway
has reloaded or restarted into the same plugin code. On VPS/container setups
with wrapper processes, send restarts or reload-triggering writes to the actual
`openclaw gateway run` process, or use `openclaw gateway restart` against the
running Gateway when the reload reports a failure.
<Accordion title="Plugin states: disabled vs missing vs invalid">
- **Disabled**: plugin exists but enablement rules turned it off. Config is preserved.
- **Missing**: config references a plugin id that discovery did not find.
- **Invalid**: plugin exists but its config does not match the declared schema. Gateway startup skips only that plugin; `openclaw doctor --fix` can quarantine the invalid entry by disabling it and removing its config payload.
</Accordion>
## Discovery and precedence
OpenClaw scans for plugins in this order (first match wins):
<Steps>
<Step title="Config paths">
`plugins.load.paths` - explicit file or directory paths. Paths that point
back at OpenClaw's own packaged bundled plugin directories are ignored;
run `openclaw doctor --fix` to remove those stale aliases.
</Step>
<Step title="Workspace plugins">
`\<workspace\>/.openclaw/<plugin-root>/*.ts` and `\<workspace\>/.openclaw/<plugin-root>/*/index.ts`.
</Step>
<Step title="Global plugins">
`~/.openclaw/<plugin-root>/*.ts` and `~/.openclaw/<plugin-root>/*/index.ts`.
</Step>
<Step title="Bundled plugins">
Shipped with OpenClaw. Many are enabled by default (model providers, speech).
Others require explicit enablement.
</Step>
</Steps>
Packaged installs and Docker images normally resolve bundled plugins from the
compiled `dist/extensions` tree. If a bundled plugin source directory is
bind-mounted over the matching packaged source path, for example
`/app/extensions/synology-chat`, OpenClaw treats that mounted source directory
as a bundled source overlay and discovers it before the packaged
`/app/dist/extensions/synology-chat` bundle. This keeps maintainer container
loops working without switching every bundled plugin back to TypeScript source.
Set `OPENCLAW_DISABLE_BUNDLED_SOURCE_OVERLAYS=1` to force packaged dist bundles
even when source overlay mounts are present.
### Enablement rules
- `plugins.enabled: false` disables all plugins and skips plugin discovery/load work
- `plugins.deny` always wins over allow
- `plugins.entries.\<id\>.enabled: false` disables that plugin
- Workspace-origin plugins are **disabled by default** (must be explicitly enabled)
- Bundled plugins follow the built-in default-on set unless overridden
- Exclusive slots can force-enable the selected plugin for that slot
- Some bundled opt-in plugins are enabled automatically when config names a
plugin-owned surface, such as a provider model ref, channel config, or harness
runtime
- Stale plugin config is preserved while `plugins.enabled: false` is active;
re-enable plugins before running doctor cleanup if you want stale ids removed
- OpenAI-family Codex routes keep separate plugin boundaries:
`openai-codex/*` belongs to the OpenAI plugin, while the bundled Codex
app-server plugin is selected by canonical `openai/*` agent refs, explicit
provider/model `agentRuntime.id: "codex"`, or legacy `codex/*` model refs
## Troubleshooting runtime hooks
If a plugin appears in `plugins list` but `register(api)` side effects or hooks
do not run in live chat traffic, check these first:
- Run `openclaw gateway status --deep --require-rpc` and confirm the active
Gateway URL, profile, config path, and process are the ones you are editing.
- Restart the live Gateway after plugin install/config/code changes. In wrapper
containers, PID 1 may only be a supervisor; restart or signal the child
`openclaw gateway run` process.
- Use `openclaw plugins inspect <id> --runtime --json` to confirm hook registrations and
diagnostics. Non-bundled conversation hooks such as `before_model_resolve`,
`before_agent_reply`, `before_agent_run`, `llm_input`, `llm_output`,
`before_agent_finalize`, and `agent_end` need
`plugins.entries.<id>.hooks.allowConversationAccess=true`.
- For model switching, prefer `before_model_resolve`. It runs before model
resolution for agent turns; `llm_output` only runs after a model attempt
produces assistant output.
- For proof of the effective session model, use `openclaw sessions` or the
Gateway session/status surfaces and, when debugging provider payloads, start
the Gateway with `--raw-stream --raw-stream-path <path>`.
### Slow plugin tool setup
If agent turns appear to stall while preparing tools, enable trace logging and
@@ -448,7 +290,9 @@ OpenClaw caches successful plugin tool factory results for repeated resolutions
with the same effective request context. The cache key includes the effective
runtime config, workspace, agent/session ids, sandbox policy, browser settings,
delivery context, requester identity, and ownership state, so factories that
depend on those trusted fields are re-run when the context changes.
depend on those trusted fields are re-run when the context changes. If timings
stay high, the plugin may be doing expensive work before returning its tool
definitions.
If one plugin dominates the timing, inspect its runtime registrations:
@@ -460,279 +304,18 @@ Then update, reinstall, or disable that plugin. Plugin authors should move
expensive dependency loading behind the tool execution path instead of doing it
inside the tool factory.
### Duplicate channel or tool ownership
Symptoms:
- `channel already registered: <channel-id> (<plugin-id>)`
- `channel setup already registered: <channel-id> (<plugin-id>)`
- `plugin tool name conflict (<plugin-id>): <tool-name>`
These mean more than one enabled plugin is trying to own the same channel,
setup flow, or tool name. The most common cause is an external channel plugin
installed beside a bundled plugin that now provides the same channel id.
Debug steps:
- Run `openclaw plugins list --enabled --verbose` to see every enabled plugin
and origin.
- Run `openclaw plugins inspect <id> --runtime --json` for each suspected plugin and
compare `channels`, `channelConfigs`, `tools`, and diagnostics.
- Run `openclaw plugins registry --refresh` after installing or removing
plugin packages so persisted metadata reflects the current install.
- Restart the Gateway after install, registry, or config changes.
Fix options:
- If one plugin intentionally replaces another for the same channel id, the
preferred plugin should declare `channelConfigs.<channel-id>.preferOver` with
the lower-priority plugin id. See [/plugins/manifest#replacing-another-channel-plugin](/plugins/manifest#replacing-another-channel-plugin).
- If the duplicate is accidental, disable one side with
`plugins.entries.<plugin-id>.enabled: false` or remove the stale plugin
install.
- If you explicitly enabled both plugins, OpenClaw keeps that request and
reports the conflict. Pick one owner for the channel or rename plugin-owned
tools so the runtime surface is unambiguous.
## Plugin slots (exclusive categories)
Some categories are exclusive (only one active at a time):
```json5
{
plugins: {
slots: {
memory: "memory-core", // or "none" to disable
contextEngine: "legacy", // or a plugin id
},
},
}
```
| Slot | What it controls | Default |
| --------------- | --------------------- | ------------------- |
| `memory` | Active memory plugin | `memory-core` |
| `contextEngine` | Active context engine | `legacy` (built-in) |
## CLI reference
```bash
openclaw plugins list # compact inventory
openclaw plugins list --enabled # only enabled plugins
openclaw plugins list --verbose # per-plugin detail lines
openclaw plugins list --json # machine-readable inventory
openclaw plugins search <query> # search ClawHub plugin catalog
openclaw plugins inspect <id> # static detail
openclaw plugins inspect <id> --runtime # registered hooks/tools/CLI/gateway methods
openclaw plugins inspect <id> --json # machine-readable
openclaw plugins inspect --all # fleet-wide table
openclaw plugins info <id> # inspect alias
openclaw plugins doctor # diagnostics
openclaw plugins registry # inspect persisted registry state
openclaw plugins registry --refresh # rebuild persisted registry
openclaw doctor --fix # repair plugin registry state
openclaw plugins install <package> # install from npm by default
openclaw plugins install clawhub:<pkg> # install from ClawHub only
openclaw plugins install npm:<pkg> # install from npm only
openclaw plugins install git:<repo> # install from git
openclaw plugins install git:<repo>@<ref> # install from git ref
openclaw plugins install <spec> --force # overwrite existing install
openclaw plugins install <path> # install from local path
openclaw plugins install -l <path> # link (no copy) for dev
openclaw plugins install <plugin> --marketplace <source>
openclaw plugins install <plugin> --marketplace https://github.com/<owner>/<repo>
openclaw plugins install <spec> --pin # record exact resolved npm spec
openclaw plugins install <spec> --dangerously-force-unsafe-install
openclaw plugins update <id-or-npm-spec> # update one plugin
openclaw plugins update <id-or-npm-spec> --dangerously-force-unsafe-install
openclaw plugins update --all # update all
openclaw plugins uninstall <id> # remove config and plugin index records
openclaw plugins uninstall <id> --keep-files
openclaw plugins marketplace list <source>
openclaw plugins marketplace list <source> --json
# Verify runtime registrations after install.
openclaw plugins inspect <id> --runtime --json
# Run plugin-owned CLI commands directly from the OpenClaw root CLI.
openclaw <plugin-command> --help
openclaw plugins enable <id>
openclaw plugins disable <id>
```
Bundled plugins ship with OpenClaw. Many are enabled by default (for example
bundled model providers, bundled speech providers, and the bundled browser
plugin). Other bundled plugins still need `openclaw plugins enable <id>`.
`--force` overwrites an existing installed plugin or hook pack in place. Use
`openclaw plugins update <id-or-npm-spec>` for routine upgrades of tracked npm
plugins. It is not supported with `--link`, which reuses the source path instead
of copying over a managed install target.
When `plugins.allow` is already set, `openclaw plugins install` adds the
installed plugin id to that allowlist before enabling it. If the same plugin id
is present in `plugins.deny`, install removes that stale deny entry so the
explicit install is immediately loadable after restart.
OpenClaw keeps a persisted local plugin registry as the cold read model for
plugin inventory, contribution ownership, and startup planning. Install, update,
uninstall, enable, and disable flows refresh that registry after changing plugin
state. The same `plugins/installs.json` file keeps durable install metadata in
top-level `installRecords` and rebuildable manifest metadata in `plugins`. If
the registry is missing, stale, or invalid, `openclaw plugins registry
--refresh` rebuilds its manifest view from install records, config policy, and
manifest/package metadata without loading plugin runtime modules.
In Nix mode (`OPENCLAW_NIX_MODE=1`), plugin lifecycle mutators are disabled.
Manage plugin package selection and config through the Nix source for the
install instead; for nix-openclaw, start with the agent-first
[Quick Start](https://github.com/openclaw/nix-openclaw#quick-start).
`openclaw plugins update <id-or-npm-spec>` applies to tracked installs. Passing
an npm package spec with a dist-tag or exact version resolves the package name
back to the tracked plugin record and records the new spec for future updates.
Passing the package name without a version moves an exact pinned install back to
the registry's default release line. If the installed npm plugin already matches
the resolved version and recorded artifact identity, OpenClaw skips the update
without downloading, reinstalling, or rewriting config.
When `openclaw update` runs on the beta channel, default-line npm and ClawHub
plugin records try `@beta` first and fall back to default/latest when no plugin
beta release exists. Exact versions and explicit tags stay pinned.
`--pin` is npm-only. It is not supported with `--marketplace`, because
marketplace installs persist marketplace source metadata instead of an npm spec.
`--dangerously-force-unsafe-install` is a break-glass override for false
positives from the built-in dangerous-code scanner. It allows plugin installs
and plugin updates to continue past built-in `critical` findings, but it still
does not bypass plugin `before_install` policy blocks or scan-failure blocking.
Install scans ignore common test files and directories such as `tests/`,
`__tests__/`, `*.test.*`, and `*.spec.*` to avoid blocking packaged test mocks;
declared plugin runtime entrypoints are still scanned even if they use one of
those names.
This CLI flag applies to plugin install/update flows only. Gateway-backed skill
dependency installs use the matching `dangerouslyForceUnsafeInstall` request
override instead, while `openclaw skills install` remains the separate ClawHub
skill download/install flow.
If a plugin you published on ClawHub is hidden or blocked by a scan, open the
ClawHub dashboard or run `clawhub package rescan <name>` to ask ClawHub to check
it again. `--dangerously-force-unsafe-install` only affects installs on your own
machine; it does not ask ClawHub to rescan the plugin or make a blocked release
public.
Compatible bundles participate in the same plugin list/inspect/enable/disable
flow. Current runtime support includes bundle skills, Claude command-skills,
Claude `settings.json` defaults, Claude `.lsp.json` and manifest-declared
`lspServers` defaults, Cursor command-skills, and compatible Codex hook
directories.
`openclaw plugins inspect <id>` also reports detected bundle capabilities plus
supported or unsupported MCP and LSP server entries for bundle-backed plugins.
Marketplace sources can be a Claude known-marketplace name from
`~/.claude/plugins/known_marketplaces.json`, a local marketplace root or
`marketplace.json` path, a GitHub shorthand like `owner/repo`, a GitHub repo
URL, or a git URL. For remote marketplaces, plugin entries must stay inside the
cloned marketplace repo and use relative path sources only.
See [`openclaw plugins` CLI reference](/cli/plugins) for full details.
## Plugin API overview
Native plugins export an entry object that exposes `register(api)`. Older
plugins may still use `activate(api)` as a legacy alias, but new plugins should
use `register`.
```typescript
export default definePluginEntry({
id: "my-plugin",
name: "My Plugin",
register(api) {
api.registerProvider({
/* ... */
});
api.registerTool({
/* ... */
});
api.registerChannel({
/* ... */
});
},
});
```
OpenClaw loads the entry object and calls `register(api)` during plugin
activation. The loader still falls back to `activate(api)` for older plugins,
but bundled plugins and new external plugins should treat `register` as the
public contract.
`api.registrationMode` tells a plugin why its entry is being loaded:
| Mode | Meaning |
| --------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `full` | Runtime activation. Register tools, hooks, services, commands, routes, and other live side effects. |
| `discovery` | Read-only capability discovery. Register providers and metadata; trusted plugin entry code may load, but skip live side effects. |
| `setup-only` | Channel setup metadata loading through a lightweight setup entry. |
| `setup-runtime` | Channel setup loading that also needs the runtime entry. |
| `cli-metadata` | CLI command metadata collection only. |
Plugin entries that open sockets, databases, background workers, or long-lived
clients should guard those side effects with `api.registrationMode === "full"`.
Discovery loads are cached separately from activating loads and do not replace
the running Gateway registry. Discovery is non-activating, not import-free:
OpenClaw may evaluate the trusted plugin entry or channel plugin module to build
the snapshot. Keep module top levels lightweight and side-effect-free, and move
network clients, subprocesses, listeners, credential reads, and service startup
behind full-runtime paths.
Common registration methods:
| Method | What it registers |
| --------------------------------------- | --------------------------- |
| `registerProvider` | Model provider (LLM) |
| `registerChannel` | Chat channel |
| `registerTool` | Agent tool |
| `registerHook` / `on(...)` | Lifecycle hooks |
| `registerSpeechProvider` | Text-to-speech / STT |
| `registerRealtimeTranscriptionProvider` | Streaming STT |
| `registerRealtimeVoiceProvider` | Duplex realtime voice |
| `registerMediaUnderstandingProvider` | Image/audio analysis |
| `registerImageGenerationProvider` | Image generation |
| `registerMusicGenerationProvider` | Music generation |
| `registerVideoGenerationProvider` | Video generation |
| `registerWebFetchProvider` | Web fetch / scrape provider |
| `registerWebSearchProvider` | Web search |
| `registerHttpRoute` | HTTP endpoint |
| `registerCommand` / `registerCli` | CLI commands |
| `registerContextEngine` | Context engine |
| `registerService` | Background service |
Hook guard behavior for typed lifecycle hooks:
- `before_tool_call`: `{ block: true }` is terminal; lower-priority handlers are skipped.
- `before_tool_call`: `{ block: false }` is a no-op and does not clear an earlier block.
- `before_install`: `{ block: true }` is terminal; lower-priority handlers are skipped.
- `before_install`: `{ block: false }` is a no-op and does not clear an earlier block.
- `message_sending`: `{ cancel: true }` is terminal; lower-priority handlers are skipped.
- `message_sending`: `{ cancel: false }` is a no-op and does not clear an earlier cancel.
Native Codex app-server runs bridge Codex-native tool events back into this
hook surface. Plugins can block native Codex tools through `before_tool_call`,
observe results through `after_tool_call`, and participate in Codex
`PermissionRequest` approvals. The bridge does not rewrite Codex-native tool
arguments yet. The exact Codex runtime support boundary lives in the
[Codex harness v1 support contract](/plugins/codex-harness-runtime#v1-support-contract).
For full typed hook behavior, see [SDK overview](/plugins/sdk-overview#hook-decision-semantics).
For dependency roots, package metadata validation, registry records, startup
reload behavior, and legacy cleanup, see
[Plugin dependency resolution](/plugins/dependency-resolution).
## Related
- [Building plugins](/plugins/building-plugins) - create your own plugin
- [Plugin bundles](/plugins/bundles) - Codex/Claude/Cursor bundle compatibility
- [Plugin manifest](/plugins/manifest) - manifest schema
- [Registering tools](/plugins/building-plugins#registering-agent-tools) - add agent tools in a plugin
- [Plugin internals](/plugins/architecture) - capability model and load pipeline
- [ClawHub](/clawhub) - third-party plugin discovery
- [Manage plugins](/plugins/manage-plugins) - command examples for list, install, update, uninstall, and publish
- [`openclaw plugins`](/cli/plugins) - full CLI reference
- [Plugin inventory](/plugins/plugin-inventory) - generated bundled and external plugin list
- [Plugin reference](/plugins/reference) - generated per-plugin reference pages
- [Community plugins](/plugins/community) - ClawHub discovery and docs PR policy
- [Plugin dependency resolution](/plugins/dependency-resolution) - install roots, registry records, and runtime boundaries
- [Building plugins](/plugins/building-plugins) - native plugin authoring guide
- [Plugin SDK overview](/plugins/sdk-overview) - runtime registration, hooks, and API fields
- [Plugin manifest](/plugins/manifest) - manifest and package metadata
+6 -5
View File
@@ -560,11 +560,12 @@ openclaw gateway restart
openclaw plugins inspect discord --runtime --json
\`\`\`
Bare package specs try ClawHub first, then npm fallback. To force a source, use
\`clawhub:@openclaw/discord\` or \`npm:@openclaw/discord\`. After install, follow
the plugin's setup doc, such as [Discord](/channels/discord), to add credentials
and channel config. See [Manage plugins](/plugins/manage-plugins) for update,
uninstall, and publishing commands.
During the launch cutover, ordinary bare package specs still install from npm.
Use \`clawhub:@openclaw/discord\` or \`npm:@openclaw/discord\` when you need an
explicit source. After install, follow the plugin's setup doc, such as
[Discord](/channels/discord), to add credentials and channel config. See
[Manage plugins](/plugins/manage-plugins) for update, uninstall, and publishing
commands.
## Core npm package
+1 -1
View File
@@ -576,7 +576,7 @@ function isKnownBenignLanceDbFinding(params: {
const evidence = params.finding.evidence ?? "";
if (params.finding.ruleId === "dangerous-exec" && relativePath === "dist/native.js") {
return (
/child_process/.test(evidence) &&
evidence.includes("child_process") &&
/\bexecSync\(\s*['"](?:ldd --version|which ldd)['"]/.test(evidence)
);
}