docs: restructure Tools & Plugins section, rename building-extensions to building-plugins, rewrite tools landing page and SDK migration

This commit is contained in:
Vincent Koc
2026-03-20 10:54:48 -07:00
parent 35ac1f6e07
commit 5f600e117d
7 changed files with 527 additions and 1008 deletions

View File

@@ -64,6 +64,10 @@
"source": "/platforms/raspberry-pi",
"destination": "/install/raspberry-pi"
},
{
"source": "/plugins/building-extensions",
"destination": "/plugins/building-plugins"
},
{
"source": "/brave-search",
"destination": "/tools/brave-search"
@@ -1015,7 +1019,7 @@
]
},
{
"tab": "Tools",
"tab": "Tools & Plugins",
"groups": [
{
"group": "Overview",
@@ -1024,23 +1028,20 @@
{
"group": "Built-in tools",
"pages": [
"tools/apply-patch",
"tools/brave-search",
"tools/btw",
"tools/diffs",
"tools/elevated",
"tools/exec",
"tools/exec-approvals",
"tools/elevated",
"tools/apply-patch",
"tools/web",
"tools/brave-search",
"tools/firecrawl",
"tools/tavily",
"tools/llm-task",
"tools/lobster",
"tools/loop-detection",
"tools/pdf",
"tools/perplexity-search",
"tools/pdf",
"tools/reactions",
"tools/thinking",
"tools/web"
"tools/loop-detection",
"tools/btw"
]
},
{
@@ -1061,22 +1062,11 @@
"tools/multi-agent-sandbox-tools"
]
},
{
"group": "Skills",
"pages": [
"tools/creating-skills",
"tools/slash-commands",
"tools/skills",
"tools/skills-config",
"tools/clawhub",
"tools/plugin",
"prose"
]
},
{
"group": "Plugins",
"pages": [
"plugins/building-extensions",
"tools/plugin",
"plugins/building-plugins",
"plugins/sdk-migration",
"plugins/architecture",
"plugins/community",
@@ -1086,6 +1076,21 @@
"tools/capability-cookbook"
]
},
{
"group": "Skills",
"pages": [
"tools/skills",
"tools/creating-skills",
"tools/skills-config",
"tools/slash-commands",
"tools/clawhub",
"prose"
]
},
{
"group": "Plugin tools",
"pages": ["tools/diffs", "tools/llm-task", "tools/lobster"]
},
{
"group": "Automation",
"pages": [

View File

@@ -1,309 +1,10 @@
---
title: "Building Plugins"
sidebarTitle: "Building Plugins"
summary: "Step-by-step guide for creating OpenClaw plugins with any combination of capabilities"
summary: "Redirects to the current Building Plugins guide"
read_when:
- You want to create a new OpenClaw plugin
- You need to understand the plugin SDK import patterns
- You are adding a new channel, provider, tool, or other capability to OpenClaw
- Legacy link to building-extensions
---
# Building Plugins
Plugins extend OpenClaw with new capabilities: channels, model providers, speech,
image generation, web search, agent tools, or any combination. A single plugin
can register multiple capabilities.
OpenClaw encourages **external plugin development**. You do not need to add your
plugin to the OpenClaw repository. Publish your plugin on npm, and users install
it with `openclaw plugins install <npm-spec>`. OpenClaw also maintains a set of
core plugins in-repo, but the plugin system is designed for independent ownership
and distribution.
## Prerequisites
- Node >= 22 and a package manager (npm or pnpm)
- Familiarity with TypeScript (ESM)
- For in-repo plugins: OpenClaw repository cloned and `pnpm install` done
## Plugin capabilities
A plugin can register one or more capabilities. The capability you register
determines what your plugin provides to OpenClaw:
| Capability | Registration method | What it adds |
| ------------------- | --------------------------------------------- | ------------------------------ |
| Text inference | `api.registerProvider(...)` | Model provider (LLM) |
| Channel / messaging | `api.registerChannel(...)` | Chat channel (e.g. Slack, IRC) |
| Speech | `api.registerSpeechProvider(...)` | Text-to-speech / STT |
| Media understanding | `api.registerMediaUnderstandingProvider(...)` | Image/audio/video analysis |
| Image generation | `api.registerImageGenerationProvider(...)` | Image generation |
| Web search | `api.registerWebSearchProvider(...)` | Web search provider |
| Agent tools | `api.registerTool(...)` | Tools callable by the agent |
A plugin that registers zero capabilities but provides hooks or services is a
**hook-only** plugin. That pattern is still supported.
## Plugin structure
Plugins follow this layout (whether in-repo or standalone):
```
my-plugin/
├── package.json # npm metadata + openclaw config
├── openclaw.plugin.json # Plugin manifest
├── index.ts # Entry point
├── setup-entry.ts # Setup wizard (optional)
├── api.ts # Public exports (optional)
├── runtime-api.ts # Internal exports (optional)
└── src/
├── provider.ts # Capability implementation
├── runtime.ts # Runtime wiring
└── *.test.ts # Colocated tests
```
## Create a plugin
<Steps>
<Step title="Create the package">
Create `package.json` with the `openclaw` metadata block. The structure
depends on what capabilities your plugin provides.
**Channel plugin example:**
```json
{
"name": "@myorg/openclaw-my-channel",
"version": "1.0.0",
"type": "module",
"openclaw": {
"extensions": ["./index.ts"],
"channel": {
"id": "my-channel",
"label": "My Channel",
"blurb": "Short description of the channel."
}
}
}
```
**Provider plugin example:**
```json
{
"name": "@myorg/openclaw-my-provider",
"version": "1.0.0",
"type": "module",
"openclaw": {
"extensions": ["./index.ts"],
"providers": ["my-provider"]
}
}
```
The `openclaw` field tells the plugin system what your plugin provides.
A plugin can declare both `channel` and `providers` if it provides multiple
capabilities.
</Step>
<Step title="Define the entry point">
The entry point registers your capabilities with the plugin API.
**Channel plugin:**
```typescript
import { defineChannelPluginEntry } from "openclaw/plugin-sdk/core";
export default defineChannelPluginEntry({
id: "my-channel",
name: "My Channel",
description: "Connects OpenClaw to My Channel",
plugin: {
// Channel adapter implementation
},
});
```
**Provider plugin:**
```typescript
import { definePluginEntry } from "openclaw/plugin-sdk/core";
export default definePluginEntry({
id: "my-provider",
name: "My Provider",
register(api) {
api.registerProvider({
// Provider implementation
});
},
});
```
**Multi-capability plugin** (provider + tool):
```typescript
import { definePluginEntry } from "openclaw/plugin-sdk/core";
export default definePluginEntry({
id: "my-plugin",
name: "My Plugin",
register(api) {
api.registerProvider({ /* ... */ });
api.registerTool({ /* ... */ });
api.registerImageGenerationProvider({ /* ... */ });
},
});
```
Use `defineChannelPluginEntry` for channel plugins and `definePluginEntry`
for everything else. A single plugin can register as many capabilities as needed.
</Step>
<Step title="Import from focused SDK subpaths">
Always import from specific `openclaw/plugin-sdk/\<subpath\>` paths. The old
monolithic import is deprecated (see [SDK Migration](/plugins/sdk-migration)).
```typescript
// Correct: focused subpaths
import { definePluginEntry } from "openclaw/plugin-sdk/core";
import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store";
import { buildOauthProviderAuthResult } from "openclaw/plugin-sdk/provider-oauth";
// Wrong: monolithic root (lint will reject this)
import { ... } from "openclaw/plugin-sdk";
```
<Accordion title="Common subpaths reference">
| Subpath | Purpose |
| --- | --- |
| `plugin-sdk/core` | Plugin entry definitions and base types |
| `plugin-sdk/channel-setup` | Setup wizard adapters |
| `plugin-sdk/channel-pairing` | DM pairing primitives |
| `plugin-sdk/channel-reply-pipeline` | Reply prefix + typing wiring |
| `plugin-sdk/channel-config-schema` | Config schema builders |
| `plugin-sdk/channel-policy` | Group/DM policy helpers |
| `plugin-sdk/secret-input` | Secret input parsing/helpers |
| `plugin-sdk/webhook-ingress` | Webhook request/target helpers |
| `plugin-sdk/runtime-store` | Persistent plugin storage |
| `plugin-sdk/allow-from` | Allowlist resolution |
| `plugin-sdk/reply-payload` | Message reply types |
| `plugin-sdk/provider-oauth` | OAuth login + PKCE helpers |
| `plugin-sdk/provider-onboard` | Provider onboarding config patches |
| `plugin-sdk/testing` | Test utilities |
</Accordion>
Use the narrowest subpath that matches the job.
</Step>
<Step title="Use local modules for internal imports">
Within your plugin, create local module files for internal code sharing
instead of re-importing through the plugin SDK:
```typescript
// api.ts — public exports for this plugin
export { MyConfig } from "./src/config.js";
export { MyRuntime } from "./src/runtime.js";
// runtime-api.ts — internal-only exports
export { internalHelper } from "./src/helpers.js";
```
<Warning>
Never import your own plugin back through its published SDK path from
production files. Route internal imports through local files like `./api.ts`
or `./runtime-api.ts`. The SDK path is for external consumers only.
</Warning>
</Step>
<Step title="Add a plugin manifest">
Create `openclaw.plugin.json` in your plugin root:
```json
{
"id": "my-plugin",
"kind": "provider",
"name": "My Plugin",
"description": "Adds My Provider to OpenClaw"
}
```
For channel plugins, set `"kind": "channel"` and add `"channels": ["my-channel"]`.
See [Plugin Manifest](/plugins/manifest) for the full schema.
</Step>
<Step title="Test your plugin">
**External plugins:** run your own test suite against the plugin SDK contracts.
**In-repo plugins:** OpenClaw runs contract tests against all registered plugins:
```bash
pnpm test:contracts:channels # channel plugins
pnpm test:contracts:plugins # provider plugins
```
For unit tests, import test helpers from the testing surface:
```typescript
import { createTestRuntime } from "openclaw/plugin-sdk/testing";
```
</Step>
<Step title="Publish and install">
**External plugins:** publish to npm, then install:
```bash
npm publish
openclaw plugins install @myorg/openclaw-my-plugin
```
**In-repo plugins:** place the plugin under `extensions/` and it is
automatically discovered during build.
Users can browse and install community plugins with:
```bash
openclaw plugins search <query>
openclaw plugins install <npm-spec>
```
</Step>
</Steps>
## Lint enforcement (in-repo plugins)
Three scripts enforce SDK boundaries for plugins in the OpenClaw repository:
1. **No monolithic root imports** — `openclaw/plugin-sdk` root is rejected
2. **No direct src/ imports** — plugins cannot import `../../src/` directly
3. **No self-imports** — plugins cannot import their own `plugin-sdk/\<name\>` subpath
Run `pnpm check` to verify all boundaries before committing.
External plugins are not subject to these lint rules, but following the same
patterns is strongly recommended.
## Pre-submission checklist
<Check>**package.json** has correct `openclaw` metadata</Check>
<Check>Entry point uses `defineChannelPluginEntry` or `definePluginEntry`</Check>
<Check>All imports use focused `plugin-sdk/\<subpath\>` paths</Check>
<Check>Internal imports use local modules, not SDK self-imports</Check>
<Check>`openclaw.plugin.json` manifest is present and valid</Check>
<Check>Tests pass</Check>
<Check>`pnpm check` passes (in-repo plugins)</Check>
## Related
- [Plugin SDK Migration](/plugins/sdk-migration) — migrating from the deprecated compat import
- [Plugin Architecture](/plugins/architecture) — internals and capability model
- [Plugin Manifest](/plugins/manifest) — full manifest schema
- [Plugin Agent Tools](/plugins/agent-tools) — adding agent tools in a plugin
- [Community Plugins](/plugins/community) — listing and quality bar
This page has moved to [Building Plugins](/plugins/building-plugins).

View File

@@ -0,0 +1,309 @@
---
title: "Building Plugins"
sidebarTitle: "Building Plugins"
summary: "Step-by-step guide for creating OpenClaw plugins with any combination of capabilities"
read_when:
- You want to create a new OpenClaw plugin
- You need to understand the plugin SDK import patterns
- You are adding a new channel, provider, tool, or other capability to OpenClaw
---
# Building Plugins
Plugins extend OpenClaw with new capabilities: channels, model providers, speech,
image generation, web search, agent tools, or any combination. A single plugin
can register multiple capabilities.
OpenClaw encourages **external plugin development**. You do not need to add your
plugin to the OpenClaw repository. Publish your plugin on npm, and users install
it with `openclaw plugins install <npm-spec>`. OpenClaw also maintains a set of
core plugins in-repo, but the plugin system is designed for independent ownership
and distribution.
## Prerequisites
- Node >= 22 and a package manager (npm or pnpm)
- Familiarity with TypeScript (ESM)
- For in-repo plugins: OpenClaw repository cloned and `pnpm install` done
## Plugin capabilities
A plugin can register one or more capabilities. The capability you register
determines what your plugin provides to OpenClaw:
| Capability | Registration method | What it adds |
| ------------------- | --------------------------------------------- | ------------------------------ |
| Text inference | `api.registerProvider(...)` | Model provider (LLM) |
| Channel / messaging | `api.registerChannel(...)` | Chat channel (e.g. Slack, IRC) |
| Speech | `api.registerSpeechProvider(...)` | Text-to-speech / STT |
| Media understanding | `api.registerMediaUnderstandingProvider(...)` | Image/audio/video analysis |
| Image generation | `api.registerImageGenerationProvider(...)` | Image generation |
| Web search | `api.registerWebSearchProvider(...)` | Web search provider |
| Agent tools | `api.registerTool(...)` | Tools callable by the agent |
A plugin that registers zero capabilities but provides hooks or services is a
**hook-only** plugin. That pattern is still supported.
## Plugin structure
Plugins follow this layout (whether in-repo or standalone):
```
my-plugin/
├── package.json # npm metadata + openclaw config
├── openclaw.plugin.json # Plugin manifest
├── index.ts # Entry point
├── setup-entry.ts # Setup wizard (optional)
├── api.ts # Public exports (optional)
├── runtime-api.ts # Internal exports (optional)
└── src/
├── provider.ts # Capability implementation
├── runtime.ts # Runtime wiring
└── *.test.ts # Colocated tests
```
## Create a plugin
<Steps>
<Step title="Create the package">
Create `package.json` with the `openclaw` metadata block. The structure
depends on what capabilities your plugin provides.
**Channel plugin example:**
```json
{
"name": "@myorg/openclaw-my-channel",
"version": "1.0.0",
"type": "module",
"openclaw": {
"extensions": ["./index.ts"],
"channel": {
"id": "my-channel",
"label": "My Channel",
"blurb": "Short description of the channel."
}
}
}
```
**Provider plugin example:**
```json
{
"name": "@myorg/openclaw-my-provider",
"version": "1.0.0",
"type": "module",
"openclaw": {
"extensions": ["./index.ts"],
"providers": ["my-provider"]
}
}
```
The `openclaw` field tells the plugin system what your plugin provides.
A plugin can declare both `channel` and `providers` if it provides multiple
capabilities.
</Step>
<Step title="Define the entry point">
The entry point registers your capabilities with the plugin API.
**Channel plugin:**
```typescript
import { defineChannelPluginEntry } from "openclaw/plugin-sdk/core";
export default defineChannelPluginEntry({
id: "my-channel",
name: "My Channel",
description: "Connects OpenClaw to My Channel",
plugin: {
// Channel adapter implementation
},
});
```
**Provider plugin:**
```typescript
import { definePluginEntry } from "openclaw/plugin-sdk/core";
export default definePluginEntry({
id: "my-provider",
name: "My Provider",
register(api) {
api.registerProvider({
// Provider implementation
});
},
});
```
**Multi-capability plugin** (provider + tool):
```typescript
import { definePluginEntry } from "openclaw/plugin-sdk/core";
export default definePluginEntry({
id: "my-plugin",
name: "My Plugin",
register(api) {
api.registerProvider({ /* ... */ });
api.registerTool({ /* ... */ });
api.registerImageGenerationProvider({ /* ... */ });
},
});
```
Use `defineChannelPluginEntry` for channel plugins and `definePluginEntry`
for everything else. A single plugin can register as many capabilities as needed.
</Step>
<Step title="Import from focused SDK subpaths">
Always import from specific `openclaw/plugin-sdk/\<subpath\>` paths. The old
monolithic import is deprecated (see [SDK Migration](/plugins/sdk-migration)).
```typescript
// Correct: focused subpaths
import { definePluginEntry } from "openclaw/plugin-sdk/core";
import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store";
import { buildOauthProviderAuthResult } from "openclaw/plugin-sdk/provider-oauth";
// Wrong: monolithic root (lint will reject this)
import { ... } from "openclaw/plugin-sdk";
```
<Accordion title="Common subpaths reference">
| Subpath | Purpose |
| --- | --- |
| `plugin-sdk/core` | Plugin entry definitions and base types |
| `plugin-sdk/channel-setup` | Setup wizard adapters |
| `plugin-sdk/channel-pairing` | DM pairing primitives |
| `plugin-sdk/channel-reply-pipeline` | Reply prefix + typing wiring |
| `plugin-sdk/channel-config-schema` | Config schema builders |
| `plugin-sdk/channel-policy` | Group/DM policy helpers |
| `plugin-sdk/secret-input` | Secret input parsing/helpers |
| `plugin-sdk/webhook-ingress` | Webhook request/target helpers |
| `plugin-sdk/runtime-store` | Persistent plugin storage |
| `plugin-sdk/allow-from` | Allowlist resolution |
| `plugin-sdk/reply-payload` | Message reply types |
| `plugin-sdk/provider-oauth` | OAuth login + PKCE helpers |
| `plugin-sdk/provider-onboard` | Provider onboarding config patches |
| `plugin-sdk/testing` | Test utilities |
</Accordion>
Use the narrowest subpath that matches the job.
</Step>
<Step title="Use local modules for internal imports">
Within your plugin, create local module files for internal code sharing
instead of re-importing through the plugin SDK:
```typescript
// api.ts — public exports for this plugin
export { MyConfig } from "./src/config.js";
export { MyRuntime } from "./src/runtime.js";
// runtime-api.ts — internal-only exports
export { internalHelper } from "./src/helpers.js";
```
<Warning>
Never import your own plugin back through its published SDK path from
production files. Route internal imports through local files like `./api.ts`
or `./runtime-api.ts`. The SDK path is for external consumers only.
</Warning>
</Step>
<Step title="Add a plugin manifest">
Create `openclaw.plugin.json` in your plugin root:
```json
{
"id": "my-plugin",
"kind": "provider",
"name": "My Plugin",
"description": "Adds My Provider to OpenClaw"
}
```
For channel plugins, set `"kind": "channel"` and add `"channels": ["my-channel"]`.
See [Plugin Manifest](/plugins/manifest) for the full schema.
</Step>
<Step title="Test your plugin">
**External plugins:** run your own test suite against the plugin SDK contracts.
**In-repo plugins:** OpenClaw runs contract tests against all registered plugins:
```bash
pnpm test:contracts:channels # channel plugins
pnpm test:contracts:plugins # provider plugins
```
For unit tests, import test helpers from the testing surface:
```typescript
import { createTestRuntime } from "openclaw/plugin-sdk/testing";
```
</Step>
<Step title="Publish and install">
**External plugins:** publish to npm, then install:
```bash
npm publish
openclaw plugins install @myorg/openclaw-my-plugin
```
**In-repo plugins:** place the plugin under `extensions/` and it is
automatically discovered during build.
Users can browse and install community plugins with:
```bash
openclaw plugins search <query>
openclaw plugins install <npm-spec>
```
</Step>
</Steps>
## Lint enforcement (in-repo plugins)
Three scripts enforce SDK boundaries for plugins in the OpenClaw repository:
1. **No monolithic root imports** — `openclaw/plugin-sdk` root is rejected
2. **No direct src/ imports** — plugins cannot import `../../src/` directly
3. **No self-imports** — plugins cannot import their own `plugin-sdk/\<name\>` subpath
Run `pnpm check` to verify all boundaries before committing.
External plugins are not subject to these lint rules, but following the same
patterns is strongly recommended.
## Pre-submission checklist
<Check>**package.json** has correct `openclaw` metadata</Check>
<Check>Entry point uses `defineChannelPluginEntry` or `definePluginEntry`</Check>
<Check>All imports use focused `plugin-sdk/\<subpath\>` paths</Check>
<Check>Internal imports use local modules, not SDK self-imports</Check>
<Check>`openclaw.plugin.json` manifest is present and valid</Check>
<Check>Tests pass</Check>
<Check>`pnpm check` passes (in-repo plugins)</Check>
## Related
- [Plugin SDK Migration](/plugins/sdk-migration) — migrating from the deprecated compat import
- [Plugin Architecture](/plugins/architecture) — internals and capability model
- [Plugin Manifest](/plugins/manifest) — full manifest schema
- [Plugin Agent Tools](/plugins/agent-tools) — adding agent tools in a plugin
- [Community Plugins](/plugins/community) — listing and quality bar

View File

@@ -1,121 +1,117 @@
---
title: "Plugin SDK Migration"
sidebarTitle: "SDK Migration"
summary: "Migrate from openclaw/plugin-sdk/compat to focused subpath imports"
summary: "Migrate from the deprecated openclaw/plugin-sdk/compat import to focused subpath imports"
read_when:
- You see the OPENCLAW_PLUGIN_SDK_COMPAT_DEPRECATED warning
- You are updating a plugin from the monolithic plugin-sdk import to scoped subpaths
- You are updating a plugin from the monolithic import to scoped subpaths
- You maintain an external OpenClaw plugin
---
# Plugin SDK Migration
OpenClaw is migrating from a single monolithic `openclaw/plugin-sdk/compat` barrel
to **focused subpath imports** (`openclaw/plugin-sdk/\<subpath\>`). This page explains
what changed, why, and how to migrate.
The `openclaw/plugin-sdk/compat` import is deprecated. All plugins should use
**focused subpath imports** (`openclaw/plugin-sdk/\<subpath\>`) instead.
## Why this change
<Info>
The compat import still works at runtime. This is a deprecation warning, not
a breaking change yet. But new plugins **must not** use it, and existing
plugins should migrate before the next major release removes it.
</Info>
The monolithic compat entry re-exported everything from a single entry point.
This caused:
## Why this changed
- **Slow startup**: importing one helper pulled in dozens of unrelated modules.
- **Circular dependency risk**: broad re-exports made it easy to create import cycles.
- **Unclear API surface**: no way to tell which exports were stable vs internal.
The old monolithic `openclaw/plugin-sdk/compat` re-exported everything from one
entry point. This caused slow startup (importing one helper loaded dozens of
unrelated modules), circular dependency risk, and an unclear API surface.
Focused subpaths fix all three: each subpath is a small, self-contained module
with a clear purpose.
## What triggers the warning
## Migration steps
If your plugin imports from the compat entry, you will see:
<Steps>
<Step title="Find deprecated imports">
Search your plugin for imports from the compat path:
```
[OPENCLAW_PLUGIN_SDK_COMPAT_DEPRECATED] Warning: openclaw/plugin-sdk/compat is
deprecated for new plugins. Migrate to focused openclaw/plugin-sdk/\<subpath\> imports.
```
```bash
grep -r "plugin-sdk/compat" my-plugin/
```
The compat entry still works at runtime. This is a deprecation warning, not an
error. But new plugins **must not** use it, and existing plugins should migrate
before compat is removed.
</Step>
## How to migrate
<Step title="Replace with focused subpaths">
Each export maps to a specific subpath. Replace the import source:
### Step 1: Find compat imports
```typescript
// Before (deprecated)
import {
createChannelReplyPipeline,
createPluginRuntimeStore,
resolveControlCommandGate,
} from "openclaw/plugin-sdk/compat";
Search your extension for imports from the compat path:
// After (focused subpaths)
import { createChannelReplyPipeline } from "openclaw/plugin-sdk/channel-reply-pipeline";
import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store";
import { resolveControlCommandGate } from "openclaw/plugin-sdk/command-auth";
```
```bash
grep -r "plugin-sdk/compat" extensions/my-plugin/
```
See the [subpath reference](#subpath-reference) below for the full mapping.
### Step 2: Replace with focused subpaths
</Step>
Each export from compat maps to a specific subpath. Replace the import source:
```typescript
// Before (compat entry)
import {
createChannelReplyPipeline,
createPluginRuntimeStore,
resolveControlCommandGate,
} from "openclaw/plugin-sdk/compat";
// After (focused subpaths)
import { createChannelReplyPipeline } from "openclaw/plugin-sdk/channel-reply-pipeline";
import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store";
import { resolveControlCommandGate } from "openclaw/plugin-sdk/command-auth";
```
### Step 3: Verify
Run the build and tests:
```bash
pnpm build
pnpm test -- extensions/my-plugin/
```
<Step title="Build and test">
```bash
pnpm build
pnpm test -- my-plugin/
```
</Step>
</Steps>
## Subpath reference
| Subpath | Purpose | Key exports |
| ----------------------------------- | ------------------------------------ | ---------------------------------------------------------------------- |
| `plugin-sdk/core` | Plugin entry definitions, base types | `defineChannelPluginEntry`, `definePluginEntry` |
| `plugin-sdk/channel-setup` | Setup wizard adapters | `createOptionalChannelSetupSurface` |
| `plugin-sdk/channel-pairing` | DM pairing primitives | `createChannelPairingController` |
| `plugin-sdk/channel-reply-pipeline` | Reply prefix + typing wiring | `createChannelReplyPipeline` |
| `plugin-sdk/channel-config-helpers` | Config adapter factories | `createHybridChannelConfigAdapter`, `createScopedChannelConfigAdapter` |
| `plugin-sdk/channel-config-schema` | Config schema builders | Channel config schema types |
| `plugin-sdk/channel-policy` | Group/DM policy resolution | `resolveChannelGroupRequireMention` |
| `plugin-sdk/channel-lifecycle` | Account status tracking | `createAccountStatusSink` |
| `plugin-sdk/channel-runtime` | Runtime wiring helpers | Channel runtime utilities |
| `plugin-sdk/channel-send-result` | Send result types | Reply result types |
| `plugin-sdk/runtime-store` | Persistent plugin storage | `createPluginRuntimeStore` |
| `plugin-sdk/allow-from` | Allowlist formatting | `formatAllowFromLowercase`, `formatNormalizedAllowFromEntries` |
| `plugin-sdk/allowlist-resolution` | Allowlist input mapping | `mapAllowlistResolutionInputs` |
| `plugin-sdk/command-auth` | Command gating | `resolveControlCommandGate` |
| `plugin-sdk/secret-input` | Secret input parsing | Secret input helpers |
| `plugin-sdk/webhook-ingress` | Webhook request helpers | Webhook target utilities |
| `plugin-sdk/reply-payload` | Message reply types | Reply payload types |
| `plugin-sdk/provider-onboard` | Provider onboarding patches | Onboarding config helpers |
| `plugin-sdk/keyed-async-queue` | Ordered async queue | `KeyedAsyncQueue` |
| `plugin-sdk/testing` | Test utilities | Test helpers and mocks |
<Accordion title="Full subpath table">
| Subpath | Purpose | Key exports |
| --- | --- | --- |
| `plugin-sdk/core` | Plugin entry definitions, base types | `defineChannelPluginEntry`, `definePluginEntry` |
| `plugin-sdk/channel-setup` | Setup wizard adapters | `createOptionalChannelSetupSurface` |
| `plugin-sdk/channel-pairing` | DM pairing primitives | `createChannelPairingController` |
| `plugin-sdk/channel-reply-pipeline` | Reply prefix + typing wiring | `createChannelReplyPipeline` |
| `plugin-sdk/channel-config-helpers` | Config adapter factories | `createHybridChannelConfigAdapter` |
| `plugin-sdk/channel-config-schema` | Config schema builders | Channel config schema types |
| `plugin-sdk/channel-policy` | Group/DM policy resolution | `resolveChannelGroupRequireMention` |
| `plugin-sdk/channel-lifecycle` | Account status tracking | `createAccountStatusSink` |
| `plugin-sdk/channel-runtime` | Runtime wiring helpers | Channel runtime utilities |
| `plugin-sdk/channel-send-result` | Send result types | Reply result types |
| `plugin-sdk/runtime-store` | Persistent plugin storage | `createPluginRuntimeStore` |
| `plugin-sdk/allow-from` | Allowlist formatting | `formatAllowFromLowercase` |
| `plugin-sdk/allowlist-resolution` | Allowlist input mapping | `mapAllowlistResolutionInputs` |
| `plugin-sdk/command-auth` | Command gating | `resolveControlCommandGate` |
| `plugin-sdk/secret-input` | Secret input parsing | Secret input helpers |
| `plugin-sdk/webhook-ingress` | Webhook request helpers | Webhook target utilities |
| `plugin-sdk/reply-payload` | Message reply types | Reply payload types |
| `plugin-sdk/provider-onboard` | Provider onboarding patches | Onboarding config helpers |
| `plugin-sdk/keyed-async-queue` | Ordered async queue | `KeyedAsyncQueue` |
| `plugin-sdk/testing` | Test utilities | Test helpers and mocks |
</Accordion>
Use the narrowest subpath that has what you need. If you cannot find an export,
Use the narrowest subpath that matches the job. If you cannot find an export,
check the source at `src/plugin-sdk/` or ask in Discord.
## Compat barrel removal timeline
## Removal timeline
- **Now**: compat entry emits a deprecation warning at runtime.
- **Next major release**: compat entry will be removed. Plugins still using it will
fail to import.
| When | What happens |
| ---------------------- | --------------------------------------------------------------- |
| **Now** | Compat import emits a runtime deprecation warning |
| **Next major release** | Compat import will be removed; plugins still using it will fail |
Bundled plugins (under `extensions/`) have already been migrated. External plugins
should migrate before the next major release.
All core plugins have already been migrated. External plugins should migrate
before the next major release.
## Suppressing the warning temporarily
If you need to suppress the warning while migrating:
Set this environment variable while you work on migrating:
```bash
OPENCLAW_SUPPRESS_PLUGIN_SDK_COMPAT_WARNING=1 openclaw gateway run
@@ -123,23 +119,8 @@ OPENCLAW_SUPPRESS_PLUGIN_SDK_COMPAT_WARNING=1 openclaw gateway run
This is a temporary escape hatch, not a permanent solution.
## Internal barrel pattern
Within your extension, use local barrel files (`api.ts`, `runtime-api.ts`) for
internal code sharing instead of importing through the plugin SDK:
```typescript
// extensions/my-plugin/api.ts — public contract for this extension
export { MyConfig } from "./src/config.js";
export { MyRuntime } from "./src/runtime.js";
```
Never import your own extension back through `openclaw/plugin-sdk/\<your-extension\>`
from production files. That path is for external consumers only. See
[Building Extensions](/plugins/building-extensions#step-4-use-local-barrels-for-internal-imports).
## Related
- [Building Extensions](/plugins/building-extensions)
- [Building Plugins](/plugins/building-plugins)
- [Plugin Architecture](/plugins/architecture)
- [Plugin Manifest](/plugins/manifest)

View File

@@ -164,7 +164,7 @@ Use these hubs to discover every page, including deep dives and reference docs t
## Extensions + plugins
- [Plugins overview](/tools/plugin)
- [Building extensions](/plugins/building-extensions)
- [Building plugins](/plugins/building-plugins)
- [Plugin manifest](/plugins/manifest)
- [Agent tools](/plugins/agent-tools)
- [Plugin bundles](/plugins/bundles)

View File

@@ -1,96 +1,89 @@
---
summary: "Agent tool surface for OpenClaw (browser, canvas, nodes, message, cron) replacing legacy `openclaw-*` skills"
summary: "OpenClaw tools and plugins overview: what the agent can do and how to extend it"
read_when:
- Adding or modifying agent tools
- Retiring or changing `openclaw-*` skills
title: "Tools"
- You want to understand what tools OpenClaw provides
- You need to configure, allow, or deny tools
- You are deciding between built-in tools, skills, and plugins
title: "Tools and Plugins"
---
# Tools (OpenClaw)
# Tools and Plugins
OpenClaw exposes **first-class agent tools** for browser, canvas, nodes, and cron.
These replace the old `openclaw-*` skills: the tools are typed, no shelling,
and the agent should rely on them directly.
OpenClaw gives the agent a set of **tools** it can call during a conversation.
Tools are how the agent reads files, runs commands, browses the web, sends
messages, and interacts with devices. Everything the agent does beyond generating
text happens through tools.
## Disabling tools
## How it all fits together
You can globally allow/deny tools via `tools.allow` / `tools.deny` in `openclaw.json`
(deny wins). This prevents disallowed tools from being sent to model providers.
<CardGroup cols={2}>
<Card title="Built-in tools" icon="wrench" href="/tools/exec">
Core tools shipped with OpenClaw: exec, browser, web search, file I/O,
messaging, cron, canvas, and nodes.
</Card>
<Card title="Skills" icon="book-open" href="/tools/skills">
Markdown instructions that teach the agent how and when to use tools.
Skills ship inside plugins or live in your workspace.
</Card>
<Card title="Plugins" icon="puzzle-piece" href="/tools/plugin">
Packages that add new capabilities: channels, model providers, tools,
skills, or any combination. Published on npm and installed with the CLI.
</Card>
<Card title="Automation" icon="clock" href="/automation/hooks">
Hooks, cron jobs, heartbeats, webhooks, and scheduled tasks that run
without manual messages.
</Card>
</CardGroup>
## Tool configuration
### Allow and deny lists
Control which tools the agent can call via `tools.allow` / `tools.deny` in
config. Deny always wins over allow.
```json5
{
tools: { deny: ["browser"] },
tools: {
allow: ["group:fs", "browser", "web_search"],
deny: ["exec"],
},
}
```
Notes:
### Tool profiles
- Matching is case-insensitive.
- `*` wildcards are supported (`"*"` means all tools).
- If `tools.allow` only references unknown or unloaded plugin tool names, OpenClaw logs a warning and ignores the allowlist so core tools stay available.
## Tool profiles (base allowlist)
`tools.profile` sets a **base tool allowlist** before `tools.allow`/`tools.deny`.
`tools.profile` sets a base allowlist before `allow`/`deny` is applied.
Per-agent override: `agents.list[].tools.profile`.
Profiles:
| Profile | What it includes |
| ----------- | ------------------------------------------- |
| `full` | All tools (default) |
| `coding` | File I/O, runtime, sessions, memory, image |
| `messaging` | Messaging, session list/history/send/status |
| `minimal` | `session_status` only |
- `minimal`: `session_status` only
- `coding`: `group:fs`, `group:runtime`, `group:sessions`, `group:memory`, `image`
- `messaging`: `group:messaging`, `sessions_list`, `sessions_history`, `sessions_send`, `session_status`
- `full`: no restriction (same as unset)
### Tool groups
Example (messaging-only by default, allow Slack + Discord tools too):
Use `group:*` shorthands in allow/deny lists:
```json5
{
tools: {
profile: "messaging",
allow: ["slack", "discord"],
},
}
```
| Group | Tools |
| ------------------ | ------------------------------------------------------------------------------ |
| `group:runtime` | exec, bash, process |
| `group:fs` | read, write, edit, apply_patch |
| `group:sessions` | sessions_list, sessions_history, sessions_send, sessions_spawn, session_status |
| `group:memory` | memory_search, memory_get |
| `group:web` | web_search, web_fetch |
| `group:ui` | browser, canvas |
| `group:automation` | cron, gateway |
| `group:messaging` | message |
| `group:nodes` | nodes |
| `group:openclaw` | All built-in OpenClaw tools (excludes plugin tools) |
Example (coding profile, but deny exec/process everywhere):
### Provider-specific restrictions
```json5
{
tools: {
profile: "coding",
deny: ["group:runtime"],
},
}
```
Example (global coding profile, messaging-only support agent):
```json5
{
tools: { profile: "coding" },
agents: {
list: [
{
id: "support",
tools: { profile: "messaging", allow: ["slack"] },
},
],
},
}
```
## Provider-specific tool policy
Use `tools.byProvider` to **further restrict** tools for specific providers
(or a single `provider/model`) without changing your global defaults.
Per-agent override: `agents.list[].tools.byProvider`.
This is applied **after** the base tool profile and **before** allow/deny lists,
so it can only narrow the tool set.
Provider keys accept either `provider` (e.g. `google-antigravity`) or
`provider/model` (e.g. `openai/gpt-5.2`).
Example (keep global coding profile, but minimal tools for Google Antigravity):
Use `tools.byProvider` to restrict tools for specific providers without
changing global defaults:
```json5
{
@@ -103,514 +96,43 @@ Example (keep global coding profile, but minimal tools for Google Antigravity):
}
```
Example (provider/model-specific allowlist for a flaky endpoint):
```json5
{
tools: {
allow: ["group:fs", "group:runtime", "sessions_list"],
byProvider: {
"openai/gpt-5.2": { allow: ["group:fs", "sessions_list"] },
},
},
}
```
Example (agent-specific override for a single provider):
```json5
{
agents: {
list: [
{
id: "support",
tools: {
byProvider: {
"google-antigravity": { allow: ["message", "sessions_list"] },
},
},
},
],
},
}
```
## Tool groups (shorthands)
Tool policies (global, agent, sandbox) support `group:*` entries that expand to multiple tools.
Use these in `tools.allow` / `tools.deny`.
Available groups:
- `group:runtime`: `exec`, `bash`, `process`
- `group:fs`: `read`, `write`, `edit`, `apply_patch`
- `group:sessions`: `sessions_list`, `sessions_history`, `sessions_send`, `sessions_spawn`, `session_status`
- `group:memory`: `memory_search`, `memory_get`
- `group:web`: `web_search`, `web_fetch`
- `group:ui`: `browser`, `canvas`
- `group:automation`: `cron`, `gateway`
- `group:messaging`: `message`
- `group:nodes`: `nodes`
- `group:openclaw`: all built-in OpenClaw tools (excludes provider plugins)
Example (allow only file tools + browser):
```json5
{
tools: {
allow: ["group:fs", "browser"],
},
}
```
## Plugins + tools
Plugins can register **additional tools** (and CLI commands) beyond the core set.
See [Plugins](/tools/plugin) for install + config, and [Skills](/tools/skills) for how
tool usage guidance is injected into prompts. Some plugins ship their own skills
alongside tools (for example, the voice-call plugin).
Optional plugin tools:
- [Lobster](/tools/lobster): typed workflow runtime with resumable approvals (requires the Lobster CLI on the gateway host).
- [LLM Task](/tools/llm-task): JSON-only LLM step for structured workflow output (optional schema validation).
- [Diffs](/tools/diffs): read-only diff viewer and PNG or PDF file renderer for before/after text or unified patches.
## Tool inventory
### `apply_patch`
Apply structured patches across one or more files. Use for multi-hunk edits.
Experimental: enable via `tools.exec.applyPatch.enabled` (OpenAI models only).
`tools.exec.applyPatch.workspaceOnly` defaults to `true` (workspace-contained). Set it to `false` only if you intentionally want `apply_patch` to write/delete outside the workspace directory.
### `exec`
Run shell commands in the workspace.
Core parameters:
- `command` (required)
- `yieldMs` (auto-background after timeout, default 10000)
- `background` (immediate background)
- `timeout` (seconds; kills the process if exceeded, default 1800)
- `elevated` (bool; run on host if elevated mode is enabled/allowed; only changes behavior when the agent is sandboxed)
- `host` (`sandbox | gateway | node`)
- `security` (`deny | allowlist | full`)
- `ask` (`off | on-miss | always`)
- `node` (node id/name for `host=node`)
- Need a real TTY? Set `pty: true`.
Notes:
- Returns `status: "running"` with a `sessionId` when backgrounded.
- Use `process` to poll/log/write/kill/clear background sessions.
- If `process` is disallowed, `exec` runs synchronously and ignores `yieldMs`/`background`.
- `elevated` is gated by `tools.elevated` plus any `agents.list[].tools.elevated` override (both must allow) and is an alias for `host=gateway` + `security=full`.
- `elevated` only changes behavior when the agent is sandboxed (otherwise its a no-op).
- `host=node` can target a macOS companion app or a headless node host (`openclaw node run`).
- gateway/node approvals and allowlists: [Exec approvals](/tools/exec-approvals).
### `process`
Manage background exec sessions.
Core actions:
- `list`, `poll`, `log`, `write`, `kill`, `clear`, `remove`
Notes:
- `poll` returns new output and exit status when complete.
- `log` supports line-based `offset`/`limit` (omit `offset` to grab the last N lines).
- `process` is scoped per agent; sessions from other agents are not visible.
### `loop-detection` (tool-call loop guardrails)
OpenClaw tracks recent tool-call history and blocks or warns when it detects repetitive no-progress loops.
Enable with `tools.loopDetection.enabled: true` (default is `false`).
```json5
{
tools: {
loopDetection: {
enabled: true,
warningThreshold: 10,
criticalThreshold: 20,
globalCircuitBreakerThreshold: 30,
historySize: 30,
detectors: {
genericRepeat: true,
knownPollNoProgress: true,
pingPong: true,
},
},
},
}
```
- `genericRepeat`: repeated same tool + same params call pattern.
- `knownPollNoProgress`: repeating poll-like tools with identical outputs.
- `pingPong`: alternating `A/B/A/B` no-progress patterns.
- Per-agent override: `agents.list[].tools.loopDetection`.
### `web_search`
Search the web using Brave, Firecrawl, Gemini, Grok, Kimi, Perplexity, or Tavily.
Core parameters:
- `query` (required)
- `count` (110; default from `tools.web.search.maxResults`)
Notes:
- Requires an API key for the chosen provider (recommended: `openclaw configure --section web`).
- Enable via `tools.web.search.enabled`.
- Responses are cached (default 15 min).
- See [Web tools](/tools/web) for setup.
### `web_fetch`
Fetch and extract readable content from a URL (HTML → markdown/text).
Core parameters:
- `url` (required)
- `extractMode` (`markdown` | `text`)
- `maxChars` (truncate long pages)
Notes:
- Enable via `tools.web.fetch.enabled`.
- `maxChars` is clamped by `tools.web.fetch.maxCharsCap` (default 50000).
- Responses are cached (default 15 min).
- For JS-heavy sites, prefer the browser tool.
- See [Web tools](/tools/web) for setup.
- See [Firecrawl](/tools/firecrawl) for the optional anti-bot fallback.
### `browser`
Control the dedicated OpenClaw-managed browser.
Core actions:
- `status`, `start`, `stop`, `tabs`, `open`, `focus`, `close`
- `snapshot` (aria/ai)
- `screenshot` (returns image block + `MEDIA:<path>`)
- `act` (UI actions: click/type/press/hover/drag/select/fill/resize/wait/evaluate)
- `navigate`, `console`, `pdf`, `upload`, `dialog`
Profile management:
- `profiles` — list all browser profiles with status
- `create-profile` — create new profile with auto-allocated port (or `cdpUrl`)
- `delete-profile` — stop browser, delete user data, remove from config (local only)
- `reset-profile` — kill orphan process on profile's port (local only)
Common parameters:
- `profile` (optional; defaults to `browser.defaultProfile`)
- `target` (`sandbox` | `host` | `node`)
- `node` (optional; picks a specific node id/name)
Notes:
- Requires `browser.enabled=true` (default is `true`; set `false` to disable).
- All actions accept optional `profile` parameter for multi-instance support.
- Omit `profile` for the safe default: isolated OpenClaw-managed browser (`openclaw`).
- Use `profile="user"` for the real local host browser when existing logins/cookies matter and the user is present to click/approve any attach prompt.
- `profile="user"` is host-only; do not combine it with sandbox/node targets.
- When `profile` is omitted, uses `browser.defaultProfile` (defaults to `openclaw`).
- Profile names: lowercase alphanumeric + hyphens only (max 64 chars).
- Port range: 18800-18899 (~100 profiles max).
- Remote profiles are attach-only (no start/stop/reset).
- If a browser-capable node is connected, the tool may auto-route to it (unless you pin `target`).
- `snapshot` defaults to `ai` when Playwright is installed; use `aria` for the accessibility tree.
- `snapshot` also supports role-snapshot options (`interactive`, `compact`, `depth`, `selector`) which return refs like `e12`.
- `act` requires `ref` from `snapshot` (numeric `12` from AI snapshots, or `e12` from role snapshots); use `evaluate` for rare CSS selector needs.
- Avoid `act``wait` by default; use it only in exceptional cases (no reliable UI state to wait on).
- `upload` can optionally pass a `ref` to auto-click after arming.
- `upload` also supports `inputRef` (aria ref) or `element` (CSS selector) to set `<input type="file">` directly.
### `canvas`
Drive the node Canvas (present, eval, snapshot, A2UI).
Core actions:
- `present`, `hide`, `navigate`, `eval`
- `snapshot` (returns image block + `MEDIA:<path>`)
- `a2ui_push`, `a2ui_reset`
Notes:
- Uses gateway `node.invoke` under the hood.
- If no `node` is provided, the tool picks a default (single connected node or local mac node).
- A2UI is v0.8 only (no `createSurface`); the CLI rejects v0.9 JSONL with line errors.
- Quick smoke: `openclaw nodes canvas a2ui push --node <id> --text "Hello from A2UI"`.
### `nodes`
Discover and target paired nodes; send notifications; capture camera/screen.
Core actions:
- `status`, `describe`
- `pending`, `approve`, `reject` (pairing)
- `notify` (macOS `system.notify`)
- `run` (macOS `system.run`)
- `camera_list`, `camera_snap`, `camera_clip`, `screen_record`
- `location_get`, `notifications_list`, `notifications_action`
- `device_status`, `device_info`, `device_permissions`, `device_health`
Notes:
- Camera/screen commands require the node app to be foregrounded.
- Images return image blocks + `MEDIA:<path>`.
- Videos return `FILE:<path>` (mp4).
- Location returns a JSON payload (lat/lon/accuracy/timestamp).
- `run` params: `command` argv array; optional `cwd`, `env` (`KEY=VAL`), `commandTimeoutMs`, `invokeTimeoutMs`, `needsScreenRecording`.
Example (`run`):
```json
{
"action": "run",
"node": "office-mac",
"command": ["echo", "Hello"],
"env": ["FOO=bar"],
"commandTimeoutMs": 12000,
"invokeTimeoutMs": 45000,
"needsScreenRecording": false
}
```
### `image`
Analyze an image with the configured image model.
Core parameters:
- `image` (required path or URL)
- `prompt` (optional; defaults to "Describe the image.")
- `model` (optional override)
- `maxBytesMb` (optional size cap)
Notes:
- Only available when `agents.defaults.imageModel` is configured (primary or fallbacks), or when an implicit image model can be inferred from your default model + configured auth (best-effort pairing).
- Uses the image model directly (independent of the main chat model).
### `image_generate`
Generate one or more images with the configured or inferred image-generation model.
Core parameters:
- `action` (optional: `generate` or `list`; default `generate`)
- `prompt` (required)
- `image` or `images` (optional reference image path/URL for edit mode)
- `model` (optional provider/model override)
- `size` (optional size hint)
- `resolution` (optional `1K|2K|4K` hint)
- `count` (optional, `1-4`, default `1`)
Notes:
- Available when `agents.defaults.imageGenerationModel` is configured, or when OpenClaw can infer a compatible image-generation default from your enabled providers plus available auth.
- Explicit `agents.defaults.imageGenerationModel` still wins over any inferred default.
- Use `action: "list"` to inspect registered providers, default models, supported model ids, sizes, resolutions, and edit support.
- Returns local `MEDIA:<path>` lines so channels can deliver the generated files directly.
- Uses the image-generation model directly (independent of the main chat model).
- Google-backed flows, including `google/gemini-3-pro-image-preview` for the native Nano Banana-style path, support reference-image edits plus explicit `1K|2K|4K` resolution hints.
- When editing and `resolution` is omitted, OpenClaw infers a draft/final resolution from the input image size.
- This is the built-in replacement for the old `nano-banana-pro` skill workflow. Use `agents.defaults.imageGenerationModel`, not `skills.entries`, for stock image generation.
Native example:
```json5
{
agents: {
defaults: {
imageGenerationModel: {
primary: "google/gemini-3-pro-image-preview", // native Nano Banana path
fallbacks: ["fal/fal-ai/flux/dev"],
},
},
},
}
```
### `pdf`
Analyze one or more PDF documents.
For full behavior, limits, config, and examples, see [PDF tool](/tools/pdf).
### `message`
Send messages and channel actions across Discord/Google Chat/Slack/Telegram/WhatsApp/Signal/iMessage/Microsoft Teams.
Core actions:
- `send` (text + optional media; Microsoft Teams also supports `card` for Adaptive Cards)
- `poll` (WhatsApp/Discord/Microsoft Teams polls)
- `react` / `reactions` / `read` / `edit` / `delete`
- `pin` / `unpin` / `list-pins`
- `permissions`
- `thread-create` / `thread-list` / `thread-reply`
- `search`
- `sticker`
- `member-info` / `role-info`
- `emoji-list` / `emoji-upload` / `sticker-upload`
- `role-add` / `role-remove`
- `channel-info` / `channel-list`
- `voice-status`
- `event-list` / `event-create`
- `timeout` / `kick` / `ban`
Notes:
- `send` routes WhatsApp via the Gateway; other channels go direct.
- `poll` uses the Gateway for WhatsApp and Microsoft Teams; Discord polls go direct.
- When a message tool call is bound to an active chat session, sends are constrained to that sessions target to avoid cross-context leaks.
### `cron`
Manage Gateway cron jobs and wakeups.
Core actions:
- `status`, `list`
- `add`, `update`, `remove`, `run`, `runs`
- `wake` (enqueue system event + optional immediate heartbeat)
Notes:
- `add` expects a full cron job object (same schema as `cron.add` RPC).
- `update` uses `{ jobId, patch }` (`id` accepted for compatibility).
### `gateway`
Restart or apply updates to the running Gateway process (in-place).
Core actions:
- `restart` (authorizes + sends `SIGUSR1` for in-process restart; `openclaw gateway` restart in-place)
- `config.schema.lookup` (inspect one config path at a time without loading the full schema into prompt context)
- `config.get`
- `config.apply` (validate + write config + restart + wake)
- `config.patch` (merge partial update + restart + wake)
- `update.run` (run update + restart + wake)
Notes:
- `config.schema.lookup` expects a targeted config path such as `gateway.auth` or `agents.list.*.heartbeat`.
- Paths may include slash-delimited plugin ids when addressing `plugins.entries.<id>`, for example `plugins.entries.pack/one.config`.
- Use `delayMs` (defaults to 2000) to avoid interrupting an in-flight reply.
- `config.schema` remains available to internal Control UI flows and is not exposed through the agent `gateway` tool.
- `restart` is enabled by default; set `commands.restart: false` to disable it.
### `sessions_list` / `sessions_history` / `sessions_send` / `sessions_spawn` / `session_status`
List sessions, inspect transcript history, or send to another session.
Core parameters:
- `sessions_list`: `kinds?`, `limit?`, `activeMinutes?`, `messageLimit?` (0 = none)
- `sessions_history`: `sessionKey` (or `sessionId`), `limit?`, `includeTools?`
- `sessions_send`: `sessionKey` (or `sessionId`), `message`, `timeoutSeconds?` (0 = fire-and-forget)
- `sessions_spawn`: `task`, `label?`, `runtime?`, `agentId?`, `model?`, `thinking?`, `cwd?`, `runTimeoutSeconds?`, `thread?`, `mode?`, `cleanup?`, `sandbox?`, `streamTo?`, `attachments?`, `attachAs?`
- `session_status`: `sessionKey?` (default current; accepts `sessionId`), `model?` (`default` clears override)
Notes:
- `main` is the canonical direct-chat key; global/unknown are hidden.
- `messageLimit > 0` fetches last N messages per session (tool messages filtered).
- Session targeting is controlled by `tools.sessions.visibility` (default `tree`: current session + spawned subagent sessions). If you run a shared agent for multiple users, consider setting `tools.sessions.visibility: "self"` to prevent cross-session browsing.
- `sessions_send` waits for final completion when `timeoutSeconds > 0`.
- Delivery/announce happens after completion and is best-effort; `status: "ok"` confirms the agent run finished, not that the announce was delivered.
- `sessions_spawn` supports `runtime: "subagent" | "acp"` (`subagent` default). For ACP runtime behavior, see [ACP Agents](/tools/acp-agents).
- For ACP runtime, `streamTo: "parent"` routes initial-run progress summaries back to the requester session as system events instead of direct child delivery.
- `sessions_spawn` starts a sub-agent run and posts an announce reply back to the requester chat.
- Supports one-shot mode (`mode: "run"`) and persistent thread-bound mode (`mode: "session"` with `thread: true`).
- If `thread: true` and `mode` is omitted, mode defaults to `session`.
- `mode: "session"` requires `thread: true`.
- If `runTimeoutSeconds` is omitted, OpenClaw uses `agents.defaults.subagents.runTimeoutSeconds` when set; otherwise timeout defaults to `0` (no timeout).
- Discord thread-bound flows depend on `session.threadBindings.*` and `channels.discord.threadBindings.*`.
- Reply format includes `Status`, `Result`, and compact stats.
- `Result` is the assistant completion text; if missing, the latest `toolResult` is used as fallback.
- Manual completion-mode spawns send directly first, with queue fallback and retry on transient failures (`status: "ok"` means run finished, not that announce delivered).
- `sessions_spawn` supports inline file attachments for subagent runtime only (ACP rejects them). Each attachment has `name`, `content`, and optional `encoding` (`utf8` or `base64`) and `mimeType`. Files are materialized into the child workspace at `.openclaw/attachments/<uuid>/` with a `.manifest.json` metadata file. The tool returns a receipt with `count`, `totalBytes`, per file `sha256`, and `relDir`. Attachment content is automatically redacted from transcript persistence.
- Configure limits via `tools.sessions_spawn.attachments` (`enabled`, `maxTotalBytes`, `maxFiles`, `maxFileBytes`, `retainOnSessionKeep`).
- `attachAs.mountPath` is a reserved hint for future mount implementations.
- `sessions_spawn` is non-blocking and returns `status: "accepted"` immediately.
- ACP `streamTo: "parent"` responses may include `streamLogPath` (session-scoped `*.acp-stream.jsonl`) for tailing progress history.
- `sessions_send` runs a replyback pingpong (reply `REPLY_SKIP` to stop; max turns via `session.agentToAgent.maxPingPongTurns`, 05).
- After the pingpong, the target agent runs an **announce step**; reply `ANNOUNCE_SKIP` to suppress the announcement.
- Sandbox clamp: when the current session is sandboxed and `agents.defaults.sandbox.sessionToolsVisibility: "spawned"`, OpenClaw clamps `tools.sessions.visibility` to `tree`.
### `agents_list`
List agent ids that the current session may target with `sessions_spawn`.
Notes:
- Result is restricted to per-agent allowlists (`agents.list[].subagents.allowAgents`).
- When `["*"]` is configured, the tool includes all configured agents and marks `allowAny: true`.
## Parameters (common)
Gateway-backed tools (`canvas`, `nodes`, `cron`):
- `gatewayUrl` (default `ws://127.0.0.1:18789`)
- `gatewayToken` (if auth enabled)
- `timeoutMs`
Note: when `gatewayUrl` is set, include `gatewayToken` explicitly. Tools do not inherit config
or environment credentials for overrides, and missing explicit credentials is an error.
Browser tool:
- `profile` (optional; defaults to `browser.defaultProfile`)
- `target` (`sandbox` | `host` | `node`)
- `node` (optional; pin a specific node id/name)
- Troubleshooting guides:
- Linux startup/CDP issues: [Browser troubleshooting (Linux)](/tools/browser-linux-troubleshooting)
- WSL2 Gateway + Windows remote Chrome CDP: [WSL2 + Windows + remote Chrome CDP troubleshooting](/tools/browser-wsl2-windows-remote-cdp-troubleshooting)
## Recommended agent flows
Browser automation:
1. `browser``status` / `start`
2. `snapshot` (ai or aria)
3. `act` (click/type/press)
4. `screenshot` if you need visual confirmation
Canvas render:
1. `canvas``present`
2. `a2ui_push` (optional)
3. `snapshot`
Node targeting:
1. `nodes``status`
2. `describe` on the chosen node
3. `notify` / `run` / `camera_snap` / `screen_record`
## Safety
- Avoid direct `system.run`; use `nodes``run` only with explicit user consent.
- Respect user consent for camera/screen capture.
- Use `status/describe` to ensure permissions before invoking media commands.
## How tools are presented to the agent
## Built-in tool reference
For the full tool-by-tool reference (parameters, actions, notes), see the
individual tool pages in the sidebar. Key tools:
| Tool | What it does | Page |
| ---------------------------- | -------------------------------------------------------- | --------------------------------- |
| `exec` / `process` | Run shell commands, manage background processes | [Exec](/tools/exec) |
| `browser` | Control a Chromium browser (navigate, click, screenshot) | [Browser](/tools/browser) |
| `web_search` / `web_fetch` | Search the web, fetch page content | [Web](/tools/web) |
| `read` / `write` / `edit` | File I/O in the workspace | |
| `apply_patch` | Multi-hunk file patches | [Apply Patch](/tools/apply-patch) |
| `message` | Send messages across all channels | [Agent Send](/tools/agent-send) |
| `canvas` | Drive node Canvas (present, eval, snapshot) | |
| `nodes` | Discover and target paired devices | |
| `cron` / `gateway` | Manage scheduled jobs, restart gateway | |
| `image` / `image_generate` | Analyze or generate images | |
| `sessions_*` / `agents_list` | Session management, sub-agents | [Sub-agents](/tools/subagents) |
## Plugins add more
Plugins can register **additional tools** beyond the built-in set. Some examples:
- [Lobster](/tools/lobster) — typed workflow runtime with resumable approvals
- [LLM Task](/tools/llm-task) — JSON-only LLM step for structured output
- [Diffs](/tools/diffs) — diff viewer and renderer
- [OpenProse](/prose) — markdown-first workflow orchestration
Plugins can also ship **skills** alongside tools, so the agent gets both the
tool definition and the instructions for using it. See
[Building Plugins](/plugins/building-plugins) to create your own.
## How tools reach the agent
Tools are exposed in two parallel channels:
1. **System prompt text**: a human-readable list + guidance.
2. **Tool schema**: the structured function definitions sent to the model API.
1. **System prompt text** a human-readable list with guidance (from skills)
2. **Tool schemas** structured function definitions sent to the model API
That means the agent sees both “what tools exist” and “how to call them.” If a tool
doesnt appear in the system prompt or the schema, the model cannot call it.
If a tool doesn't appear in either, the model cannot call it.

View File

@@ -1,13 +1,14 @@
---
summary: "OpenClaw plugins/extensions: discovery, config, and safety"
summary: "OpenClaw plugins: install, configure, and manage plugins that extend the gateway"
read_when:
- Adding or modifying plugins/extensions
- Documenting plugin install or load rules
- Installing or configuring plugins
- Understanding plugin discovery and load rules
- Working with Codex/Claude-compatible plugin bundles
title: "Plugins"
sidebarTitle: "Install and Configure"
---
# Plugins (Extensions)
# Plugins
## Quick start
@@ -329,7 +330,7 @@ See [Plugin manifest](/plugins/manifest) for the manifest file format.
- [Plugin architecture and internals](/plugins/architecture) -- capability model,
ownership model, contracts, load pipeline, runtime helpers, and developer API
reference
- [Building extensions](/plugins/building-extensions)
- [Building plugins](/plugins/building-plugins)
- [Plugin bundles](/plugins/bundles)
- [Plugin manifest](/plugins/manifest)
- [Plugin agent tools](/plugins/agent-tools)