Gateways
Connecting Org in a Box to every channel your team uses.
Supported Channels
| Gateway | Package | Status | Auth Method |
|---|---|---|---|
| Slack | gateway/slack | Implemented | Socket Mode (no public URL needed) |
| Microsoft Teams | gateway/teams | Implemented | Bot Framework webhook |
gateway/email | Implemented | IMAP poll + SMTP send |
Org in a Box focuses on the enterprise and business channels teams already run on. Packages and setup guides exist for each channel above. Treat them as implementation-ready integrations you should validate in your own environment, not as a blanket "production certified" claim for every deployment target.
Consumer channels (Telegram, Discord) ship in the codebase but are disabled by default. They are not part of the supported surface and have no setup guide in these docs.
How Gateways Work
Every gateway follows the same pattern:
Inbound message
↓
buildExternalId() → "<platform>:<userId>"
↓
resolveChannelUser(db, channel, externalId, fallbackUserId)
↓ (finds or creates user + channel_link row)
enqueue({ kind: "agent-turn", payload: { userId, sessionId, text, channel } })
↓
Worker drainer claims job
↓
opencode session.promptAsync()
↓
SSE stream → gateway streams response back to channel
User Pairing
All gateways use a DB-backed pairing system instead of static allowlists. Unknown users receive a one-time pairing code when they first message the bot. The owner approves via the web admin panel (/admin/gateways) or CLI (oiab gateway pairing-approve).
Starting Gateways
Each gateway is a Docker Compose profile:
docker compose --profile slack up -d
docker compose --profile teams up -d
docker compose --profile email up -d
Multiple gateways can run simultaneously.
Multi-Tenant User Resolution
When Azure AD SSO is enabled, users are resolved by their external identity:
- Teams:
aadObjectIdfrom the Bot Framework activity - Slack:
team_id:channel_id:user_id - Others: platform-specific unique ID
When SSO is disabled, all messages from a gateway fall back to OPERATOR_USER_ID.
