How Maka Integrates with Messaging Platforms via Bot Bridges: Architecture and Implementation Guide

Maka integrates with messaging platforms via pluggable Bot Bridges that translate native protocols into a canonical BotMessageEvent shape, managed centrally by the BotRegistry which handles lifecycle, configuration, and bidirectional message routing.

Maka's messaging-platform integration relies on a sophisticated adapter pattern that abstracts platform-specific protocols into a unified interface. The apache/maka repository implements this through Bot Bridges—specialized adapters that normalize incoming messages and expose a common send API to the runtime. This architecture allows developers to interact with Slack, Discord, and other platforms without managing disparate connection logic.

Architecture Overview

The integration architecture consists of five core components working in concert. The BotRegistry maintains a map of platform identifiers to active bridge instances, while BaseBotAdapter provides the abstract foundation for all platform implementations. For WebSocket-based platforms, GatewayBridgeBase and WsBridgeBase handle connection resilience and gateway protocols. Concrete implementations like SlackBotBridge and DiscordBotBridge manage transport specifics and payload mapping. Finally, BotChatSettings defines the configuration schema that drives bridge instantiation.

This design decouples the runtime from platform specifics, ensuring that new messaging services can be added without modifying core business logic.

Configuration and Registry Management

Bridge lifecycle begins with configuration defined in packages/core/src/bot-chat-settings.ts. The BotChatSettings interface contains a channels record where each entry specifies provider credentials, enablement flags, and connection parameters.

When settings are applied, BotRegistry.applySettings() (located in packages/runtime/src/bots/bot-registry.ts) orchestrates the reconciliation process. The method iterates over configured channels and invokes reconcileOne() (lines 36-84), which either instantiates new bridges for enabled platforms or stops and removes disabled ones. The applySettingsNow method (lines 24-31) handles the async coordination of these operations.

const settings: BotChatSettings = {
  channels: {
    slack: { provider: 'slack', enabled: true, token: 'xoxb-…', appSecret: '…' },
    discord: { provider: 'discord', enabled: true, token: '…' }
  }
};
await registry.applySettings(settings);

Bridge Lifecycle and Event Handling

All bridges extend BaseBotAdapter (packages/runtime/src/bots/base-adapter.ts), which defines the common interface for start(), stop(), and status management. WebSocket-based platforms utilize GatewayBridgeBase or WsBridgeBase (packages/runtime/src/bots/ws-bridge-base.ts), implementing automatic reconnection with exponential back-off and close-policy handling.

During startup, bridges establish platform-specific connections—Slack opens a Socket Mode WebSocket, while Discord fetches the gateway URL via REST before WebSocket handshake. Once connected, bridges listen for native events (e.g., Discord's MESSAGE_CREATE or Slack's slack_event), transform them via platform-specific mappers like slackMessageToEvent() or discordMessageToEvent(), and emit normalized BotIncomingMessage objects.

Platform-Specific Bridge Implementations

Slack Integration

The SlackBotBridge (packages/runtime/src/bots/slack-bridge.ts) leverages @slack/socket-mode for real-time event streaming. The start() method (lines 78-85) initializes the Socket Mode client, while slackMessageToEvent() maps Slack's proprietary event schema to Maka's canonical format. Outbound messages translate to Slack's chat.postMessage API via the internal WebClient.

Discord Integration

The DiscordBotBridge (packages/runtime/src/bots/discord-bridge.ts) implements the Discord Gateway protocol. It fetches the gateway URL (lines 38-55), establishes WebSocket communication through WsBridgeBase, and sends an identify payload for authentication. Incoming MESSAGE_CREATE dispatches trigger discordMessageToEvent() (lines 83-94) to normalize payloads. Sending operates via REST calls to Discord's channels/{id}/messages endpoint.

Message Normalization and Routing

Incoming message flow traverses from platform-specific formats to the unified BotIncomingMessage interface containing platform, userId, chatId, and text fields. The BotRegistry.wire() method (lines 94-98 in bot-registry.ts) attaches event listeners to each bridge, forwarding normalized events to the runtime via the onIncomingMessage callback supplied during registry construction.

This normalization ensures that downstream handlers process messages identically regardless of whether they originated from Slack, Discord, or QQ.

Sending Messages via the Unified API

Outbound communication flows through BotRegistry.sendMessage() (lines 82-91), which accepts a platform identifier, chat ID, message text, and optional parameters. The registry locates the appropriate bridge instance, verifies it implements the optional sendMessage method, and delegates the call. Each bridge translates the request into platform-native API calls—Slack uses chat.postMessage, while Discord utilizes channel-specific REST endpoints.

// Send to Slack channel
await registry.sendMessage('slack', 'C01ABCD2EFG', 'Hello from Maka!');

// Send to Discord channel  
await registry.sendMessage('discord', '123456789012345678', 'Hello Discord!');

Health Monitoring and Status Aggregation

Bridges expose granular readiness states—scaffolded, configured, operational, or degraded—managed through BaseBotAdapter fields (running, readiness, reason). Status transitions emit via emitStatusChange(), allowing the registry to aggregate health across all platforms via allStatuses().

The registry propagates these states to the UI, enabling real-time visibility into connection health without exposing platform-specific error codes to the application layer.

Practical Implementation Example

The following example demonstrates complete bridge initialization and messaging:

import { BotRegistry } from '@maka/runtime/src/bots/bot-registry';
import { BotChatSettings } from '@maka/core/bot-chat-settings';

// Build configuration from environment variables
const settings: BotChatSettings = {
  channels: {
    slack: {
      provider: 'slack',
      enabled: true,
      token: process.env.SLACK_BOT_TOKEN ?? '',
      appSecret: process.env.SLACK_APP_SECRET ?? '',
      proxyUrl: '',
      connected: false,
      readiness: 'scaffolded',
    },
    discord: {
      provider: 'discord',
      enabled: true,
      token: process.env.DISCORD_BOT_TOKEN ?? '',
      proxyUrl: '',
      connected: false,
      readiness: 'scaffolded',
    }
  }
};

// Initialize registry with runtime callbacks
const registry = new BotRegistry({
  onIncomingMessage: (msg) => console.log('←', msg),
  onStatusChange: (status) => console.log('↔', status),
});

// Apply settings and start bridges
await registry.applySettings(settings);

// Send test messages
await registry.sendMessage('slack', 'C01ABCD2EFG', 'Hello from Maka!');
await registry.sendMessage('discord', '123456789012345678', 'Hello Discord!');

// Query aggregated health status
console.log(registry.allStatuses());

Summary

  • Pluggable Architecture: Maka uses Bot Bridges to abstract platform protocols (WebSocket, HTTP, Socket Mode) into a unified BotMessageEvent interface.
  • Centralized Management: The BotRegistry handles bridge instantiation via applySettings(), lifecycle management via reconcileOne(), and message routing through sendMessage().
  • Normalization Layer: Platform-specific implementations (Slack, Discord) transform native payloads via dedicated mappers like slackMessageToEvent() and discordMessageToEvent().
  • Resilient Connectivity: WsBridgeBase and GatewayBridgeBase provide reusable WebSocket management with automatic reconnection and health monitoring.
  • Configuration-Driven: BotChatSettings defines provider credentials and enablement states, allowing dynamic bridge creation without code changes.

Frequently Asked Questions

How do I add support for a new messaging platform to Maka?

Create a new class extending BaseBotAdapter (or WsBridgeBase for WebSocket platforms) in packages/runtime/src/bots/. Implement the start() method to establish connections, transform native payloads into BotIncomingMessage via a custom mapper function, and provide a sendMessage() method for outbound communication. Register the bridge in the BOT_PROVIDERS map so BotRegistry can instantiate it from BotChatSettings.

What is the difference between BotChatSettings and BotChannelSettings?

BotChannelSettings defines the interface for individual platform configurations (tokens, secrets, proxy URLs), while BotChatSettings serves as the container object holding the complete channels record. The registry consumes BotChatSettings via applySettings() to reconcile which bridges should be active based on the enabled flags.

How does Maka handle connection failures or disconnections?

The WsBridgeBase class implements automatic reconnection with exponential back-off and configurable close policies. Bridges emit status changes through emitStatusChange(), transitioning readiness states from operational to degraded when connections drop. The registry surfaces these via allStatuses(), allowing applications to monitor health without handling platform-specific retry logic.

Can I send messages to multiple platforms simultaneously?

While BotRegistry.sendMessage() targets a single platform per call, you can broadcast by iterating over enabled channels. Retrieve current bridge statuses via allStatuses(), filter for operational platforms, and invoke sendMessage() for each target. Each bridge translates the request into its native API format (e.g., Slack's chat.postMessage or Discord's channel messages endpoint) independently.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →