Channels overview

How the outside world reaches an app: the channels available today, how a connector is claimed by an agent, and which older channel types you shouldn't build new work on.

The Spikefrost Team30 Jul 20263 min read

A channel is how something outside your app starts work inside it. Some carry conversations, some carry events, and the difference determines what you should build.

What's available

Channel Carries Status
Browser chat A conversation with a visitor or signed-in user Current path for web chat
Slack, Teams, WhatsApp Messages, mentions, threads Live, handled natively
Transactional email Outbound mail from app code Live — sending only
Queues Durable async work Live
Webhooks HTTP POSTs from other systems A route in your app
Routines Scheduled calls to your own endpoints Live

Two honest gaps, because building around them will waste your time:

  • Inbound email is not available. Your app can send; it cannot receive. Don't write handlers for mail arriving at an app address.
  • The embedded chat widget is a legacy path. It still serves the apps already using it, but new browser chat belongs in your own page — see below.

Connectors and claims

A connector is one configured channel instance, identified by an alias, owned by exactly one agent. One owner is deliberate: with two, nothing decides who answers.

The reverse is fine and common — one agent owning several connectors. A support agent that answers the website chat, the Slack channel, and eventually more is a single agent with a single set of rules.

For messengers, the connector is created once via OAuth in the console, and your app's code claims it by alias:

# agent-config/connectors.yaml
claims:
  acme_slack_bot: SupportAgent
  acme_teams: { agent: SupportAgent }

The manifest only references the alias; credentials never enter your source. Claims can't be stolen — if another app holds one, it releases first.

sf connectors list             # this app's connectors
sf connectors show <alias>     # install snippet, URLs, current owner

Choosing the right shape

Not everything should be a conversation.

Use a conversational channel when a human is on the other end and the exchange benefits from context — support, sales questions, an internal assistant. Browser chat and messengers.

Use a queue when another system hands you work to process reliably. At-least-once delivery, retries, a dead-letter queue. Most integrations are this, not chat.

Use a plain HTTP route when another system pushes you an event. A webhook is a POST handler in your app — verify the signature, do the work, return 2xx fast. If the work is slow, put it on a queue and return immediately.

Use email for one-way outbound facts: receipts, codes, alerts, digests.

Use a schedule when the trigger is time rather than an event. Agent judgment goes in agent schedules; deterministic jobs go in a routine.

A rule of thumb that saves rework: if there's no human in the loop, it probably isn't a conversation. A queue consumer that calls domain functions is cheaper, faster, and more predictable than a model turn — reach for an agent when the work needs judgment.

Where the trust boundary sits

Everything on this page is untrusted input arriving from outside. The pattern is the same in each case:

  1. Authenticate at the edge — verify the signature, the token, or the session in your route, before anything else runs.
  2. Establish identity there, not later. An agent reads the user from this.identity, never from what a message claims.
  3. Enforce rules in domain code, so they hold no matter which channel the request came in on.

That third point is why the agent pages insist that tools be adapters over domain functions. Add a second channel and you'll be glad the rules didn't live in the first one's handler.

Next

Frequently asked questions

What's the difference between a channel and a connector?

A channel is the medium — chat, Slack, email, a queue. A connector is one configured instance of it, owned by exactly one agent. 'Slack' is a channel; 'acme_support_bot' is a connector.

Can two agents share one connector?

No. A connector has exactly one owner, because otherwise nothing decides who answers. Several connectors pointing at the same agent is normal and often what you want.

How does an agent get connected to Slack?

Create the connector once through OAuth in the console, then claim its alias for an agent class in agent-config/connectors.yaml and deploy. The manifest only references the alias.

Can my app receive email?

Not yet. Sending transactional email from app code is fully supported; inbound email to an app or agent is not available — don't build handlers expecting it.

Should I use the embedded chat widget?

Not for new apps. The current path for browser chat is a page in your own app talking to the agent directly, which gives you real authentication and full control of the UI.