Adding a new capability
When a plugin needs behavior that does not fit the current API, do not bypass the plugin system with a private reach-in. Add the missing capability. Recommended sequence:- Define the core contract. Decide what shared behavior core should own: policy, fallback, config merge, lifecycle, channel-facing semantics, and runtime helper shape.
- Add typed plugin registration/runtime surfaces. Extend
OpenClawPluginApiand/orapi.runtimewith the smallest useful typed capability surface. - Wire core + channel/feature consumers. Channels and feature plugins should consume the new capability through core, not by importing a vendor implementation directly.
- Register vendor implementations. Vendor plugins then register their backends against the capability.
- Add contract coverage. Add tests so ownership and registration shape stay explicit over time.
Capability checklist
When you add a new capability, the implementation should usually touch these surfaces together:- core contract types in
src/<capability>/types.ts - core runner/runtime helper in
src/<capability>/runtime.ts - plugin API registration surface in
src/plugins/types.ts - plugin registry wiring in
src/plugins/registry.ts - plugin runtime exposure in
src/plugins/runtime/*when feature/channel plugins need to consume it - capture/test helpers in
src/test-utils/plugin-registration.ts - ownership/contract assertions in
src/plugins/contracts/registry.ts - operator/plugin docs in
docs/
Capability template
Minimal pattern:src/plugins/contracts/registry.ts exposes ownership
lookups such as providerContractPluginIds; tests assert a plugin’s
contracts.videoGenerationProviders list matches what it actually registers):
- core owns the capability contract + orchestration
- vendor plugins own vendor implementations
- feature/channel plugins consume runtime helpers
- contract tests keep ownership explicit