# How to Add New Messaging Platform Adapters to the Hermes Agent Gateway

> Learn how to add new messaging platform adapters to the Hermes Agent gateway. Integrate custom platforms by subclassing BasePlatform, implementing async methods, and registering your adapter.

- Repository: [Nous Research/hermes-agent](https://github.com/NousResearch/hermes-agent)
- Tags: how-to-guide
- Published: 2026-03-09

---

**To add a new messaging platform adapter to Hermes Agent, create a Python module in `gateway/platforms/` that subclasses `BasePlatform`, implement the required async methods for message handling and sending, register the class in the `PLATFORMS` dictionary in [`gateway/platforms/__init__.py`](https://github.com/NousResearch/hermes-agent/blob/main/gateway/platforms/__init__.py), and add any required environment variables to the configuration schema.**

The Hermes Agent gateway serves as the bridge between the LLM-driven assistant core and external messaging services like Telegram, Discord, and WhatsApp. For the NousResearch/hermes-agent repository, extending support to additional platforms follows a strict modular architecture that keeps platform-specific logic isolated from the core agent. This guide explains the exact process for adding new messaging platform adapters to the Hermes Agent gateway while preserving the existing abstraction patterns.

## Understanding the BasePlatform Interface

All messaging adapters in Hermes Agent must inherit from the abstract base class defined in [`gateway/platforms/base.py`](https://github.com/NousResearch/hermes-agent/blob/main/gateway/platforms/base.py). This interface enforces a consistent contract for platform initialization, inbound message processing, and outbound message delivery. Your implementation must provide concrete versions of three critical async methods: `handle_update()` for processing incoming webhooks, `send_message()` for delivering replies to users, and `__init__()` for initializing platform-specific credentials. The base class also provides helper utilities like `_post()` for HTTP requests, which your adapter can leverage for API calls to the external messaging service.

## Step-by-Step Implementation Process

### 1. Create the Platform Module

Create a new file under `gateway/platforms/` using a descriptive name for your service (e.g., [`whatsapp.py`](https://github.com/NousResearch/hermes-agent/blob/main/whatsapp.py) or [`signal.py`](https://github.com/NousResearch/hermes-agent/blob/main/signal.py)). This module will house your adapter class and any platform-specific utility functions. Keep the file focused solely on the messaging interface—authentication logic, webhook parsing, and message formatting should all live here to maintain the single-responsibility principle established by existing adapters like [`gateway/platforms/telegram.py`](https://github.com/NousResearch/hermes-agent/blob/main/gateway/platforms/telegram.py).

### 2. Implement the Adapter Class

Subclass `BasePlatform` and define the required attributes and methods. You must set a `name` class attribute (e.g., `name = "whatsapp"`) that serves as the platform identifier throughout the gateway. Implement `__init__()` to accept and store configuration tokens, which the gateway injects from environment variables automatically. The `handle_update()` method receives raw webhook payloads and must return a canonical dictionary with `user_id`, `content`, and `platform` keys. Finally, implement `send_message()` to transmit text responses back to the user through the platform's API.

### 3. Register in the Platform Registry

Update [`gateway/platforms/__init__.py`](https://github.com/NousResearch/hermes-agent/blob/main/gateway/platforms/__init__.py) to import your new class and add it to the `PLATFORMS` dictionary. This registry acts as the discovery mechanism for [`gateway/run.py`](https://github.com/NousResearch/hermes-agent/blob/main/gateway/run.py). The dictionary maps platform name strings to class references, enabling the gateway to instantiate the correct adapter dynamically at runtime based on configuration.

### 4. Configure Environment Variables

Add any required authentication tokens or API secrets to the `.env.example` file for documentation purposes. Then update [`hermes_cli/config.py`](https://github.com/NousResearch/hermes-agent/blob/main/hermes_cli/config.py) to include these variables in the configuration schema, allowing the CLI setup wizard to prompt users for credentials during installation. The gateway automatically loads these environment variables when instantiating your platform class through the `PLATFORMS` registry.

### 5. Implement Custom Commands (Optional)

If your platform requires specific slash commands (e.g., `/whatsapp status`), add handlers in [`gateway/commands.py`](https://github.com/NousResearch/hermes-agent/blob/main/gateway/commands.py) using the `@register_command` decorator. These commands allow users to interact with platform-specific features directly from the chat interface. Alternatively, you can map commands within the platform module itself if the logic is tightly coupled to the adapter's functionality.

## Integration Flow and Architecture

When a message arrives from your new platform, the flow follows this path: the external service sends a webhook to the gateway, [`gateway/run.py`](https://github.com/NousResearch/hermes-agent/blob/main/gateway/run.py) loads the appropriate class from the `PLATFORMS` dictionary, instantiates it using stored credentials, and calls `handle_update()` to normalize the payload. The normalized message passes to the core `AIAgent` for processing. Once the agent generates a response, the gateway calls your adapter's `send_message()` method to deliver the reply back to the user.

## Code Implementation Examples

Here is a minimal skeleton for a new platform adapter:

```python

# gateway/platforms/example.py

from .base import BasePlatform

class ExamplePlatform(BasePlatform):
    """Adapter for the Example messaging service."""

    name = "example"

    def __init__(self, token: str):
        super().__init__()
        self.token = token

    async def handle_update(self, raw_update: dict) -> dict:
        """Convert a raw webhook payload into a canonical message dict."""
        user_id = raw_update["user"]["id"]
        text = raw_update["message"]["text"]
        return {"user_id": user_id, "content": text, "platform": self.name}

    async def send_message(self, user_id: str, content: str) -> None:
        """Send a textual reply back to the user."""
        payload = {"to": user_id, "text": content}
        await self._post("/send", json=payload)

```

Register the adapter in the platform registry:

```python

# gateway/platforms/__init__.py

from .telegram import TelegramPlatform
from .discord import DiscordPlatform
from .example import ExamplePlatform

PLATFORMS = {
    "telegram": TelegramPlatform,
    "discord": DiscordPlatform,
    "example": ExamplePlatform,
}

```

The gateway runner dynamically loads your adapter:

```python

# gateway/run.py excerpt

from .platforms import PLATFORMS

def _create_platform(name: str):
    platform_cls = PLATFORMS[name]
    return platform_cls()

```

Add optional slash commands:

```python

# gateway/commands.py

@register_command("/example")
async def cmd_example(agent, args):
    """Echo the arguments back to the Example platform."""
    await agent.send_to_platform("example", args.text)
    return "Message sent to Example platform."

```

## Testing Your Adapter

Place unit tests under `tests/gateway/test_<platform_name>.py` following the pattern established in existing test files. Mock the external messaging API using `unittest.mock` or `pytest-asyncio` fixtures to verify that `handle_update()` correctly parses webhooks and that `send_message()` formats API requests properly. Test edge cases like malformed payloads, authentication failures, and rate limiting to ensure production reliability.

## Summary

- **Inherit from `BasePlatform`**: All adapters must subclass the abstract base class in [`gateway/platforms/base.py`](https://github.com/NousResearch/hermes-agent/blob/main/gateway/platforms/base.py) and implement `handle_update()`, `send_message()`, and `__init__()`.
- **Register in `PLATFORMS`**: Add your class to the dictionary in [`gateway/platforms/__init__.py`](https://github.com/NousResearch/hermes-agent/blob/main/gateway/platforms/__init__.py) to enable dynamic discovery by [`gateway/run.py`](https://github.com/NousResearch/hermes-agent/blob/main/gateway/run.py).
- **Isolate platform logic**: Keep authentication, webhook parsing, and API calls contained within your `gateway/platforms/<name>.py` module.
- **Configure credentials**: Add environment variables to `.env` examples and [`hermes_cli/config.py`](https://github.com/NousResearch/hermes-agent/blob/main/hermes_cli/config.py) for CLI integration.
- **Test thoroughly**: Create comprehensive mocks in `tests/gateway/` to verify inbound and outbound message handling without hitting live APIs.

## Frequently Asked Questions

### What methods are absolutely required when subclassing BasePlatform?

You must implement three async methods: `__init__()` to accept configuration tokens, `handle_update()` to parse incoming webhooks into canonical dictionaries, and `send_message()` to transmit replies back to users. Missing any of these will raise `NotImplementedError` or cause runtime failures in [`gateway/run.py`](https://github.com/NousResearch/hermes-agent/blob/main/gateway/run.py).

### Where does the gateway load platform credentials from?

The gateway loads credentials from environment variables automatically. Define your required variables (e.g., `EXAMPLE_TOKEN`) in [`hermes_cli/config.py`](https://github.com/NousResearch/hermes-agent/blob/main/hermes_cli/config.py) so the setup CLI can prompt for them, then access them via `os.environ` or the config object within your adapter's `__init__()` method.

### Can I add custom slash commands specific to my messaging platform?

Yes. Register platform-specific commands in [`gateway/commands.py`](https://github.com/NousResearch/hermes-agent/blob/main/gateway/commands.py) using the `@register_command` decorator with a unique prefix (e.g., `/whatsapp status`). These handlers receive the agent instance and command arguments, allowing you to trigger platform-specific actions before returning control to the core agent loop.

### How do I test my adapter without connecting to the live messaging service?

Create unit tests in `tests/gateway/` that mock your platform's API responses using `unittest.mock.patch` or `aioresponses` for async HTTP calls. Verify that `handle_update()` correctly transforms sample webhook JSON into the expected canonical format, and assert that `send_message()` calls the expected API endpoints with properly formatted payloads.