Adding capabilities (contributor guide)
Use this when OpenClaw needs a new shared domain such as embeddings, image generation, video generation, or some future vendor-backed feature area.
The rule:
- plugin = ownership boundary
- capability = shared core contract
Do not start by wiring a vendor directly into a channel or a tool. Start by defining the capability.
When to create a capability
Section titled “When to create a capability”Create a new capability when all of these are true:
- More than one vendor could plausibly implement it.
- Channels, tools, or feature plugins should consume it without caring about the vendor.
- Core needs to own fallback, policy, config, or delivery behavior.
If the work is vendor-only and no shared contract exists yet, stop and define the contract first.
The standard sequence
Section titled “The standard sequence”- Define the typed core contract.
- Add plugin registration for that contract.
- Add a shared runtime helper.
- Wire one real vendor plugin as proof.
- Move feature/channel consumers onto the runtime helper.
- Add contract tests.
- Document the operator-facing config and ownership model.
What goes where
Section titled “What goes where”Core:
- Request/response types.
- Provider registry + resolution.
- Fallback behavior.
- Config schema with propagated
title/descriptiondocs 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.
- Registration of the capability implementation.
Feature/channel plugin:
- Calls
api.runtime.*or the matchingplugin-sdk/*-runtimehelper. - Never calls a vendor implementation directly.
Provider and harness seams
Section titled “Provider and harness seams”Use provider hooks when the behavior belongs to the model provider contract rather than the generic agent loop. Examples include provider-specific request params after transport selection, auth-profile preference, prompt overlays, and follow-up fallback routing after model/profile failover.
Use agent harness hooks when the behavior belongs to the runtime that is executing a turn. Harnesses can classify successful-but-unusable attempt results such as empty, reasoning-only, or planning-only responses so the outer model fallback policy can make the retry decision.
Keep both seams narrow:
- Core owns the retry/fallback policy.
- Provider plugins own provider-specific request/auth/routing hints.
- Harness plugins own runtime-specific attempt classification.
- Third-party plugins return hints, not direct mutations of core state.
File checklist
Section titled “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
Section titled “Worked example: image generation”Image generation follows the standard shape:
- Core defines
ImageGenerationProvider. - Core exposes
registerImageGenerationProvider(...). - Core exposes
runtime.imageGeneration.generate(...). - The
openai,google,fal, andminimaxplugins register vendor-backed implementations. - Future vendors register the same contract without changing channels/tools.
The config key is intentionally separate from vision-analysis routing:
agents.defaults.imageModelanalyzes images.agents.defaults.imageGenerationModelgenerates images.
Keep those separate so fallback and policy remain explicit.
Embedding providers
Section titled “Embedding providers”Use 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.
For memory-engine-specific adapters, keep using memoryEmbeddingProviders.
Those adapters own memory indexing details such as query/document split,
runtime metadata, and local memory engine setup. Do not make a generic
embedding provider depend on memory-owned modules unless the provider is only
usable by memory.
Review checklist
Section titled “Review checklist”Before shipping a new capability, verify:
- No channel/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/config key.
- Plugin docs explain the ownership boundary.
If a PR skips the capability layer and hardcodes vendor behavior into a channel/tool, send it back and define the contract first.
Related
Section titled “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.