--- summary: "Cookbook for adding a new shared capability to OpenClaw" read_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 title: "Capability Cookbook" --- # Capability Cookbook Use this when OpenClaw needs a new domain such as image generation, video generation, or some future vendor-backed feature area. The rule: - plugin = ownership boundary - capability = shared core contract That means you should not start by wiring a vendor directly into a channel or a tool. Start by defining the capability. ## When to create a capability Create a new capability when all of these are true: 1. more than one vendor could plausibly implement it 2. channels, tools, or feature plugins should consume it without caring about the vendor 3. 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 1. Define the typed core contract. 2. Add plugin registration for that contract. 3. Add a shared runtime helper. 4. Wire one real vendor plugin as proof. 5. Move feature/channel consumers onto the runtime helper. 6. Add contract tests. 7. Document the operator-facing config and ownership model. ## What goes where Core: - request/response types - provider registry + resolution - fallback behavior - config schema and labels/help - 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 matching `plugin-sdk/*-runtime` helper - never calls a vendor implementation directly ## File checklist For a new capability, expect to touch these areas: - `src//types.ts` - `src//...registry/runtime.ts` - `src/plugins/types.ts` - `src/plugins/registry.ts` - `src/plugins/captured-registration.ts` - `src/plugins/contracts/registry.ts` - `src/plugins/runtime/types-core.ts` - `src/plugins/runtime/index.ts` - `src/plugin-sdk/.ts` - `src/plugin-sdk/-runtime.ts` - one or more `extensions//...` - config/docs/tests ## Example: image generation Image generation follows the standard shape: 1. core defines `ImageGenerationProvider` 2. core exposes `registerImageGenerationProvider(...)` 3. core exposes `runtime.imageGeneration.generate(...)` 4. the `openai` and `google` plugins register vendor-backed implementations 5. future vendors can register the same contract without changing channels/tools The config key is separate from vision-analysis routing: - `agents.defaults.imageModel` = analyze images - `agents.defaults.imageGenerationModel` = generate images Keep those separate so fallback and policy remain explicit. ## 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.