diff --git a/docs/plugin.md b/docs/plugin.md index 9b1882f29..e868588ee 100644 --- a/docs/plugin.md +++ b/docs/plugin.md @@ -204,6 +204,82 @@ Notes: - `meta.label` is used for labels in CLI/UI lists. - `meta.aliases` adds alternate ids for normalization and CLI inputs. +### Write a new messaging channel (step‑by‑step) + +Use this when you want a **new chat surface** (a “messaging channel”), not a model provider. +Model provider docs live under `/providers/*`. + +1) Pick an id + config shape +- All channel config lives under `channels.`. +- Prefer `channels..accounts.` for multi‑account setups. + +2) Define the channel metadata +- `meta.label`, `meta.selectionLabel`, `meta.docsPath`, `meta.blurb` control CLI/UI lists. +- `meta.docsPath` should point at a docs page like `/channels/`. + +3) Implement the required adapters +- `config.listAccountIds` + `config.resolveAccount` +- `capabilities` (chat types, media, threads, etc.) +- `outbound.deliveryMode` + `outbound.sendText` (for basic send) + +4) Add optional adapters as needed +- `setup` (wizard), `security` (DM policy), `status` (health/diagnostics) +- `gateway` (start/stop/login), `mentions`, `threading`, `streaming` +- `actions` (message actions), `commands` (native command behavior) + +5) Register the channel in your plugin +- `api.registerChannel({ plugin })` + +Minimal config example: + +```json5 +{ + channels: { + acmechat: { + accounts: { + default: { token: "ACME_TOKEN", enabled: true } + } + } + } +} +``` + +Minimal channel plugin (outbound‑only): + +```ts +const plugin = { + id: "acmechat", + meta: { + id: "acmechat", + label: "AcmeChat", + selectionLabel: "AcmeChat (API)", + docsPath: "/channels/acmechat", + blurb: "AcmeChat messaging channel.", + aliases: ["acme"], + }, + capabilities: { chatTypes: ["direct"] }, + config: { + listAccountIds: (cfg) => Object.keys(cfg.channels?.acmechat?.accounts ?? {}), + resolveAccount: (cfg, accountId) => + (cfg.channels?.acmechat?.accounts?.[accountId ?? "default"] ?? { accountId }), + }, + outbound: { + deliveryMode: "direct", + sendText: async ({ text }) => { + // deliver `text` to your channel here + return { ok: true }; + }, + }, +}; + +export default function (api) { + api.registerChannel({ plugin }); +} +``` + +Load the plugin (extensions dir or `plugins.load.paths`), restart the gateway, +then configure `channels.` in your config. + ### Register a tool ```ts