There's a default assumption baked into how most teams build their first agent: it lives in a web chat widget. You build the widget, you style it, you ship it, and you consider the interface problem solved.
It isn't solved. It's barely started.
The people who need your agent are not sitting on your website waiting to open a chat widget. They're in Slack, coordinating with their team. They're on WhatsApp, because that's how they communicate with everyone in their life, work included. They're checking email between meetings. They're on a phone call because typing isn't an option while driving. The web widget is one door into your agent. For most real usage, it's not even the most-used door.
An agent that only lives in a single interface is an agent that's opted out of most of the moments where it could actually be useful. This issue is about building agent access as a genuinely multi-channel system — how the architecture works, what's hard about it, and why the investment matters more than it initially looks like it should.
Why Channel Breadth Isn't a Nice-to-Have
The instinct to treat multi-channel support as a later-stage feature — "we'll add WhatsApp and Slack once the core agent is solid" — misunderstands what channels actually are. They're not additional surface area for a finished product. They're the difference between an agent that fits into how people actually work and one that requires people to change their behavior to use it.
Consider what each channel is actually optimized for, from the user's side:
Slack and Teams are where work coordination already happens. A user getting a notification that an invoice needs approval, right inside the channel where they're already discussing the vendor relationship, is a fundamentally lower-friction experience than getting an email that pulls them out of their workflow into a different tool.
WhatsApp and SMS are where billions of people communicate by default, particularly outside north america and western europe, and particularly for anyone who isn't primarily a desk worker. A field technician, a delivery driver, a small business owner — for a huge population of potential agent users, "open a web app" is a meaningfully higher-friction ask than "reply to a text."
Voice is the only option in genuinely hands-busy, eyes-busy contexts — driving, cooking, physical work. An agent that can only be reached through a screen has quietly excluded every scenario where a screen isn't available.
Email remains the highest-reach, lowest-friction channel for anything that doesn't need to be synchronous. Not everyone has Slack. Not everyone will install a new app. Everyone has email, and everyone already knows how to reply to one.
The pattern across all of this: each channel isn't just a different technical integration. It's a different context of use, with different latency expectations, different formatting capabilities, and a different relationship between the user and the moment they're reaching out. An agent that only supports one channel is implicitly deciding which contexts of use it's willing to serve — usually without anyone on the team making that decision deliberately.
The Architecture: One Agent Core, Many Doors In
The naive approach to multi-channel support is building the agent logic separately for each channel — a Slack bot here, a WhatsApp integration there, each with its own conversation handling, its own state management, its own version of the agent's reasoning. This duplicates enormous amounts of work and guarantees the channels drift apart in behavior over time as each one gets patched independently.
The right architecture separates the agent's reasoning from the channel it's being accessed through entirely. There are four distinct layers:
Channel adapters are the only layer that knows anything about the specifics of a given channel. Each adapter's job is narrow: receive the inbound message in whatever format that channel delivers it, extract the user's identity and the channel-specific session identifier, verify the request is authentic (webhook signature validation, API token checks), and normalize the message into a single internal schema that looks identical regardless of whether it arrived via WhatsApp, Slack, or a web widget. The adapter for a new channel is new code. Nothing else in the system needs to change when you add one.
The unified conversation core is channel-agnostic by design. This is where the actual agent lives — the orchestration, the tool calls, the memory, the reasoning loop covered in earlier issues. It receives a normalized message, resolves it to a canonical conversation, loads the relevant history and state, runs the agent, and produces a response. Crucially, this layer has no knowledge of Slack Block Kit or WhatsApp template message rules or SSML for voice synthesis. It doesn't need to. It just needs to know what happened and what should happen next.
The response renderer does the inverse of the adapter: takes the agent's channel-agnostic response and translates it into the native rich format of whatever channel the conversation is happening in. The same underlying response — "your invoice for $4,200 needs approval" with an approve/reject decision point — becomes an interactive Slack Block Kit message with buttons in Slack, a WhatsApp message with numbered reply options, an SSML-formatted spoken prompt on a voice channel, and a rich card with buttons in the web widget. One response object, many renderings.
Identity resolution is the layer that makes cross-channel continuity actually work, and it's the hardest of the four to get right.
The Identity Problem
Here's the scenario that breaks naive multi-channel implementations: a user starts a conversation with your agent on WhatsApp, asking about a return. They get busy, don't finish the conversation. Two days later, they email support about the same issue. From the user's perspective, this is one ongoing interaction with one company. From a naively built system's perspective, these are two completely unrelated conversations with two unrelated users, because the WhatsApp phone number and the email address have no connection to each other in the system.
Solving this requires a canonical identity layer that sits above all the channel-specific identifiers. Every channel has its own native identity concept — a phone number for WhatsApp and SMS, a Slack user ID scoped to a specific workspace, an email address, a web session token, a Teams user ID scoped to a tenant. None of these natively know about each other.
The canonical identity layer maps all of these channel-specific identifiers to a single underlying identity, wherever that mapping can be established — through account login, through a verification flow, through matching on a known field like email or phone number provided during onboarding. Once that mapping exists, a conversation started on one channel can be recognized and continued on another, with the full context of memory, conversation history, and agent state intact.
This isn't always fully solvable. A user who has never authenticated on any channel and reaches out anonymously through two different channels cannot be reliably linked without some connecting piece of information. But for any user who has an established account — which covers the majority of high-value interactions — cross-channel identity resolution is what makes the difference between an agent that feels like one continuous relationship and one that feels like starting over every time you happen to reach for a different app.
Managing Back-and-Forth Conversation State Across Channels
Beyond identity, there's the harder ongoing problem of actually managing a multi-turn conversation across channels with fundamentally different technical characteristics.
Synchronicity varies enormously by channel, and the agent needs to behave differently as a result. A web widget conversation is synchronous — the user is watching, waiting for a response, and a multi-second delay feels broken. An email conversation is asynchronous by nature — the user sent a message and closed their inbox; a response arriving five minutes or five hours later is both expected and fine. A WhatsApp conversation sits somewhere in between — often synchronous in the moment, but tolerant of gaps if the agent needs to do real work (a longer research task, a multi-step booking process) before responding. The same underlying agent task might need to stream partial progress in a web widget, send nothing until it's fully done for email, and send an intermediate "still working on this" message for WhatsApp to avoid the user assuming the conversation died.
Session boundaries differ by channel and need explicit handling. Slack conversations are naturally scoped by threads — a new thread is a clear signal of a new topic, and the agent can use thread boundaries as a reasonable proxy for conversation boundaries. WhatsApp has no native threading; a 24-hour session window governs what kind of messages you can send without a pre-approved template, but from a conversation-continuity perspective, you need your own logic to decide when a gap in messages represents a new topic versus a continuation of the same one. Email threading via Message-ID and References headers gives you a technical signal for what's part of the same thread, but users routinely start "new" emails that are conceptually continuations, and reply to old threads with unrelated new questions. None of these signals are fully reliable on their own; production systems typically combine channel-native threading signals with a time-based gap heuristic and, where uncertain, a lightweight check with the user.
Rich formatting capabilities vary drastically, and the agent's response needs to degrade gracefully. A response that includes a data table, a set of clickable options, and an embedded image works beautifully in a web widget or Slack. The same response needs to become a numbered list of text options for WhatsApp, plain text with a request to reply with a number for SMS, and a spoken enumeration for voice — "I found three options. Say one, two, or three, or ask me to repeat them." Building the agent's response as a structured, semantic object — not raw text — is what makes this degradation possible without rewriting the agent's logic per channel. The renderer layer handles the translation; the agent just needs to express its response in a format that carries enough structure to be translated well.
Interruptions and channel switches mid-task need to be handled without losing progress. A user starts a multi-step booking flow on the web widget, gets a notification and closes their laptop, then continues the conversation from their phone via WhatsApp twenty minutes later. If identity resolution and conversation state are correctly unified, this should just work — the agent picks up exactly where the task left off, on a different channel, without the user having to re-explain anything. This is one of the more impressive-feeling capabilities from a user's perspective, and it's a direct payoff of building the architecture with a genuinely channel-agnostic conversation core from the start, rather than retrofitting it after building channel-specific silos.
Channel-Specific Considerations Worth Knowing Upfront
A few practical notes on the channels most agent deployments end up needing, because each has real constraints that shape what's possible:
WhatsApp Business API requires pre-approved message templates for any message that initiates contact with a user, or for messages sent outside a 24-hour window since the user's last message. Free-form replies are only permitted within that 24-hour session. This has real design implications: an agent that needs to follow up with a user after more than a day needs a pre-approved template for that specific type of outreach, not arbitrary generated text. Plan for this constraint from the start rather than discovering it when a follow-up message gets rejected.
Slack rewards building with Block Kit rather than plain text from day one. Interactive buttons, structured approval cards, and threaded context isolation are native to the platform and dramatically improve the HITL approval experience covered in the last issue — a Slack-native approve/reject button pair is a far better interface for that pattern than asking a user to type "approve" or "reject" as free text.
Voice channels impose the tightest technical constraints of any channel: strict latency budgets (silence past a couple seconds feels broken in a phone call in a way it doesn't in a chat interface), no visual context to fall back on for complex information, and a requirement that everything the agent wants to convey has to work as spoken language, including how numbers, lists, and options are read aloud. Voice deployments typically need meaningfully more investment in response formatting — SSML markup, careful enumeration of options, explicit confirmation of what the system heard — than any text-based channel.
Email has the highest latency tolerance of any common channel, which is both an advantage (you can afford to do real agent work before responding) and a trap (users' expectations for email response time have been shaped by human response patterns, and an agent that takes three days to reply because nobody built proper trigger handling will feel broken even though three days is, technically, well within typical human email norms).
Why Investing in Channel Breadth Compounds
The case for building genuine multi-channel support early, rather than treating it as a backlog item, comes down to three compounding effects.
Adoption follows availability, not just quality. An excellent agent that only lives in a web widget will be used by the subset of your audience who happen to already be on your website at the moment they have a need. An agent available in Slack, WhatsApp, and email meets people at the moment the need arises, in whatever context they're already in. The quality bar matters, but availability at the point of need is very often the larger lever on actual usage.
Different channels surface genuinely different use cases. A field service agent accessed via SMS handles fundamentally different interactions than the same agent accessed via a rich web dashboard — not because the underlying capability differs, but because the channel shapes what kind of question people think to ask and what kind of task feels natural to delegate through it. Teams that build only one channel often conclude their agent's use cases are narrower than they actually are, simply because they've only observed the slice of usage that fits through the one door they built.
The unified architecture, once built, makes every new channel cheap. This is the real payoff of investing in the channel-agnostic core early rather than building channel-specific silos. The first two channels are the expensive ones — that's where the conversation core, the identity resolution layer, and the response rendering abstraction get built. Every channel after that is, largely, a new adapter and a new renderer target, plugged into infrastructure that already works. Teams that build channel-specific silos from the start pay the full cost of every new channel, indefinitely, and their channels drift in behavior and quality over time because there's no shared core keeping them consistent.
⚡ The practitioner take
The teams I've seen underinvest in this are almost always teams that started with a web chat widget, found it working reasonably well, and treated additional channels as a straightforward "add an integration" task late in the roadmap. It's rarely straightforward at that point — because the agent's conversation handling, state management, and response generation were built with the assumptions of a single rich, synchronous channel baked in, and retrofitting channel-agnostic behavior after the fact touches almost everything.
Build the channel abstraction early, even if you're only shipping one channel initially. Treat the web widget as channel one of several from day one — with a clean adapter boundary and a channel-agnostic core — rather than as the whole system with channel support bolted on as an afterthought. The incremental cost of building it right the first time is small. The cost of retrofitting it after the agent's logic has become entangled with one channel's specific capabilities is not.
Your users are not going to come to your interface. Your agent needs to go to theirs.
— Santosh
👀 Also Watching
WhatsApp Business Platform's template message policies — worth reading closely before building any WhatsApp integration; the 24-hour session window and template approval process shape the entire design of proactive agent outreach on this channel.
Slack's Bolt framework and Block Kit Builder — the fastest path to a genuinely rich Slack agent experience, including the interactive approval components directly relevant to HITL workflows covered last issue.
Twilio's Conversations API — a useful reference for how a mature platform handles the exact cross-channel identity and session unification problem described in this issue, across SMS, WhatsApp, and voice simultaneously.
Until next time,

Learn to use AI. Use AI to learn.
If someone forwarded this to you, subscribe at whattheagent.com. If this was useful, forward it to one engineer who needs it.