A channel is a chat surface your deployed portable agent can be reached from: someone mentions it in a Slack channel, or sends it a direct message, and it answers. Slack is available today. WhatsApp is coming, and mail after that.
The most important thing to understand before you start is what airlock does and does not do here.
airlock is not in the message path
You run the listener. It is a small service in your own infrastructure that connects to Slack, receives the event, decides that this agent should answer it, and then calls airlock's MCP endpoint as a service account.
Slack -> your listener -> airlock MCP endpoint -> your tools
What airlock sees is an ordinary authenticated tool call, exactly like one from any other client. There is no airlock webhook to point Slack at, no route for airlock to resolve, and no inbound endpoint to configure. That is deliberate: your agent runs where you choose to run it, and its governance does not depend on where that is.
What airlock gives you is the setup material (both Slack app manifests, generated for your organization, plus the written steps) and the identity and credential your listener authenticates with. It keeps no record of which channels an agent is reachable from: airlock cannot see whether a listener is running, so such a record would look like status without being one.
You can write the listener yourself: it is a small service, and the scopes and events it needs are exactly what the generated manifest requests. airlock's own reference implementation (airlock-assistant) is being prepared for release, and this guide describes the behaviour it implements.
Where to find it
Channels live on the Channels tab of an agent, beside Configure and Deploy. The tab holds the setup guides and nothing else: there is no form to fill in and nothing per agent to pick, because the setup is identical for every agent. The only thing that varies is the token your listener authenticates with.
A channel is not part of the agent definition, so it is not part of what a host loads when it runs the agent: what a host fetches is the prompt, the model preference and the skills, never a Slack workspace.
Step 1: choose the service account
This is the single most consequential decision on the page.
A deployment carries no permissions of its own. When your listener calls airlock, airlock evaluates policy for the acting principal, which is the service account the listener authenticated as. So:
The agent can do exactly what that service account can do. No more, and no less.
A narrower agent is a narrower service account. Give the account only the integrations, skills and tools this agent needs, and create a dedicated account rather than reusing a broad one across several agents. See Service Accounts for how to create one and grant it access.
A listener runs on its own with no person present per call, which is exactly what a service account is for: it is governed like any other process running without a person at the keyboard.
Step 2: issue the token your listener authenticates with
Create a token for that account on the Service Accounts screen. It is shown once, and your listener presents it as its airlock identity.
Revoking the token, or disabling the account, is how you stop the listener reaching airlock. There is no other switch, because airlock is not in the message path.
Step 3: create the Slack app your listener runs as
In the Control Room, open the agent's Channels tab and copy the listener app manifest. In Slack, go to api.slack.com/apps, choose Create New App, then From an app manifest, and paste it.
Install the app into your workspace, then generate an app-level token with the connections:write scope. Socket Mode needs that scope specifically and the bot token cannot stand in for it, so a token generated with any other scope leaves the listener unable to open its connection. Give both tokens to your listener. Socket Mode means the listener needs no public endpoint of its own.
You hold this token, and airlock never sees it.
The manifest requests exactly what the reference listener uses:
Step 4 (optional): give airlock its own Slack credential
Only if you want your agents to use Slack as a tool, for example posting a summary into a channel or reading a channel's history, rather than only replying where they were addressed.
That is a second, separate Slack app, and its manifest is generated for you too. Install it, then give its bot token to airlock. Keep it out of your listener's environment.
Save it on the service account, not on your own user. airlock injects credentials per calling principal, and your listener calls as the service account from Step 1. So:
- Grant that service account access to the Slack integration.
- Open the service account (Service Accounts in the sidebar, then its detail page) and enter the bot token under Credentials.
A token entered from your own Credentials tab is stored against you. The integration will look connected while you are signed in, and every Slack tool call the agent makes will still fail for want of a credential.
Its scopes are exactly what airlock's own Slack tools call, and nothing more: removing one removes the tools that need it, and adding one grants reach no airlock tool will use.
Strongly consider setting its send-message tool to require approval. Outbound messages to people, under your organization's name, written by a model, are the textbook case for a human gate.
Step 5: invite the app to the channels it should see
A bot token only reads and posts where its app is a member, so invite it to each channel deliberately. Treat that as a feature: your agent's reach becomes explicit and revocable per channel rather than "the whole workspace, forever".
Step 6: check that it answers
Mention the agent in a channel you invited it to and confirm it replies. That check is the only confirmation there is: airlock does not route messages and never observes your listener, so it cannot tell you whether the wiring works, and it will not report a listener that has stopped.
Pointing two agents at one channel is allowed. airlock does not route messages, so it is a configuration smell for you to notice rather than a conflict for airlock to reject.
What is actually enforced, and by what
This section matters more than it looks. Three different things are doing the work, and they do not survive the same changes.
Enforced by the Slack credential. Neither bot token can read history in, or post into, a channel its app was never invited to. Neither manifest requests chat:write.public, so neither app can post uninvited. This holds whatever your listener's code does.
Direct messages are not channels. That bound is a channel bound, and it does not reach DMs. Both apps hold im:history (the airlock app also mpim:history), so each reads the full history of any direct message or group DM its bot takes part in, and there is no invite to withhold. chat:write writes back into those same conversations.
Nor is listing bounded by membership. Membership gates content, not existence. users:read enumerates your entire workspace user directory on both apps, and the airlock app additionally holds channels:read, which lists every public channel and its metadata with no invite at all.
Neither generated manifest requests a user scope. Slack's search scopes exist only for user tokens, and airlock refuses its two search tools on a bot connection outright, so requesting one here would mint a second token acting as the installing person, searching everything they can see, that this flow never stores or uses. Searching Slack needs a user OAuth connection instead.
Enforced by the listener's code. Replying only in a thread, and only where the bot already participates, is a rule in the listener you run, and it applies to channel messages. Direct messages are handled before those checks. Change that code and this changes with it.
Not governed at all. Within the channels it was invited to, your listener reads history and posts using its own Slack token, directly. Those calls do not pass through airlock. airlock governs what your listener asks airlock to do, not what it does in Slack.
So what does splitting the credential across two apps buy? It keeps the broader credential out of your own compute. That is the honest claim, and it is worth stating what it is not: the airlock app's token is not a workspace-wide credential (both are bot tokens, gated on channel membership for reading history and for posting), and it is not a strict superset of the listener's either (the listener holds app_mentions:read, which the airlock app does not). Each app requests what its own job needs.
Size your trust to that, not to the paragraph above it.
WhatsApp and mail
WhatsApp appears in the Control Room as coming soon. There will be no file to generate for it: connecting a WhatsApp Business number is a sequence of steps in Meta Business Manager (a Business Account, a registered phone number, webhook configuration) rather than an app manifest. The shape of the flow is the same, and the same rule applies: you run the listener.
Mail follows after that.
Troubleshooting
The agent never answers a mention. Check that the app is invited to the channel, and that your listener's Socket Mode connection is up. airlock has no visibility into either.
The agent answers but every tool call is refused. The service account it authenticates as has no grant for that integration. Access is the account's, not the deployment's.
Calls stopped after a token change. A rotated or revoked service token is refused from the next call onward. Issue a new one on the Service Accounts screen and update the listener.