docs: rewrite sdk-migration and bundles, fold agent-tools into building-plugins, remove cookbook from nav, remove dead WeChat listing

This commit is contained in:
Vincent Koc 2026-03-20 11:32:11 -07:00
parent 2e0b445b46
commit 483926a6fb
6 changed files with 247 additions and 433 deletions

View File

@ -68,6 +68,14 @@
"source": "/plugins/building-extensions",
"destination": "/plugins/building-plugins"
},
{
"source": "/plugins/agent-tools",
"destination": "/plugins/building-plugins#registering-agent-tools"
},
{
"source": "/tools/capability-cookbook",
"destination": "/plugins/architecture"
},
{
"source": "/brave-search",
"destination": "/tools/brave-search"
@ -1033,10 +1041,8 @@
"plugins/community",
"plugins/bundles",
"plugins/manifest",
"plugins/agent-tools",
"plugins/sdk-migration",
"plugins/architecture",
"tools/capability-cookbook"
"plugins/architecture"
]
},
{

View File

@ -1,103 +1,10 @@
---
summary: "Register custom agent tools in a plugin with schemas, optional opt-in, and allowlists"
summary: "Redirects to Building Plugins (registering tools section)"
read_when:
- You want to add a new agent tool in a plugin
- You need to make a tool opt-in via allowlists
title: "Registering Tools in Plugins"
sidebarTitle: "Registering Tools"
- Legacy link to agent-tools
title: "Registering Tools"
---
# Registering Tools in Plugins
Plugins can register **agent tools** — typed functions that the LLM can call
during agent runs. Tools can be **required** (always available) or
**optional** (users opt in via allowlists).
See [Building Plugins](/plugins/building-plugins) for the full plugin creation
guide. This page focuses on the tool registration API.
Agent tools are configured under `tools` in the main config, or peragent under
`agents.list[].tools`. The allowlist/denylist policy controls which tools the agent
can call.
## Basic tool
```ts
import { Type } from "@sinclair/typebox";
export default function (api) {
api.registerTool({
name: "my_tool",
description: "Do a thing",
parameters: Type.Object({
input: Type.String(),
}),
async execute(_id, params) {
return { content: [{ type: "text", text: params.input }] };
},
});
}
```
## Optional tool (opt-in)
Optional tools are **never** autoenabled. Users must add them to an agent
allowlist.
```ts
export default function (api) {
api.registerTool(
{
name: "workflow_tool",
description: "Run a local workflow",
parameters: {
type: "object",
properties: {
pipeline: { type: "string" },
},
required: ["pipeline"],
},
async execute(_id, params) {
return { content: [{ type: "text", text: params.pipeline }] };
},
},
{ optional: true },
);
}
```
Enable optional tools in `agents.list[].tools.allow` (or global `tools.allow`):
```json5
{
agents: {
list: [
{
id: "main",
tools: {
allow: [
"workflow_tool", // specific tool name
"workflow", // plugin id (enables all tools from that plugin)
"group:plugins", // all plugin tools
],
},
},
],
},
}
```
Other config knobs that affect tool availability:
- Allowlists that only name plugin tools are treated as plugin opt-ins; core tools remain
enabled unless you also include core tools or groups in the allowlist.
- `tools.profile` / `agents.list[].tools.profile` (base allowlist)
- `tools.byProvider` / `agents.list[].tools.byProvider` (providerspecific allow/deny)
- `tools.sandbox.tools.*` (sandbox tool policy when sandboxed)
## Rules + tips
- Tool names must **not** clash with core tool names; conflicting tools are skipped.
- Plugin ids used in allowlists must not clash with core tool names.
- Prefer `optional: true` for tools that trigger side effects or require extra
binaries/credentials.
This page has moved. See [Building Plugins: Registering agent tools](/plugins/building-plugins#registering-agent-tools).

View File

@ -285,6 +285,58 @@ my-plugin/
</Step>
</Steps>
## Registering agent tools
Plugins can register **agent tools** — typed functions the LLM can call. Tools
can be required (always available) or optional (users opt in via allowlists).
```typescript
import { Type } from "@sinclair/typebox";
export default definePluginEntry({
id: "my-plugin",
name: "My Plugin",
register(api) {
// Required tool (always available)
api.registerTool({
name: "my_tool",
description: "Do a thing",
parameters: Type.Object({ input: Type.String() }),
async execute(_id, params) {
return { content: [{ type: "text", text: params.input }] };
},
});
// Optional tool (user must add to allowlist)
api.registerTool(
{
name: "workflow_tool",
description: "Run a workflow",
parameters: Type.Object({ pipeline: Type.String() }),
async execute(_id, params) {
return { content: [{ type: "text", text: params.pipeline }] };
},
},
{ optional: true },
);
},
});
```
Enable optional tools in config:
```json5
{
tools: { allow: ["workflow_tool"] },
}
```
Tips:
- Tool names must not clash with core tool names (conflicts are skipped)
- Use `optional: true` for tools that trigger side effects or require extra binaries
- Users can enable all tools from a plugin by adding the plugin id to `tools.allow`
## Lint enforcement (in-repo plugins)
Three scripts enforce SDK boundaries for plugins in the OpenClaw repository:

View File

@ -1,307 +1,181 @@
---
summary: "Unified bundle format guide for Codex, Claude, and Cursor bundles in OpenClaw"
summary: "Install and use Codex, Claude, and Cursor bundles as OpenClaw plugins"
read_when:
- You want to install or debug a Codex, Claude, or Cursor-compatible bundle
- You want to install a Codex, Claude, or Cursor-compatible bundle
- You need to understand how OpenClaw maps bundle content into native features
- You are documenting bundle compatibility or current support limits
- You are debugging bundle detection or missing capabilities
title: "Plugin Bundles"
---
# Plugin bundles
# Plugin Bundles
OpenClaw supports one shared class of external plugin package: **bundle
plugins**.
OpenClaw can install plugins from three external ecosystems: **Codex**, **Claude**,
and **Cursor**. These are called **bundles** — content and metadata packs that
OpenClaw maps into native features like skills, hooks, and MCP tools.
Today that means three closely related ecosystems:
<Info>
Bundles are **not** the same as native OpenClaw plugins. Native plugins run
in-process and can register any capability. Bundles are content packs with
selective feature mapping and a narrower trust boundary.
</Info>
- Codex bundles
- Claude bundles
- Cursor bundles
## Why bundles exist
OpenClaw shows all of them as `Format: bundle` in `openclaw plugins list`.
Verbose output and `openclaw plugins inspect <id>` also show the subtype
(`codex`, `claude`, or `cursor`).
Many useful plugins are published in Codex, Claude, or Cursor format. Instead
of requiring authors to rewrite them as native OpenClaw plugins, OpenClaw
detects these formats and maps their supported content into the native feature
set. This means you can install a Claude command pack or a Codex skill bundle
and use it immediately.
Related:
## Install a bundle
- Plugin system overview: [Plugins](/tools/plugin)
- CLI install/list flows: [plugins](/cli/plugins)
- Native manifest schema: [Plugin manifest](/plugins/manifest)
<Steps>
<Step title="Install from a directory, archive, or marketplace">
```bash
# Local directory
openclaw plugins install ./my-bundle
## What a bundle is
# Archive
openclaw plugins install ./my-bundle.tgz
A bundle is a **content/metadata pack**, not a native in-process OpenClaw
plugin.
# Claude marketplace
openclaw plugins marketplace list <marketplace-name>
openclaw plugins install <plugin-name>@<marketplace-name>
```
Today, OpenClaw does **not** execute bundle runtime code in-process. Instead,
it detects known bundle files, reads the metadata, and maps supported bundle
content into native OpenClaw surfaces such as skills, hook packs, MCP config,
and embedded Pi settings.
</Step>
That is the main trust boundary:
<Step title="Verify detection">
```bash
openclaw plugins list
openclaw plugins inspect <id>
```
- native OpenClaw plugin: runtime module executes in-process
- bundle: metadata/content pack, with selective feature mapping
Bundles show as `Format: bundle` with a subtype of `codex`, `claude`, or `cursor`.
## Shared bundle model
</Step>
Codex, Claude, and Cursor bundles are similar enough that OpenClaw treats them
as one normalized model.
<Step title="Restart and use">
```bash
openclaw gateway restart
```
Shared idea:
Mapped features (skills, hooks, MCP tools) are available in the next session.
- a small manifest file, or a default directory layout
- one or more content roots such as `skills/` or `commands/`
- optional tool/runtime metadata such as MCP, hooks, agents, or LSP
- install as a directory or archive, then enable in the normal plugin list
</Step>
</Steps>
Common OpenClaw behavior:
## What OpenClaw maps from bundles
- detect the bundle subtype
- normalize it into one internal bundle record
- map supported parts into native OpenClaw features
- report unsupported parts as detected-but-not-wired capabilities
In practice, most users do not need to think about the vendor-specific format
first. The more useful question is: which bundle surfaces does OpenClaw map
today?
## Detection order
OpenClaw prefers native OpenClaw plugin/package layouts before bundle handling.
Practical effect:
- `openclaw.plugin.json` wins over bundle detection
- package installs with valid `package.json` + `openclaw.extensions` use the
native install path
- if a directory contains both native and bundle metadata, OpenClaw treats it
as native first
That avoids partially installing a dual-format package as a bundle and then
loading it later as a native plugin.
## What works today
OpenClaw normalizes bundle metadata into one internal bundle record, then maps
supported surfaces into existing native behavior.
Not every bundle feature runs in OpenClaw today. Here is what works and what
is detected but not yet wired.
### Supported now
#### Skill content
- bundle skill roots load as normal OpenClaw skill roots
- Claude `commands` roots are treated as additional skill roots
- Cursor `.cursor/commands` roots are treated as additional skill roots
This means Claude markdown command files work through the normal OpenClaw skill
loader. Cursor command markdown works through the same path.
#### Hook packs
- bundle hook roots work **only** when they use the normal OpenClaw hook-pack
layout. Today this is primarily the Codex-compatible case:
- `HOOK.md`
- `handler.ts` or `handler.js`
#### MCP for Pi
- enabled bundles can contribute MCP server config
- OpenClaw merges bundle MCP config into the effective embedded Pi settings as
`mcpServers`
- OpenClaw also exposes supported bundle MCP tools during embedded Pi agent
turns by launching supported stdio MCP servers as subprocesses
- project-local Pi settings still apply after bundle defaults, so workspace
settings can override bundle MCP entries when needed
#### Embedded Pi settings
- Claude `settings.json` is imported as default embedded Pi settings when the
bundle is enabled
- OpenClaw sanitizes shell override keys before applying them
Sanitized keys:
- `shellPath`
- `shellCommandPrefix`
| Feature | How it maps | Applies to |
| ------------- | ---------------------------------------------------------------------------------------------------- | -------------- |
| Skill content | Bundle skill roots load as normal OpenClaw skills | All formats |
| Commands | `commands/` and `.cursor/commands/` treated as skill roots | Claude, Cursor |
| Hook packs | OpenClaw-style `HOOK.md` + `handler.ts` layouts | Codex |
| MCP tools | Bundle MCP config merged into embedded Pi settings; supported stdio servers launched as subprocesses | All formats |
| Settings | Claude `settings.json` imported as embedded Pi defaults | Claude |
### Detected but not executed
These surfaces are detected, shown in bundle capabilities, and may appear in
diagnostics/info output, but OpenClaw does not run them yet:
These are recognized and shown in diagnostics, but OpenClaw does not run them:
- Claude `agents`
- Claude `hooks.json` automation
- Claude `lspServers`
- Claude `outputStyles`
- Cursor `.cursor/agents`
- Cursor `.cursor/hooks.json`
- Cursor `.cursor/rules`
- Claude `agents`, `hooks.json` automation, `lspServers`, `outputStyles`
- Cursor `.cursor/agents`, `.cursor/hooks.json`, `.cursor/rules`
- Codex inline/app metadata beyond capability reporting
## Capability reporting
## Bundle formats
`openclaw plugins inspect <id>` shows bundle capabilities from the normalized
bundle record.
<AccordionGroup>
<Accordion title="Codex bundles">
Markers: `.codex-plugin/plugin.json`
Supported capabilities are loaded quietly. Unsupported capabilities produce a
warning such as:
Optional content: `skills/`, `hooks/`, `.mcp.json`, `.app.json`
```text
bundle capability detected but not wired into OpenClaw yet: agents
```
Codex bundles fit OpenClaw best when they use skill roots and OpenClaw-style
hook-pack directories (`HOOK.md` + `handler.ts`).
Current exceptions:
</Accordion>
- Claude `commands` is considered supported because it maps to skills
- Claude `settings` is considered supported because it maps to embedded Pi settings
- Cursor `commands` is considered supported because it maps to skills
- bundle MCP is considered supported because it maps into embedded Pi settings
and exposes supported stdio tools to embedded Pi
- Codex `hooks` is considered supported only for OpenClaw hook-pack layouts
<Accordion title="Claude bundles">
Two detection modes:
## Format differences
- **Manifest-based:** `.claude-plugin/plugin.json`
- **Manifestless:** default Claude layout (`skills/`, `commands/`, `agents/`, `hooks/`, `.mcp.json`, `settings.json`)
The formats are close, but not byte-for-byte identical. These are the practical
differences that matter in OpenClaw.
Claude-specific behavior:
### Codex
- `commands/` is treated as skill content
- `settings.json` is imported into embedded Pi settings (shell override keys are sanitized)
- `.mcp.json` exposes supported stdio tools to embedded Pi
- `hooks/hooks.json` is detected but not executed
- Custom component paths in the manifest are additive (they extend defaults, not replace them)
Typical markers:
</Accordion>
- `.codex-plugin/plugin.json`
- optional `skills/`
- optional `hooks/`
- optional `.mcp.json`
- optional `.app.json`
<Accordion title="Cursor bundles">
Markers: `.cursor-plugin/plugin.json`
Codex bundles fit OpenClaw best when they use skill roots and OpenClaw-style
hook-pack directories.
Optional content: `skills/`, `.cursor/commands/`, `.cursor/agents/`, `.cursor/rules/`, `.cursor/hooks.json`, `.mcp.json`
### Claude
- `.cursor/commands/` is treated as skill content
- `.cursor/rules/`, `.cursor/agents/`, and `.cursor/hooks.json` are detect-only
OpenClaw supports both:
</Accordion>
</AccordionGroup>
- manifest-based Claude bundles: `.claude-plugin/plugin.json`
- manifestless Claude bundles that use the default Claude layout
## Detection precedence
Default Claude layout markers OpenClaw recognizes:
OpenClaw checks for native plugin format first:
- `skills/`
- `commands/`
- `agents/`
- `hooks/hooks.json`
- `.mcp.json`
- `.lsp.json`
- `settings.json`
1. `openclaw.plugin.json` or valid `package.json` with `openclaw.extensions` — treated as **native plugin**
2. Bundle markers (`.codex-plugin/`, `.claude-plugin/`, or default Claude/Cursor layout) — treated as **bundle**
Claude-specific notes:
If a directory contains both, OpenClaw uses the native path. This prevents
dual-format packages from being partially installed as bundles.
- `commands/` is treated like skill content
- `settings.json` is imported into embedded Pi settings
- `.mcp.json` and manifest `mcpServers` can expose supported stdio tools to
embedded Pi
- `hooks/hooks.json` is detected, but not executed as Claude automation
## Security
### Cursor
Bundles have a narrower trust boundary than native plugins:
Typical markers:
- OpenClaw does **not** load arbitrary bundle runtime modules in-process
- Skills and hook-pack paths must stay inside the plugin root (boundary-checked)
- Settings files are read with the same boundary checks
- Supported stdio MCP servers may be launched as subprocesses
- `.cursor-plugin/plugin.json`
- optional `skills/`
- optional `.cursor/commands/`
- optional `.cursor/agents/`
- optional `.cursor/rules/`
- optional `.cursor/hooks.json`
- optional `.mcp.json`
Cursor-specific notes:
- `.cursor/commands/` is treated like skill content
- `.cursor/rules/`, `.cursor/agents/`, and `.cursor/hooks.json` are
detect-only today
## Claude custom paths
Claude bundle manifests can declare custom component paths. OpenClaw treats
those paths as **additive**, not replacing defaults.
Currently recognized custom path keys:
- `skills`
- `commands`
- `agents`
- `hooks`
- `mcpServers`
- `lspServers`
- `outputStyles`
Examples:
- default `commands/` plus manifest `commands: "extra-commands"` =>
OpenClaw scans both
- default `skills/` plus manifest `skills: ["team-skills"]` =>
OpenClaw scans both
## Security model
Bundle support is intentionally narrower than native plugin support.
Current behavior:
- bundle discovery reads files inside the plugin root with boundary checks
- skills and hook-pack paths must stay inside the plugin root
- bundle settings files are read with the same boundary checks
- supported stdio bundle MCP servers may be launched as subprocesses for
embedded Pi tool calls
- OpenClaw does not load arbitrary bundle runtime modules in-process
This makes bundle support safer by default than native plugin modules, but you
should still treat third-party bundles as trusted content for the features they
do expose.
## Install examples
```bash
openclaw plugins install ./my-codex-bundle
openclaw plugins install ./my-claude-bundle
openclaw plugins install ./my-cursor-bundle
openclaw plugins install ./my-bundle.tgz
openclaw plugins marketplace list <marketplace-name>
openclaw plugins install <plugin-name>@<marketplace-name>
openclaw plugins inspect my-bundle
```
If the directory is a native OpenClaw plugin/package, the native install path
still wins.
For Claude marketplace names, OpenClaw reads the local Claude known-marketplace
registry at `~/.claude/plugins/known_marketplaces.json`. Marketplace entries
can resolve to bundle-compatible directories/archives or to native plugin
sources; after resolution, the normal install rules still apply.
This makes bundles safer by default, but you should still treat third-party
bundles as trusted content for the features they do expose.
## Troubleshooting
### Bundle is detected but capabilities do not run
<AccordionGroup>
<Accordion title="Bundle is detected but capabilities do not run">
Run `openclaw plugins inspect <id>`. If a capability is listed but marked as
not wired, that is a product limit — not a broken install.
</Accordion>
Check `openclaw plugins inspect <id>`.
<Accordion title="Claude command files do not appear">
Make sure the bundle is enabled and the markdown files are inside a detected
`commands/` or `skills/` root.
</Accordion>
If the capability is listed but OpenClaw says it is not wired yet, that is a
real product limit, not a broken install.
<Accordion title="Claude settings do not apply">
Only embedded Pi settings from `settings.json` are supported. OpenClaw does
not treat bundle settings as raw config patches.
</Accordion>
### Claude command files do not appear
<Accordion title="Claude hooks do not execute">
`hooks/hooks.json` is detect-only. If you need runnable hooks, use the
OpenClaw hook-pack layout or ship a native plugin.
</Accordion>
</AccordionGroup>
Make sure the bundle is enabled and the markdown files are inside a detected
`commands` root or `skills` root.
## Related
### Claude settings do not apply
Current support is limited to embedded Pi settings from `settings.json`.
OpenClaw does not treat bundle settings as raw OpenClaw config patches.
### Claude hooks do not execute
`hooks/hooks.json` is only detected today.
If you need runnable bundle hooks today, use the normal OpenClaw hook-pack
layout through a supported Codex hook root or ship a native OpenClaw plugin.
- [Install and Configure Plugins](/tools/plugin)
- [Building Plugins](/plugins/building-plugins) — create a native plugin
- [Plugin Manifest](/plugins/manifest) — native manifest schema

View File

@ -45,17 +45,6 @@ openclaw plugins install <npm-spec>
</Accordion>
<Accordion title="WeChat — Personal accounts via WeChatPadPro (iPad protocol)">
Supports text, image, and file exchange with keyword-triggered conversations.
- **npm:** `@icesword760/openclaw-wechat`
- **repo:** [github.com/icesword0760/openclaw-wechat](https://github.com/icesword0760/openclaw-wechat)
```bash
openclaw plugins install @icesword760/openclaw-wechat
```
</Accordion>
</AccordionGroup>
## Submit your plugin

View File

@ -1,41 +1,52 @@
---
title: "Plugin SDK Migration"
sidebarTitle: "SDK Migration"
summary: "Migrate from legacy compat surfaces to focused plugin-sdk subpaths and injected runtime helpers"
summary: "Migrate from the legacy backwards-compatibility layer to the modern plugin SDK"
read_when:
- You see the OPENCLAW_PLUGIN_SDK_COMPAT_DEPRECATED warning
- You see the OPENCLAW_EXTENSION_API_DEPRECATED warning
- You are updating a plugin from the monolithic plugin-sdk import to scoped subpaths
- You are updating a plugin away from openclaw/extension-api
- You are updating a plugin to the modern plugin architecture
- You maintain an external OpenClaw plugin
---
# Plugin SDK Migration
OpenClaw is migrating from broad compatibility surfaces to narrower, documented
contracts:
OpenClaw has moved from a broad backwards-compatibility layer to a modern plugin
architecture with focused, documented imports. If your plugin was built before
the new architecture, this guide helps you migrate.
- `openclaw/plugin-sdk/compat` -> focused `openclaw/plugin-sdk/<subpath>` imports
- `openclaw/extension-api` -> injected runtime helpers such as `api.runtime.agent.*`
## What is changing
This page explains what changed, why, and how to migrate.
The old plugin system provided two wide-open surfaces that let plugins import
anything they needed from a single entry point:
<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>
- **`openclaw/plugin-sdk/compat`** — a single import that re-exported dozens of
helpers. It was introduced to keep older hook-based plugins working while the
new plugin architecture was being built.
- **`openclaw/extension-api`** — a bridge that gave plugins direct access to
host-side helpers like the embedded agent runner.
Both surfaces are now **deprecated**. They still work at runtime, but new
plugins must not use them, and existing plugins should migrate before the next
major release removes them.
<Warning>
The backwards-compatibility layer will be removed in a future major release.
Plugins that still import from these surfaces will break when that happens.
</Warning>
## Why this changed
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.
The old approach caused problems:
Focused subpaths fix all three: each subpath is a small, self-contained module
with a clear purpose.
- **Slow startup** — importing one helper loaded dozens of unrelated modules
- **Circular dependencies** — broad re-exports made it easy to create import cycles
- **Unclear API surface** — no way to tell which exports were stable vs internal
## Migration steps
The modern plugin SDK fixes this: each import path (`openclaw/plugin-sdk/\<subpath\>`)
is a small, self-contained module with a clear purpose and documented contract.
## How to migrate
<Steps>
<Step title="Find deprecated imports">
@ -43,91 +54,66 @@ with a clear purpose.
```bash
grep -r "plugin-sdk/compat" my-plugin/
grep -r "openclaw/extension-api" extensions/my-plugin/
grep -r "openclaw/extension-api" my-plugin/
```
</Step>
<Step title="Replace with focused subpaths or runtime injection">
Each export from compat maps to a specific subpath. Replace the import
source:
<Step title="Replace with focused imports">
Each export from the old surface maps to a specific modern import path:
```typescript
// Before (compat entry)
// Before (deprecated backwards-compatibility layer)
import {
createChannelReplyPipeline,
createPluginRuntimeStore,
resolveControlCommandGate,
} from "openclaw/plugin-sdk/compat";
// After (focused subpaths)
// After (modern focused imports)
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";
```
If your plugin imports from `openclaw/extension-api`, you will now see:
```text
[OPENCLAW_EXTENSION_API_DEPRECATED] Warning: openclaw/extension-api is deprecated.
Migrate to api.runtime.agent.* or focused openclaw/plugin-sdk/<subpath> imports.
```
That bridge also still works at runtime today. It exists to preserve older
plugins while they migrate to the injected plugin runtime.
Move host-side helpers onto the injected plugin runtime instead of
importing them directly:
For host-side helpers, use the injected plugin runtime instead of importing
directly:
```typescript
// Before (deprecated extension-api bridge)
import { runEmbeddedPiAgent } from "openclaw/extension-api";
const result = await runEmbeddedPiAgent({ sessionId, prompt });
const result = await runEmbeddedPiAgent({
sessionId,
sessionFile,
workspaceDir,
prompt,
timeoutMs,
});
// After (preferred injected runtime)
const result = await api.runtime.agent.runEmbeddedPiAgent({
sessionId,
sessionFile,
workspaceDir,
prompt,
timeoutMs,
});
// After (injected runtime)
const result = await api.runtime.agent.runEmbeddedPiAgent({ sessionId, prompt });
```
The same pattern applies to the other legacy `extension-api` helpers:
The same pattern applies to other legacy bridge helpers:
- `resolveAgentDir` -> `api.runtime.agent.resolveAgentDir`
- `resolveAgentWorkspaceDir` -> `api.runtime.agent.resolveAgentWorkspaceDir`
- `resolveAgentIdentity` -> `api.runtime.agent.resolveAgentIdentity`
- `resolveThinkingDefault` -> `api.runtime.agent.resolveThinkingDefault`
- `resolveAgentTimeoutMs` -> `api.runtime.agent.resolveAgentTimeoutMs`
- `ensureAgentWorkspace` -> `api.runtime.agent.ensureAgentWorkspace`
- session store helpers -> `api.runtime.agent.session.*`
See the [subpath reference](#subpath-reference) below for the scoped import
mapping.
| Old import | Modern equivalent |
| --- | --- |
| `resolveAgentDir` | `api.runtime.agent.resolveAgentDir` |
| `resolveAgentWorkspaceDir` | `api.runtime.agent.resolveAgentWorkspaceDir` |
| `resolveAgentIdentity` | `api.runtime.agent.resolveAgentIdentity` |
| `resolveThinkingDefault` | `api.runtime.agent.resolveThinkingDefault` |
| `resolveAgentTimeoutMs` | `api.runtime.agent.resolveAgentTimeoutMs` |
| `ensureAgentWorkspace` | `api.runtime.agent.ensureAgentWorkspace` |
| session store helpers | `api.runtime.agent.session.*` |
</Step>
<Step title="Build and test">
```bash
pnpm build
pnpm test -- extensions/my-plugin/
pnpm test -- my-plugin/
```
</Step>
</Steps>
## Subpath reference
## Import path reference
<Accordion title="Full subpath table">
| Subpath | Purpose | Key exports |
<Accordion title="Full import path table">
| Import path | Purpose | Key exports |
| --- | --- | --- |
| `plugin-sdk/core` | Plugin entry definitions, base types | `defineChannelPluginEntry`, `definePluginEntry` |
| `plugin-sdk/channel-setup` | Setup wizard adapters | `createOptionalChannelSetupSurface` |
@ -151,22 +137,22 @@ with a clear purpose.
| `plugin-sdk/testing` | Test utilities | Test helpers and mocks |
</Accordion>
Use the narrowest subpath that matches the job. If you cannot find an export,
Use the narrowest import that matches the job. If you cannot find an export,
check the source at `src/plugin-sdk/` or ask in Discord.
## Removal timeline
| When | What happens |
| --- | --- |
| **Now** | Compat import and `openclaw/extension-api` emit runtime warnings |
| **Next major release** | These legacy bridges may be removed; plugins still using them will fail |
| When | What happens |
| ---------------------- | ----------------------------------------------------------------------- |
| **Now** | Deprecated surfaces emit runtime warnings |
| **Next major release** | Deprecated surfaces will be removed; plugins still using them will fail |
All core plugins have already been migrated. External plugins should migrate
before the next major release.
## Suppressing the warning temporarily
## Suppressing the warnings temporarily
Set this environment variable while you work on migrating:
Set these environment variables while you work on migrating:
```bash
OPENCLAW_SUPPRESS_PLUGIN_SDK_COMPAT_WARNING=1 openclaw gateway run
@ -178,5 +164,5 @@ This is a temporary escape hatch, not a permanent solution.
## Related
- [Building Plugins](/plugins/building-plugins)
- [Plugin Architecture](/plugins/architecture)
- [Plugin Internals](/plugins/architecture)
- [Plugin Manifest](/plugins/manifest)