Adapter Guide
This guide explains how to configure and use adapters in onebots.
Supported Adapters
onebots currently supports the following platform adapters:
| Platform | Status | Package | Description |
|---|---|---|---|
| QQ Official Bot | ✅ Implemented | @onebots/adapter-qq | Supports QQ channels, group chats, private chats |
| ICQQ | ✅ Implemented | @onebots/adapter-icqq | Supports QQ via unofficial protocol with more complete features |
| Kook | ✅ Implemented | @onebots/adapter-kook | Supports channels, private chats, server management |
| ✅ Implemented | @onebots/adapter-wechat | Supports WeChat Official Accounts | |
| WeChat ClawBot (iLink) | ✅ Implemented | @onebots/adapter-wechat-clawbot | WeChat iLink Bot HTTP (QR login, long polling) |
| Discord | ✅ Implemented | @onebots/adapter-discord | Supports Discord bots |
| Telegram | ✅ Implemented | @onebots/adapter-telegram | Supports private chats, groups, channels |
| Feishu | ✅ Implemented | @onebots/adapter-feishu | Supports private chats, group chats, rich text messages |
| DingTalk | ✅ Implemented | @onebots/adapter-dingtalk | Supports enterprise internal apps and custom bots |
| Slack | ✅ Implemented | @onebots/adapter-slack | Supports channel messages, private chats, app commands |
| WeCom | ✅ Implemented | @onebots/adapter-wecom | Supports app message push, contact sync |
| Microsoft Teams | ✅ Implemented | @onebots/adapter-teams | Supports channel messages, private chats, adaptive cards |
| Line | ✅ Implemented | @onebots/adapter-line | Supports Line bot messages and events |
| ✅ Implemented | @onebots/adapter-email | Supports SMTP sending and IMAP receiving | |
| ✅ Implemented | @onebots/adapter-whatsapp | Supports WhatsApp Business API | |
| Zulip | ✅ Implemented | @onebots/adapter-zulip | Supports Zulip streams and private messages |
| Matrix | ✅ Implemented | @onebots/adapter-matrix | Client-Server API, AppService, and manual ingress |
| Google Chat | ✅ Implemented | @onebots/adapter-google-chat | Interaction HTTPS, Workspace Events, and manual ingress |
| Facebook Messenger | ✅ Implemented | @onebots/adapter-facebook-messenger | Messenger Platform, Graph API, webhook, and manual ingress |
| Instagram Messaging | ✅ Implemented | @onebots/adapter-instagram | Instagram Login, Messaging, Graph API, webhook, and manual ingress |
| Mattermost | ✅ Implemented | @onebots/adapter-mattermost | REST API v4, reliable WebSocket, existing sockets, and manual ingress |
| Twitch | ✅ Implemented | @onebots/adapter-twitch | Helix, EventSub WebSocket/Webhook, existing Host/socket, and manual ingress |
| IRCv3 | ✅ Implemented | @onebots/adapter-ircv3 | Modern IRC, CAP/SASL, TCP/TLS, existing sockets, and manual ingress |
Capability manifests
Every adapter exports and registers one runtime capability manifest. It describes actions, events, message segments, and transports, distinguishing native support, emulated projections, and unsupported features. Context-dependent entries also declare their required permissions, availability, and scenes.
Use adapter.describeCapabilities(accountId) for the complete manifest and adapter.getSupportedActions(accountId) for callable actions. OneBots verifies that every advertised action has a concrete adapter implementation, preventing capability metadata from drifting away from runtime behavior.
The versioned manifest is a closed runtime contract rather than a TypeScript-only convention. Adapter registration and construction validate all four categories, support levels, availability, scenes, permissions, message directions, transport modes, and unknown fields, then retain a deeply immutable copy. A third-party JavaScript plugin therefore cannot publish a malformed or subsequently mutated manifest to the management API; a registration failure participates in the plugin transaction rollback.
The management API and Web capability panel now call describeCapabilities(accountId) for each configured account. To avoid repeating large manifests, /api/adapters keeps the adapter default in capabilities and places only object-distinct account overrides in accountCapabilities. Selecting an account in the Web panel explicitly shows either account-specific manifest or uses adapter default. An adapter may vary its manifest using stable token, plan, or permission information, but should not present transient network failures as capability changes.
Explicit event subscriptions are also account capability boundaries. QQ/Discord intents, Telegram allowed_updates, and Zulip event_types are projected into the canonical events that the selected account can actually receive. A webhook, reverse WebSocket, or manual mode that only changes ingress transport does not invent an upstream event filter when OneBots cannot observe one.
In the Web console, both Extensions and Bots → Capability overview show package-versioned catalog snapshots for platforms that are not installed, loaded, or configured with an account yet. Users can compare actions, events, message segments, and transports in the same overview without creating an account or entering credentials. Once an adapter is loaded, the overview gives its authoritative registered manifest precedence. After creating an account, users can switch to that account to inspect overrides caused by its token, permissions, or event subscriptions. A third-party plugin without a runtime manifest is explicitly marked as unknown rather than being hidden behind a catalog snapshot. The overview labels each source as a catalog snapshot or runtime manifest with its plugin version. Summary counts include native and emulated capabilities, while explicitly unsupported entries remain visible; permission, scene, and context restrictions appear on each item. The repository runs pnpm catalog:capabilities:check to keep the published snapshot aligned with every built adapter manifest.
Capability evidence distinguishes verified, unknown, and unavailable. If catalog integrity validation fails, the CLI and Web UI keep the affected platforms visible for diagnosis but do not display or search an unverified snapshot; empty categories cannot be interpreted as proof that a platform lacks those capabilities. unknown is reserved for a loaded plugin that did not declare a manifest, separate from catalog evidence that is unavailable.
The CLI can export each selected adapter's registered default manifest without starting an account:
onebots capabilities
onebots capabilities --json
onebots capabilities --register <adapter-name-or-package>Without an adapter selection, the command displays the complete catalog snapshot shipped with the current OneBots version. --register can temporarily load the authoritative manifest from an installed adapter. It does not connect to a platform or load protocols. JSON includes package names, versions, real entry paths, status, category counts, and complete manifests for selection reviews and CI evidence. Plugin load failures remain in errors and return exit code 2; an adapter without a registered default manifest or with unavailable catalog evidence sets complete to false and returns exit code 1. Account permission and subscription overrides remain available after startup through /api/adapters and the Web capability panel.
Native platform actions
Capabilities outside the common protocol surface are called through adapter.callAction(accountId, action, params). Each adapter package also exports a closed action set, its inferred action union, and a low-level executor. For QQ these are QQ_PLATFORM_ACTIONS, QQPlatformAction, and executeQQPlatformAction(). The set's has() accepts a dynamic string and narrows its type, so integrations do not need to duplicate action names or erase the native client type.
Named actions must declare their complete field allowlist, types, required relationships, and HTTP locations; APIs that combine query parameters with a JSON body model both separately. Only explicitly low-level entries such as call_*_api may carry a platform-native object. Typos, stale fields, and invalid types therefore fail with structured errors before a network request is sent instead of being forwarded silently.
import {
QQ_PLATFORM_ACTIONS,
executeQQPlatformAction,
type QQClient,
} from '@onebots/adapter-qq'
async function callQQ(client: QQClient, action: string, params: Record<string, unknown>) {
if (!QQ_PLATFORM_ACTIONS.has(action)) throw new Error(`Unknown QQ action: ${action}`)
return executeQQPlatformAction(client, action, params)
}The Web Extensions view can browse the complete install catalog. Account and protocol forms use the adapters, protocols, and schemas registered by the active runtime generation. A plugin's registered schema is the single source for runtime validation, form sections, sensitive fields, and dynamic lists; the application does not maintain a second field catalog.
Keep using choices for closed enumerations. When an array should provide common suggestions while accepting ecosystem extension values, use ui.widget: 'choice-list' and explicitly set allowCustomValues: true. In that mode choices drives suggestions without rejecting custom strings. The flag is valid only on an array choice-list; invalid combinations fail during plugin registration.
Adapter names, protocol name-version pairs, and their configuration schema keys are unique within a process. The same factory or schema object may register repeatedly so plugin loading remains idempotent. A different implementation or schema cannot claim an occupied identifier: the registry throws a ValidationError instead of silently changing the implementation, metadata, or validation contract. Unregistering an implementation also removes its schema.
Plugin entries are resolved from the startup working directory with support for exports.import conditions, module, and main, then loaded through native ESM dynamic imports. Module initialization is awaited, so plugins may use top-level await. An initialization rejection is preserved in startup and doctor diagnostics instead of being misreported as a missing module.
A plugin must declare onebots, and @onebots/core when it uses core APIs directly, as peer dependencies supplied from the same installation root that starts the gateway. Before executing plugin code, the loader compares the real resolved package paths. Loading fails with both locations when a dependency manager installed a second copy, or when a global CLI attempts to load a plugin bound to a project-local OneBots installation. Run the project-local onebots command or install the plugin alongside the global CLI. A factory therefore cannot register into a separate static Registry and surface later as a misleading “initialized but did not register” error.
After initialization, the loader verifies the installation plan's plugin contract. An adapter must register the factory and schema named by the plan; a protocol must register the matching factory and <name>.<version> schema. A package that merely exports code, skips registration, or registers the wrong identity fails during installation verification, doctor, and service preflight diagnostics.
Plugin import and contract verification run as one serialized registry transaction. Each transaction may modify only the factory, metadata, and schema promised by its CLI name. Registering another adapter or protocol, or using another package to claim an identity that existed before import, reports the specific conflict and restores every adapter, protocol, schema, and protocol-version metadata entry to the pre-import state. Initialization errors and missing promised entries receive the same full rollback. Repeated loading of the same package and entry remains idempotent; multiple versions of one protocol may still share protocol metadata while registering their own factories and schemas. A failed plugin therefore cannot leave a partial registration or cause a false name conflict in the next plugin. Restart the process after fixing the package so Node.js imports the module again.
Quick Links
- QQ Adapter Documentation
- ICQQ Adapter Documentation
- Kook Adapter Documentation
- WeChat Adapter Documentation
- WeChat ClawBot (iLink)
- Discord Adapter Documentation
- DingTalk Adapter Documentation
- Telegram Adapter Documentation
- Feishu Adapter Documentation
- Slack Adapter Documentation
- WeCom Adapter Documentation
- Microsoft Teams Adapter Documentation
- Line Adapter Documentation
- Email Adapter Documentation
- WhatsApp Adapter Documentation
- Zulip Adapter Documentation
- Matrix Adapter Documentation
- Google Chat Adapter Documentation
- Facebook Messenger Adapter Documentation
- Instagram Messaging Adapter Documentation
- Mattermost Adapter Documentation
- Twitch Adapter Documentation
- IRCv3 Adapter Documentation
Install adapters
Do not run npm install directly in the OneBots runtime directory. The management service resolves the selected adapter together with its protocols, framework extensions and required peers, installs them into a new immutable generation, and verifies the complete runtime before activation. Modifying the active directory bypasses those checks and the recovery boundary.
The simplest path is the Install dependencies page in the Web console. Select platforms, protocols and frameworks, review the complete plan, then confirm it. The interactive terminal uses the same management API:
onebots ui --data-dir <workspace> --setupPrivate registry authorization is scoped to one installation and is never written to config.yaml. Headless deployments can use onebots control plan/install/installation/activate; pass authorization only through standard input with install --auth-stdin. See Quick start and Runtime updates for the complete flow and recovery rules.
Configuration
onebots uses YAML format configuration files, supporting multiple protocols per account.
Configuration Structure
# Global configuration
port: 6727 # HTTP server port
log_level: info # Log level
timeout: 30 # Login timeout (seconds)
# General configuration (protocol default configuration)
general:
onebot.v11: # OneBot V11 protocol general configuration
use_http: true
use_ws: true
access_token: ''
heartbeat_interval: 5000
onebot.v12: # OneBot V12 protocol general configuration
use_http: true
use_ws: true
access_token: ''
heartbeat_interval: 5000
satori.v1: # Satori protocol general configuration
use_http: true
use_ws: true
token: ''
milky.v1: # Milky protocol general configuration
use_http: true
use_ws: true
token: ''
# Account configuration
# Format: {platform}.{account_id}
wechat.my_wechat_mp:
# Protocol configuration
onebot.v11:
use_http: true
use_ws: true
# WeChat platform configuration
app_id: your_app_id
app_secret: your_app_secret
token: your_tokenFor complete configuration examples, see Configuration Guide.