Channel plugins are full channel adapters that extend xbot with new communication channels (e.g., GenUI display_html). They use the stdio protocol with additional channel-specific messages.
A channel plugin is a stdio plugin that declares a channel_provider in its activate response. xbot creates a ChannelProvider bridge that connects the plugin process to xbot’s channel system.
In the activate response, return a channel_provider:
{
"channel_provider": {
"name": "my-channel",
"config_schema": [
{
"key": "enabled",
"label": "Enable",
"description": "Enable this channel",
"type": "toggle",
"default_value": "true"
}
]
}
}
type ChannelProviderDecl struct {
Name string `json:"name"`
ConfigSchema []map[string]any `json:"config_schema,omitempty"`
// Entry info populated by xbot from the plugin manifest
Entry string `json:"-"`
Executable string `json:"-"`
Args []string `json:"-"`
Dir string `json:"-"`
}
Channel plugins use additional inbound messages beyond the standard stdio protocol:
Declares tools for a specific channel. Sent as an inbound message from the plugin:
{
"method": "channel_tools",
"params": {
"tools": [
{
"name": "display_html",
"description": "Display HTML content",
"input_schema": {
"type": "object",
"properties": {
"code": {"type": "string"}
}
}
}
]
}
}
Tools are registered with RegisterForChannel("channel-name", tool) — only visible when the channel is active.
Declares channel-specific system prompt parts:
{
"method": "channel_prompt",
"params": {
"system_parts": {
"05_channel_myplugin": "You have access to display_html tool..."
}
}
}
Key naming convention: "05_channel_xxx" prefix (after "00_base", before "10_skills").
Declares web UI components for the channel:
{
"method": "web_ui",
"params": {
"widgets": [...]
}
}
Pushes user messages from the channel to xbot:
{
"method": "channel_inbound",
"params": {
"message": "user input from channel"
}
}
ChannelToolBridge wraps channel-declared tools. When the LLM calls a channel tool:
- xbot routes the call to
ChannelToolBridge.Execute - The bridge sends an
execute_toolrequest to the plugin process viaCall("execute_tool") - The plugin processes the request and returns a result
- The bridge wraps the result with
Detail(for UI rendering) andui_code(for web)
LLM calls tool → ChannelToolBridge.Execute
→ Call("execute_tool", {toolName, input})
→ Plugin processes and returns result
→ Bridge wraps result with Detail/ui_code
→ Result returned to LLM
Channel plugins declare config schema in the channel_provider response. Users configure channels in config.json:
{
"channels": {
"my-channel": {
"enabled": "true"
}
}
}
Important: The channel provider’s IsEnabled check requires channels.<name>.enabled=true in config.json. Without this, the channel is never created.
ChannelProviderFactory is registered by serverapp during initialization to create channel provider instances without a plugin → channel import cycle:
type ChannelProviderFactory func(decl *ChannelProviderDecl, process *StdioPluginProcess) (any, error)
After ActivateAll(), WireChannelProviders(pm) connects all active channel providers to the external registry:
func WireChannelProviders(pm *PluginManager) {
// Iterates active plugins
// For each, gets ChannelProviders from context
// Registers each via globalChannelProviderRegistrar
}
The xbot-genui plugin is a real channel plugin example:
{
"id": "xbot.genui",
"name": "GenUI (display_html)",
"version": "1.0.0",
"runtime": "grpc",
"entry": "./bin/genui-plugin",
"activationEvents": ["onStart"],
"permissions": ["channels.register", "tools.register", "ui.contribute"],
"contributes": {
"channelProvider": {
"name": "genui",
"config_schema": [
{
"key": "enabled",
"label": "Enable",
"type": "toggle",
"default_value": "true"
}
]
}
}
}
The plugin process:
- On
activate, returnschannel_providerwith name"genui" - Sends
channel_toolsto declare thedisplay_htmltool - Sends
channel_promptto declare system prompt parts - On
execute_tool, renders HTML and returns the result
- Stdio Protocol — Base JSON-RPC protocol
- Architecture — How channel plugins fit in
- Configuration — Channel configuration
- Built-in Plugins: GenUI — Real channel plugin example