OpenClaw Plugins: Extend Agents Without Forking Core
The fastest way to ruin an agent platform is to put every custom integration directly into core. It feels efficient for the first week. Then the first customer asks for a private tool, the second team wants a different model provider, and the third workflow needs a channel that nobody else uses. Suddenly every upgrade is a merge conflict and every operator-specific idea becomes a platform risk.
OpenClaw's plugin system exists to keep that from happening. A plugin can add channels, model providers, speech providers, image generation, web search, agent tools, custom commands, hooks, HTTP routes, Gateway methods, CLI subcommands, services, memory adapters, and other runtime behavior through the SDK registration API. The point is the typed boundary: OpenClaw can discover, validate, test, disable, and upgrade around it.
That is a revenue feature, not just a developer convenience. If I need an agent to check subscription events, triage support tickets, summarize sales calls, or talk to a niche internal system, I want a small package with a manifest, a narrow entry point, a test surface, and a clean uninstall path.
Start with the boundary, not the code
The first design question is simple: what should this plugin own? The OpenClaw docs split the capability model clearly. A channel plugin owns account resolution, setup, security policy, pairing, outbound delivery, and threading for a messaging platform. Core still owns the shared message tool, prompt wiring, session bookkeeping, and dispatch. A provider plugin owns model auth, catalog resolution, and provider runtime behavior. A tool or hook plugin owns smaller operator behaviors without pretending to be a whole channel or model backend.
That boundary keeps the agent sane. A revenue plugin should not patch the session store because it wants a dashboard metric. A channel plugin should not invent its own duplicate send tool when core already routes outbound messaging through the shared message tool. A provider plugin should not smuggle secrets through prompts when provider auth and manifest metadata already exist. Good plugin design starts by choosing the smallest capability that matches the job.
For related boundaries, read the MCP guide and the hooks guide. Plugins are the native extension lane; MCP is for external tools without owning runtime integration.
Every native plugin needs a manifest
The native manifest is openclaw.plugin.json, and the docs are blunt about it: every native OpenClaw plugin must ship one in the plugin root. OpenClaw reads this file before loading plugin code. Missing or invalid manifests are plugin errors and block config validation.
The manifest is for cheap, static facts: plugin identity, config validation, auth and onboarding metadata, UI hints, static capability ownership snapshots, and fields like channels, providers, cliBackends, skills, and contracts when the plugin owns those surfaces. Runtime behavior belongs in plugin code. Entry files and install metadata belong in package.json.
The boring-looking configSchema is not optional. Even a plugin with no config needs a JSON Schema, and an empty strict object schema is acceptable. Schemas are validated at config read and write time, not after the Gateway is already halfway through loading a broken runtime.
Why this matters in operations
Config validation is where plugin discipline pays off. The manifest docs say unknown channels.* keys are errors unless the channel id is declared by a plugin manifest. plugins.entries.<id>, plugins.allow, plugins.deny, and plugins.slots.* must reference discoverable plugin ids. If a plugin is installed but has a broken or missing manifest or schema, validation fails and Doctor reports the plugin error. If plugin config exists but the plugin is disabled, OpenClaw keeps the config and surfaces a warning.
That behavior is exactly what operators need. You can remove a plugin, disable it, or investigate an auth problem without guessing whether the runtime silently swallowed the mistake. The manifest gives OpenClaw enough information to say, “this id is unknown,” “this config shape is wrong,” or “this disabled plugin still has config.”
If you are turning OpenClaw into a real operator, not a demo bot, the extension boundary matters. Get ClawKit for the full operating guide.
Use focused SDK imports
The SDK overview gives one import rule that is worth treating as law: import from specific openclaw/plugin-sdk/<subpath> paths. Use openclaw/plugin-sdk/plugin-entry for definePluginEntry. Use openclaw/plugin-sdk/core for defineChannelPluginEntry, defineSetupPluginEntry, and shared channel helpers. Use runtime, provider, channel, auth, and testing subpaths only for the surface you actually need.
The reason is practical. Narrow subpaths keep startup fast and help avoid circular dependency problems. The docs also warn against importing your own plugin through an SDK path from production code. Inside a plugin, use local modules such as api.ts, runtime-api.ts, index.ts, and setup-entry.ts. In-repo lint rules reject monolithic root imports, direct src/ imports, and SDK self-imports.
A small tool plugin is enough for many revenue workflows
Not every integration needs to be a channel or provider. If the agent only needs a typed action, register a tool. The docs describe tools as typed functions the LLM can call. They can be required, or optional with { optional: true }. Use optional tools for side effects or extra binary requirements, then let the operator opt in through tools.allow.
A tool like this should still be boringly strict. Give it a clear name, a narrow parameter schema, and a result format the agent can understand. Do not let a “quick internal tool” become a magic backdoor. If it sends messages, touches billing, changes data, or invokes outside systems, make it optional and document how the operator enables it.
The getting-started docs add two guardrails I like: tool names must not clash with core tools, and users can enable all tools from a plugin by adding the plugin id to tools.allow. That gives you a clean adoption path. Start with one optional tool, test it, then let a team opt into the plugin when they trust the whole bundle.
Channels need a setup lane
Channel plugins are heavier because they sit on the boundary between OpenClaw and people. The channel guide says a channel plugin owns config, security, pairing, outbound messaging, and threading. The setup docs show the package metadata for a channel plugin: openclaw.extensions, optional setupEntry, and an openclaw.channel block with id, label, blurb, and optional setup metadata.
Use defineChannelPluginEntry for the full channel entry and defineSetupPluginEntry for the lightweight setup file. The entrypoint docs explain the split: defineChannelPluginEntry automatically registers the channel and gates registerFull on registration mode. defineSetupPluginEntry returns just the plugin for setup-only loading, with no runtime or CLI wiring.
That split prevents setup flows from dragging in heavy runtime dependencies. The setup docs say the lightweight entry is used when a channel is disabled but needs setup surfaces, enabled but unconfigured, or when deferred loading is enabled. Setup entries should include the channel plugin object and required startup setup surfaces, not background services, heavy SDK imports, or CLI registrations.
Respect registration mode
The entrypoint docs define three registration modes: full, setup-only, and setup-runtime. Full startup registers everything. Setup-only registers channel setup surfaces. Setup-runtime gives setup plus lightweight runtime. If you use defineChannelPluginEntry, the helper handles the split for you. If you register a channel directly inside definePluginEntry, check api.registrationMode yourself and return before heavy runtime registrations when the mode is not full.
This is where many homemade extensions get flaky. They work on the developer machine, then fail during onboarding because the setup path imports a huge client library or assumes a token exists. A plugin that respects registration mode can show setup status, inspect accounts without exposing secrets, and let the Gateway start cleanly before heavy runtime code is needed.
Use runtime helpers instead of host internals
The runtime helper docs describe api.runtime as the injected interface for core helpers. A plugin can resolve agent directories and workspace paths, inspect identity defaults, use session-store helpers, run managed subagents, call TTS, use media understanding, and access other runtime namespaces through that object. The design is intentional: use the injected runtime, not private imports from OpenClaw internals.
That keeps plugins portable. If an operator installs your package from ClawHub or npm, the plugin should not depend on a private file path in the OpenClaw repository. The docs also note that model overrides for plugin-run subagents require explicit operator opt-in through plugin config. That is the right default: untrusted plugins can ask for work, but they should not silently pick arbitrary model overrides.
Provider plugins should expose auth without booting runtime
Provider plugins follow the same pattern. The provider guide shows a manifest with providers, providerAuthEnvVars, and providerAuthChoices. That lets OpenClaw detect credentials and present auth choices before the provider runtime is loaded. The provider entry then registers a provider with id, label, docs path, env vars, auth methods, and a catalog.
For operators, this makes model providers manageable. The manifest can say which environment variable proves credentials exist. The runtime can resolve the catalog only when an API key is available. Users can select model refs like acme-ai/acme-large after the provider is installed and configured. No fork, prompt-level secret handling, or mystery local patch.
Test the contract, not just the happy path
The plugin testing docs describe focused helpers for target resolution, channel feedback, plugin API mocks, runtime contracts, provider HTTP mocks, fixtures, and more. They also show ordinary Vitest patterns for channel account resolution, provider model resolution, and runtime-store mocking. For bundled plugins, contract tests verify which plugins register which providers, which speech providers they own, registration shape correctness, and runtime compliance.
If you are building inside the OpenClaw repository, run the scoped plugin tests and pnpm check. If you are publishing externally, keep the same discipline even when the repo-specific lint rules do not apply. Test account inspection without materializing secrets. Test target resolution failures. Test provider catalogs with and without keys. Test that disabled or unconfigured setup paths do not import half the internet.
Publish as a package, not as a patch
The setup docs say external plugins can be published to ClawHub or npm, then installed with openclaw plugins install <package-name>. OpenClaw tries ClawHub first and falls back to npm. You can also force a source with clawhub: or npm:. In-repo plugins live under extensions/ and are discovered during build.
One install detail matters: for npm-sourced installs, the setup docs say openclaw plugins install runs npm install --ignore-scripts. Keep dependency trees pure JavaScript or TypeScript unless you document native build steps and package-manager allowlists.
The operator checklist
- Choose the smallest capability: tool, hook, provider, channel, service, or setup helper.
- Create
package.jsonwith the correctopenclawmetadata. - Add
openclaw.plugin.jsonwith a stable id and strictconfigSchema. - Use focused SDK subpath imports and local barrels for plugin internals.
- Use
definePluginEntryfor non-channel plugins anddefineChannelPluginEntryfor channels. - Keep setup-only code lightweight, and respect
api.registrationMode. - Use
api.runtimehelpers instead of private OpenClaw internals. - Mark risky tools optional and require explicit
tools.allow. - Test setup, auth-missing, disabled, and contract paths before publishing.
- Publish to ClawHub or npm so users install the plugin instead of carrying your fork.
Forking core is sometimes necessary for platform work. It should not be the default answer for customer integrations, private tools, revenue automations, or provider experiments. The plugin SDK gives you a better lane: static discovery through the manifest, typed registration through entrypoints, setup-aware loading, runtime helpers, and tests that prove the contract.
That is how you keep an agent business upgradeable. Put platform changes in the platform. Put operator-specific extension work in plugins.
Want the complete guide? Get ClawKit — $9.99
Originally published at https://www.openclawplaybook.ai/blog/openclaw-plugins-extend-agents-without-forking/
Get The OpenClaw Playbook → https://www.openclawplaybook.ai?utm_source=devto&utm_medium=article&utm_campaign=parasite-seo
Top comments (0)