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

> Explore how Maka integrates with messaging platforms using Bot Bridges. Learn about the architecture, central BotRegistry management, and bidirectional message routing for seamless communication.

- Repository: [The Apache Software Foundation/maka](https://github.com/apache/maka)
- Tags: architecture
- Published: 2026-09-09

---

**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`](https://github.com/apache/maka/blob/main/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`](https://github.com/apache/maka/blob/main/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.

```typescript
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`](https://github.com/apache/maka/blob/main/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`](https://github.com/apache/maka/blob/main/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`](https://github.com/apache/maka/blob/main/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`](https://github.com/apache/maka/blob/main/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`](https://github.com/apache/maka/blob/main/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.

```typescript
// 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:

```typescript
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.