# How to Add a New Platform Interface to the Heurist Agent Framework: Slack, WhatsApp, and Custom Integrations

> Learn to add new platform interfaces like Slack and WhatsApp to Heurist Agent Framework. Follow our guide to create wrappers and integrate custom solutions easily. Extend agent capabilities today.

- Repository: [Heurist/heurist-agent-framework](https://github.com/heurist-network/heurist-agent-framework)
- Tags: how-to-guide
- Published: 2026-03-03

---

**To add a new platform interface to the Heurist Agent Framework, create a wrapper class that stores a reference to `CoreAgent` in `_parent`, registers itself via `register_interface()`, implements the `async def send_message(self, chat_id: str, message: str, image_url: str | None = None)` coroutine, and forwards inbound messages to `self.handle_message()`.**

The Heurist Agent Framework decouples reasoning logic from communication channels, allowing you to add a new platform interface such as Slack or WhatsApp without modifying the core AI pipeline. By treating every external service as a thin translation layer, the framework enables agents to respond uniformly across Telegram, Discord, Twitter, and any custom platform you implement.

## Architecture of a Platform Interface

A platform interface in the Heurist Agent Framework acts as a bridge between external messaging services and the **CoreAgent** located in [`agents/core_agent.py`](https://github.com/heurist-network/heurist-agent-framework/blob/main/agents/core_agent.py). Unlike traditional inheritance patterns, platform interfaces use **composition** to reuse logic.

The interface stores a reference to the core agent in the private attribute `_parent` and delegates missing attributes via `__getattr__` and `__setattr__`. This design lets the interface call `self.handle_message()` and `self.register_interface()` as if it were the core agent itself, while only implementing platform-specific send/receive logic.

According to the source code in [`agents/base_agent.py`](https://github.com/heurist-network/heurist-agent-framework/blob/main/agents/base_agent.py), every interface must satisfy three contractual obligations:

1. **Link to CoreAgent** – Store the core agent reference in `_parent` and call `CoreAgent.register_interface(name, self)` during initialization.
2. **Implement `send_message`** – Provide an async method with the exact signature `async def send_message(self, chat_id: str, message: str, image_url: str | None = None)` that the core agent invokes when generating replies.
3. **Forward inbound events** – Capture platform-specific events and translate them into calls to `self.handle_message(message=..., source_interface=..., chat_id=...)`.

## Step-by-Step Guide to Adding a Slack Interface

Follow these concrete steps to add a new platform interface for Slack. The same pattern applies to WhatsApp, Microsoft Teams, or any other service.

### 1. Create the Interface File

Add a new file at [`interfaces/slack.py`](https://github.com/heurist-network/heurist-agent-framework/blob/main/interfaces/slack.py). Use [`interfaces/telegram.py`](https://github.com/heurist-network/heurist-agent-framework/blob/main/interfaces/telegram.py) as a reference template, as it demonstrates the proper parent-linking pattern and event handling structure.

### 2. Install Platform Dependencies

Add the Slack SDK to your environment. The framework uses `uv` for dependency management:

```bash
uv add slack_sdk

```

Document the new requirement in [`pyproject.toml`](https://github.com/heurist-network/heurist-agent-framework/blob/main/pyproject.toml) to ensure reproducible builds.

### 3. Configure Environment Variables

Define authentication variables in `.env.example` and your runtime environment:

```bash
SLACK_BOT_TOKEN=xoxb-your-bot-token
SLACK_SIGNING_SECRET=your-signing-secret

```

The framework follows a strict convention where each interface reads its credentials from environment variables, matching the pattern used by `TELEGRAM_API_TOKEN` and `DISCORD_TOKEN` in existing implementations.

### 4. Implement the SlackAgent Class

Create the class with parent linking, authentication, and event handling. The following implementation in [`interfaces/slack.py`](https://github.com/heurist-network/heurist-agent-framework/blob/main/interfaces/slack.py) demonstrates the complete pattern:

```python
import os
import logging
import asyncio
from slack_sdk.web.async_client import AsyncWebClient
from slack_sdk.socket_mode.aiohttp import SocketModeClient
from slack_sdk.socket_mode.request import SocketModeRequest
from slack_sdk.socket_mode.response import SocketModeResponse
from agents.base_agent import BaseAgent

logger = logging.getLogger(__name__)

class SlackAgent:
    def __init__(self, core_agent=None):
        # Parent linkage pattern required by the framework

        if core_agent is not None and not isinstance(core_agent, BaseAgent):
            raise TypeError("core_agent must be a BaseAgent")
        
        if core_agent:
            super().__setattr__("_parent", core_agent)
        else:
            super().__setattr__("_parent", self)
            super().__init__()

        # Platform-specific authentication

        self.token = os.getenv("SLACK_BOT_TOKEN")
        if not self.token:
            raise ValueError("SLACK_BOT_TOKEN not set")
        
        self.web_client = AsyncWebClient(token=self.token)
        self.socket_client = SocketModeClient(
            app_token=self.token, 
            web_client=self.web_client
        )

        # Register event handlers

        self.socket_client.socket_mode_request_listeners.append(self._process_events)

        # Register interface with CoreAgent

        self.register_interface("slack", self)

    async def _process_events(self, client: SocketModeClient, req: SocketModeRequest):
        if req.type != "events_api":
            return
        
        event = req.payload["event"]
        # Handle simple text messages only

        if event.get("type") == "message" and "subtype" not in event:
            channel = event["channel"]
            user_msg = event["text"]
            
            # Forward to CoreAgent logic

            text_resp, img_url, _ = await self.handle_message(
                message=user_msg,
                source_interface="slack",
                chat_id=channel,
            )
            
            await self.send_message(channel, text_resp, img_url)
        
        # Acknowledge receipt to Slack

        response = SocketModeResponse(envelope_id=req.envelope_id)
        await client.send_socket_mode_response(response)

    async def send_message(self, chat_id: str, message: str, image_url: str | None = None):
        """Required interface method called by CoreAgent."""
        await self.web_client.chat_postMessage(channel=chat_id, text=message)
        
        if image_url:
            await self.web_client.files_upload(
                channels=chat_id, 
                file=image_url, 
                title="Generated image"
            )

    def run(self):
        asyncio.run(self.socket_client.connect())

```

### 5. Create an Entry Point (Optional)

For standalone testing, create [`main_slack.py`](https://github.com/heurist-network/heurist-agent-framework/blob/main/main_slack.py) to instantiate the core agent and attach your interface:

```python
import asyncio
from agents.core_agent import CoreAgent
from interfaces.slack import SlackAgent

async def main():
    core = CoreAgent()
    await core.initialize()
    
    # Instantiate registers the interface automatically

    slack = SlackAgent(core_agent=core)
    
    # Keep the process alive

    await asyncio.Event().wait()

if __name__ == "__main__":
    asyncio.run(main())

```

### 6. Register with the Core Agent

When running multiple interfaces, instantiate each one with the same `CoreAgent` reference:

```python
from agents.core_agent import CoreAgent
from interfaces.slack import SlackAgent
from interfaces.telegram import TelegramAgent

async def main():
    core = CoreAgent()
    await core.initialize()
    
    SlackAgent(core_agent=core)    # Registers as "slack"

    TelegramAgent(core_agent=core) # Registers as "telegram"

    
    await asyncio.Event().wait()

```

The `CoreAgent.send_to_interface()` method (located at lines 185-215 in [`agents/core_agent.py`](https://github.com/heurist-network/heurist-agent-framework/blob/main/agents/core_agent.py)) looks up the target interface by the name provided during registration and invokes its `send_message` method.

## Adapting the Pattern for WhatsApp or Other Platforms

To add a new platform interface for WhatsApp instead of Slack, follow the identical architectural pattern while substituting the client library:

1. **Install the appropriate SDK** (e.g., `twilio` for WhatsApp Business API or `yowsup` for unofficial protocols) using `uv add`.
2. **Define environment variables** such as `WHATSAPP_API_KEY` and `WHATSAPP_PHONE_NUMBER_ID`.
3. **Implement the event loop** using the library's webhook or polling mechanism, translating incoming messages into `self.handle_message()` calls.
4. **Implement `send_message`** using the library's message delivery API.

The framework imposes no constraints on how you receive events—webhooks, WebSockets, or polling—provided you forward the text content to `handle_message()` and expose the standardized `send_message` coroutine.

## Key Source Files

Understanding these files in the `heurist-network/heurist-agent-framework` repository helps when debugging or extending your interface:

- **[`agents/base_agent.py`](https://github.com/heurist-network/heurist-agent-framework/blob/main/agents/base_agent.py)** – Defines the abstract interface contract including `handle_message`, `register_interface`, and `send_to_interface`.
- **[`agents/core_agent.py`](https://github.com/heurist-network/heurist-agent-framework/blob/main/agents/core_agent.py)** – Implements the reasoning pipeline, tool orchestration, and knowledge-base lookup. Lines 185-215 contain the `send_to_interface` dispatch logic.
- **[`interfaces/telegram.py`](https://github.com/heurist-network/heurist-agent-framework/blob/main/interfaces/telegram.py)** – Reference implementation showing proper parent linking and message handling.
- **[`interfaces/discord.py`](https://github.com/heurist-network/heurist-agent-framework/blob/main/interfaces/discord.py)** – Alternative example demonstrating WebSocket-based event handling.
- **[`pyproject.toml`](https://github.com/heurist-network/heurist-agent-framework/blob/main/pyproject.toml)** – Dependency management file where you add platform-specific SDKs.

## Summary

- **Platform interfaces** are thin wrappers that translate between external messaging services and the Heurist Agent Framework's core logic.
- **Composition over inheritance**: Interfaces store a `_parent` reference to `CoreAgent` and delegate attributes via `__getattr__`, avoiding code duplication.
- **Required methods**: Implement `send_message(self, chat_id, message, image_url)` and forward inbound events to `handle_message(source_interface, chat_id, message)`.
- **Registration**: Call `self.register_interface("name", self)` during initialization to enable the core agent to route replies.
- **Environment configuration**: Follow the existing pattern of reading tokens from environment variables defined in `.env.example`.

## Frequently Asked Questions

### Do platform interfaces inherit from BaseAgent?

No. Platform interfaces do not inherit from `BaseAgent` or any other base class. Instead, they use **composition** by storing a reference to the core agent in `_parent` and delegating attribute access via `__getattr__` and `__setattr__`. This allows the interface to reuse all core logic—including prompt handling and tool execution—without duplicating code or creating circular dependencies.

### How does CoreAgent know which interface to use when sending replies?

When your interface calls `self.register_interface("slack", self)` during initialization, it adds itself to a registry inside `CoreAgent`. Later, when the core agent generates a response, it calls `send_to_interface()` (implemented in [`agents/core_agent.py`](https://github.com/heurist-network/heurist-agent-framework/blob/main/agents/core_agent.py) lines 185-215), which looks up the interface by the name provided during registration and invokes its `send_message` method with the appropriate `chat_id`.

### Can I run multiple platform interfaces simultaneously?

Yes. Instantiate multiple interface classes with the same `CoreAgent` reference in your main entry point. Each interface runs its own event loop or webhook listener. For example, you can run `SlackAgent(core_agent=core)` and `TelegramAgent(core_agent=core)` in the same process, and `CoreAgent` will route responses to the correct platform based on the `source_interface` parameter passed to `handle_message`.

### Which library should I use for WhatsApp integration?

For WhatsApp Business API, use the official **Twilio** Python SDK (`twilio`) or **Meta's Business SDK**. For unofficial WhatsApp Web protocols, libraries like `yowsup` or [`whatsapp-web.js`](https://github.com/heurist-network/heurist-agent-framework/blob/main/whatsapp-web.js) (via Python bridge) are community options. Regardless of the library, you must implement the same three contractual obligations: parent linking, `send_message`, and forwarding events to `handle_message`.