Building Extensions
This guide walks through creating an OpenClaw extension from scratch. Extensions can add channels, model providers, tools, or other capabilities.Prerequisites
- OpenClaw repository cloned and dependencies installed (
pnpm install) - Familiarity with TypeScript (ESM)
Extension structure
Every extension lives underextensions/<name>/ and follows this layout:
Step 1: Create the package
Createextensions/my-channel/package.json:
openclaw field tells the plugin system what your extension provides.
For provider plugins, use providers instead of channel.
Step 2: Define the entry point
Createextensions/my-channel/index.ts:
definePluginEntry instead.
Step 3: Import from focused subpaths
The plugin SDK exposes 70+ focused subpaths. Always import from specific subpaths rather than the monolithic root:| Subpath | Purpose |
|---|---|
plugin-sdk/core | Plugin entry definitions, base types |
plugin-sdk/channel-runtime | Channel runtime helpers |
plugin-sdk/channel-config-schema | Config schema builders |
plugin-sdk/channel-policy | Group/DM policy helpers |
plugin-sdk/setup | Setup wizard adapters |
plugin-sdk/runtime-store | Persistent plugin storage |
plugin-sdk/allow-from | Allowlist resolution |
plugin-sdk/reply-payload | Message reply types |
plugin-sdk/testing | Test utilities |
Step 4: Use local barrels for internal imports
Within your extension, create barrel files for internal code sharing instead of importing through the plugin SDK:./api.ts or ./runtime-api.ts instead. The SDK contract is for
external consumers only.
Step 5: Add a plugin manifest
Createopenclaw.plugin.json in your extension root:
Step 6: Test with contract tests
OpenClaw runs contract tests against all registered plugins. After adding your extension, run:Lint enforcement
Three scripts enforce SDK boundaries:- No monolithic root imports —
openclaw/plugin-sdkroot is rejected - No direct src/ imports — extensions cannot import
../../src/directly - No self-imports — extensions cannot import their own
plugin-sdk/<name>subpath
pnpm check to verify all boundaries before committing.
Checklist
Before submitting your extension:-
package.jsonhas correctopenclawmetadata - Entry point uses
defineChannelPluginEntryordefinePluginEntry - All imports use focused
plugin-sdk/<subpath>paths - Internal imports use local barrels, not SDK self-imports
-
openclaw.plugin.jsonmanifest is present and valid - Contract tests pass (
pnpm test:contracts) - Unit tests colocated as
*.test.ts -
pnpm checkpasses (lint + format) - Doc page created under
docs/channels/ordocs/plugins/