Skip to main content

Channel adapters

A channel adapter connects WednesdayAI to a messaging platform. A channel is a plugin that exposes a ChannelPlugin object — a composition of small adapter interfaces, each owning one concern (auth, messaging, outbound delivery, status, setup, onboarding, and more). You implement only the adapters your platform needs; the rest are optional.
ChannelPlugin is not a flat object with login / logout / send / handleEvent methods. Those names are not part of the contract. The real model is a set of named adapter slots, each typed by its own interface and re-exported from openclaw/plugin-sdk.

The ChannelPlugin shape

ChannelPlugin<ResolvedAccount, Probe, Audit> is generic. ResolvedAccount is the per-account type your config adapter resolves; Probe and Audit are channel-specific status types.

Adapter slots

Each adapter type is imported from openclaw/plugin-sdk. Implement an adapter in its own file (src/auth.ts, src/messaging.ts, etc.) and compose them in the plugin object.

Registering the channel

A channel plugin is registered from the plugin’s register function via api.registerChannel(...):

Repo layout

Channel plugins live under extensions/ as pnpm workspace packages:

package.json requirements

Rules:
  • Plugin id, directory name, and npm package name must match exactly.
  • Bundled extensions carry no openclaw peer or dev dependency (ADR 0005) — fork-base compatibility is expressed by our SemVer version and the forkBase marker in dist/build-info.json, not an openclaw range.
  • Third-party installable plugins put openclaw in devDependencies targeting our published SemVer, with "openclaw": "*" in peerDependencies — see the Plugin SDK installation pattern. Never put openclaw in dependencies; the gateway provides the SDK at runtime.
  • No workspace:* in dependencies.
The package.json "openclaw" key carries the id used for workspace discovery. A separate openclaw.plugin.json manifest (with id and configSchema) is still required at the plugin root for config validation. See the manifest reference.

Account model

The ResolvedAccount type parameter is the per-account record your config adapter resolves from configuration. For channels that store credentials, keep them under ~/.openclaw/credentials/<channel>/ and use the SDK credential and config helpers rather than writing files directly.

Testing a channel adapter

Test each adapter in isolation. Mock the platform client; do not make live API calls in unit tests.
Live integration tests (require credentials) run under a dedicated live script:

Docs and PR checklist for a new channel

When adding a channel, update every surface that lists channels (onboarding/overview docs, control UI, mobile/macOS app where applicable) and add matching status and configuration forms.
  • ChannelPlugin composes the adapters the platform needs (config, meta, capabilities at minimum)
  • Registered via api.registerChannel(...)
  • Package name @wednesdayai/<channel>; id matches directory name
  • No openclaw peer pin (bundled extensions carry none — ADR 0005); no workspace:* in dependencies
  • openclaw.plugin.json present with id + configSchema
  • Unit tests pass: pnpm test:fast
  • Channel doc added under docs/channels/ and indexed
  • CHANGELOG.md updated; dev log at docs/logs/YYYY-MM-DD-<name>-channel.md

What’s next