Research: OpenClaw plugin system architecture — discovery, lifecycle, and extension points #195
Labels
No labels
Compat/Breaking
Kind/Bug
Kind/Competitor
Kind/Documentation
Kind/Enhancement
Kind/Epic
Kind/Feature
Kind/Security
Kind/Story
Kind/Testing
Priority
Critical
Priority
High
Priority
Low
Priority
Medium
Reviewed
Confirmed
Reviewed
Duplicate
Reviewed
Invalid
Reviewed
Won't Fix
Scope/Core
Scope/Cross-Plugin
Scope/Plugin-System
Scope/Single-Plugin
Status
Abandoned
Status
Blocked
Status
Need More Info
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
ultanio/cobot#195
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Context
OpenClaw has a mature plugin system that lets extensions register channels, tools, hooks, services, CLI commands, provider auth flows, and auto-reply commands — all in-process with the Gateway. Understanding this architecture is critical for designing cobot's own extensibility model.
This follows the same format as #121 (system prompt architecture).
Plugin System Overview
OpenClaw plugins are TypeScript modules loaded at runtime via jiti. They run in-process with the Gateway (trusted code). Config validation happens via a static JSON manifest — without executing plugin code.
As of 2026.2.26, OpenClaw ships 37 bundled plugins (most disabled by default). 5 are loaded in a typical agent setup (Telegram, Memory, Device Pairing, Phone Control, Talk Voice).
Plugin Manifest (
openclaw.plugin.json)Every plugin must ship a manifest in its root directory:
Required fields:
id(string): canonical plugin idconfigSchema(object): JSON Schema for plugin config (even if empty)Optional fields:
kind(string): plugin kind (e.g.,"memory"for slot-based exclusion)channels(array): channel ids this plugin registersproviders(array): provider ids this plugin registersskills(array): skill directories to load (relative to plugin root)name,description,version: display metadatauiHints(object): config field labels/placeholders/sensitive flags for UIKey design decision: Validation uses the manifest + JSON Schema only, never executes plugin code. This means a broken plugin can't crash config validation.
Plugin Discovery & Precedence
OpenClaw scans these locations in order (first match wins for duplicate ids):
1. Config paths — `plugins.load.paths`
Explicit file or directory paths. Highest precedence.
2. Workspace extensions
3. Global extensions
4. Bundled extensions (shipped with OpenClaw, disabled by default)
Must be explicitly enabled via
plugins.entries.<id>.enabledoropenclaw plugins enable <id>.Security hardening on discovery
openclaw plugins installrunsnpm install --ignore-scripts(no lifecycle scripts)Plugin API — Registration Points
Plugins export either a function
(api) => { ... }or an object{ id, name, configSchema, register(api) { ... } }.The
apiobject provides 8 registration methods:1. `api.registerTool()` — Agent tools
Expose JSON-schema functions to the LLM. Can be required (always available) or optional (opt-in via allowlist).
Optional tools must be enabled via
agents.list[].tools.allow:"my_tool""my-plugin""group:plugins"2. `api.registerChannel()` — Messaging channels
Register a full messaging channel (like Telegram, WhatsApp, etc.). Channel config lives under
channels.<id>.Required adapters:
config.listAccountIds+config.resolveAccountcapabilities(chat types, media, threads)outbound.deliveryMode+outbound.sendTextOptional adapters:
setup,security,status,gateway,mentions,threading,streaming,actions,commandsOnboarding hooks:
configure,configureInteractive,configureWhenConfiguredConcrete example (Telegram plugin):
Channel metadata supports:
meta.aliases— alternate ids for CLI/normalizationmeta.preferOver— auto-enable preference over other channelsmeta.detailLabel/meta.systemImage— rich UI labels/iconsopenclaw.channel+openclaw.installinpackage.json— catalog onboarding metadata3. `api.registerHook()` — Event hooks
Register event-driven automation (e.g., run logic when
/newis invoked).Shows up in
openclaw hooks listwithplugin:<id>prefix. Cannot be toggled independently — enable/disable the plugin instead.4. `api.registerService()` — Background services
Long-running background processes with start/stop lifecycle.
5. `api.registerProvider()` — Model provider auth
Register OAuth/API-key auth flows for model providers.
Powers
openclaw models auth login --provider <id>. Context providesprompter,runtime,openUrl,oauth.createVpsAwareHandlers.6. `api.registerGatewayMethod()` — Gateway RPC
Register custom WebSocket RPC methods on the Gateway.
Convention:
pluginId.actionnaming.7. `api.registerCli()` — CLI commands
Register top-level CLI commands.
8. `api.registerCommand()` — Auto-reply slash commands
Register slash commands that execute without invoking the AI agent — processed before built-in commands.
Options:
acceptsArgs,requireAuth. Reserved command names cannot be overridden.Plugin Configuration
Validation rules (strict):
entries,allow,deny,slots→ errorchannels.<id>keys → error (unless declared by a plugin manifest)Plugin slots — exclusive categories where only one plugin can be active:
Plugin Lifecycle
openclaw.plugin.json, extract JSON Schemaplugins.entries.<id>.configagainst schema (no code execution)register(api)function — registers tools, channels, hooks, etc.start()calledstop()called on gateway shutdownPackage Packs
A plugin directory can contain multiple extensions via
package.json:Each entry becomes a separate plugin. Multi-extension packs get ids like
name/<fileBase>. All entries must stay inside the package directory (symlink escape = rejected).External Channel Catalogs
OpenClaw can merge external plugin catalogs for channel discovery:
Or via
OPENCLAW_PLUGIN_CATALOG_PATHSenv var. Format:{ "entries": [{ "name": "@scope/pkg", "openclaw": { "channel": {...}, "install": {...} } }] }Runtime Helpers
Plugins access core functionality via
api.runtime:CLI Management
Relevance to Cobot
Extensibility model: OpenClaw's 8 registration points cover the full surface area — tools, channels, hooks, services, providers, RPC, CLI, and commands. This is a comprehensive blueprint for cobot's plugin system.
Static validation: Manifest + JSON Schema validation without executing plugin code is a strong safety pattern. Broken plugins can't crash the config layer.
Discovery precedence: Config paths > workspace > global > bundled gives clear override semantics.
Security: Path traversal checks, ownership validation,
--ignore-scriptson npm install, allowlist/denylist — defense in depth for trusted-code plugins.Slot system: Exclusive categories (like memory) prevent conflicting plugins. Clean pattern for cobot's own exclusive-category extensions.
Channel abstraction: The channel plugin interface (config, capabilities, outbound, onboarding) is well-factored and could be adapted for cobot's communication layer.
Package distribution: npm-based distribution with integrity checking is mature and reusable.
Filed by Hermes 🪽 on behalf of k9ert