Skip to content

Channels

A Channel is where the agent communicates with users. Agent One is channel-agnostic — the same logic runs regardless of whether you’re chatting on WhatsApp, Telegram, or the terminal.

type Channel interface {
ID() string
Send(ctx context.Context, to string, msg Message) error
Listen(ctx context.Context, events chan<- Event) error
}

Every channel can both send and receive messages. The Listen method pushes incoming messages as events into the shared queue (where they become Message signals).

Local terminal input/output. Always available, used for development and testing.

channels:
cli:
enabled: true

Go-native WhatsApp Web integration via whatsmeow. No Node.js dependency — pure Go.

channels:
whatsapp:
enabled: true
device_db: "./data/whatsapp.db"
allowed_numbers: [] # empty = allow all

Pairing happens via QR code in the TUI setup wizard. The device session persists in device_db.

Standard Telegram Bot API. Create a bot via BotFather and provide the token.

channels:
telegram:
enabled: true
bot_token: "${TELEGRAM_BOT_TOKEN}"

Supports webhook-first mode for production, with polling fallback for development.

Listens to and responds via ClickUp comments and chat.

channels:
clickup:
enabled: true
api_key: "${CLICKUP_API_KEY}"
listen_spaces: ["my-workspace"]

The agent uses different channels depending on the signal type:

Signal TypeResponse Goes To
MessageThe channel it came from
Cronchannels.default
Heartbeatchannels.default
Webhookchannels.default
channels:
default: whatsapp # Proactive signals go here

Channels use the registry pattern. Adding a new channel requires:

  1. Implement the interface — create a package under internal/channel/:
package slack
type Channel struct { /* config, client */ }
func (c *Channel) ID() string { return "slack" }
func (c *Channel) Send(ctx context.Context, to string, msg signal.Message) error {
// Send message via Slack API
}
func (c *Channel) Listen(ctx context.Context, events chan<- signal.Event) error {
// Listen for incoming Slack messages, push to events
}
  1. Register it — add to the channel registry during startup. No switch statements — the registry handles lookup.

  2. Add config — add the channel’s config fields under channels: in config.yaml.

The agent loop doesn’t know or care which channels exist. It dequeues events from the shared queue and sends responses via whichever channel the event came from (or channels.default for proactive signals).

Agent One supports unified identity across channels. The channel_identities table maps (channel, external_id) to a single user_id. This means the same person chatting on WhatsApp and Telegram sees one continuous conversation with shared memory and persona.

Identity linking methods:

  • OAuth auto-link — web chat sessions automatically link when authenticated
  • Code-based — send /link 123456 from a new channel to associate it
  • Phone match — WhatsApp numbers can auto-match with existing profiles