Adding Capabilities to OpenClaw: Contributor Guide
Learn when and how to add a new shared capability to the OpenClaw plugin system. This guide is for core contributors, covering the standard sequence and key principles.
Read this when
- Adding a new core capability and plugin registration surface
- Deciding whether code belongs in core, a vendor plugin, or a feature plugin
- Wiring a new runtime helper for channels or tools
Note
This guide is aimed at contributors working on OpenClaw's core. For external plugin development, refer to Building plugins. A deeper look at the architecture, covering the capability model, ownership, loading, and runtime helpers, is in Plugin internals.
Turn to this when OpenClaw requires a fresh shared domain, for instance embeddings, image generation, video generation, or another vendor-backed feature area down the road.
The guiding principle:
- plugin = where ownership ends
- capability = the shared contract at the core
Avoid hooking a vendor straight into a channel or tool. Lay down the capability first.
When to create a capability
Only introduce a new capability when every condition below holds:
- At least two vendors could realistically offer an implementation.
- Channels, tools, or feature plugins should use it without knowing the vendor.
- Core must handle fallback, policy, configuration, or delivery.
If the task is vendor-only and no shared contract exists yet, write the contract before anything else.
The standard sequence
- Define the typed contract at the core.
- Set up plugin registration for that contract.
- Provide a shared runtime helper.
- Connect one actual vendor plugin to prove the approach.
- Shift feature and channel consumers onto the runtime helper.
- Add contract tests.
- Document the operator-facing config and ownership model.
What goes where
| Layer | Owns |
|---|---|
| Core | Request and response types; provider registry and resolution; fallback behavior; config schema with propagated title/description docs metadata on nested object, wildcard, array-item, and composition nodes; runtime helper surface. |
| Vendor plugin | Vendor API calls, vendor auth handling, vendor-specific request normalization, and registration of the capability implementation. |
| Feature/channel plugin | Calls api.runtime.* or the matching plugin-sdk/*-runtime helper. Never calls a vendor implementation directly. |
Provider and harness seams
Choose provider hooks when the behavior belongs to the model provider contract rather than the generic agent loop. Cases include provider-specific request params after transport selection, auth-profile preference, prompt overlays, and follow-up fallback routing after model or profile failover.
Choose agent harness hooks when the behavior belongs to the runtime executing a turn. Harnesses can classify explicit protocol outcomes such as empty output, reasoning without visible output, or a structured plan without a final answer so the outer model fallback policy can decide on retries.
Keep both seams narrow:
- Core owns the retry and fallback policy.
- Provider plugins own provider-specific request, auth, and routing hints.
- Harness plugins own runtime-specific attempt classification.
- Third-party plugins return hints, not direct mutations of core state.
File checklist
For a new capability, expect to touch these areas:
src/<capability>/types.tssrc/<capability>/...registry/runtime.tssrc/plugins/types.tssrc/plugins/registry.tssrc/plugins/captured-registration.tssrc/plugins/contracts/registry.tssrc/plugins/runtime/types-core.tssrc/plugins/runtime/index.tssrc/plugin-sdk/<capability>.tssrc/plugin-sdk/<capability>-runtime.ts- One or more bundled plugin packages.
- Config, docs, tests.
Worked example: image generation
Image generation follows the standard shape:
- Core defines
ImageGenerationProvider. - Core exposes
registerImageGenerationProvider(...). - Core exposes
api.runtime.imageGeneration.generate(...)and.listProviders(...). - Vendor plugins (
comfy,deepinfra,fal,google,litellm,microsoft-foundry,minimax,openai,openrouter,vydra,xai) register vendor-backed implementations. - Future vendors register the same contract without changing channels or tools.
The config key is intentionally separate from vision-analysis routing:
agents.defaults.imageModelanalyzes images.agents.defaults.mediaModels.imagegenerates images.
Keep those separate so fallback and policy remain explicit.
Embedding providers
Use registerEmbeddingProvider(...) / contract embeddingProviders for
reusable vector embedding providers. This contract is intentionally broader
than memory: tools, search, retrieval, importers, or future feature plugins
can consume embeddings without depending on the memory engine. Memory search
also consumes generic embeddingProviders.
The older memory-specific registration API and memoryEmbeddingProviders
contract were removed after their August 2026 migration window. Use
registerEmbeddingProvider and embeddingProviders for every embedding
provider.
Review checklist
Before shipping a new capability, verify:
- No channel or tool imports vendor code directly.
- The runtime helper is the shared path.
- At least one contract test asserts bundled ownership.
- Config docs name the new model or config key.
- Plugin docs explain the ownership boundary.
If a PR skips the capability layer and hardcodes vendor behavior into a channel or tool, send it back and define the contract first.
Related
- Plugin internals, capability model, ownership, load pipeline, runtime helpers.
- Building plugins, first-plugin tutorial.
- SDK overview, import map and registration API reference.
- Creating skills, companion contributor surface.