Universal gateway connecting AI agent runtimes to messaging platforms
Project description
HarnessGate (Python)
Connect any AI agent runtime to any messaging platform.
Why HarnessGate?
Existing chatbot frameworks run their own agent loop — they call LLM APIs, parse tool calls, execute tools locally, and manage context. When you connect them to a managed agent runtime like Claude Managed Agents, they have to bypass their entire infrastructure just to pipe messages through.
HarnessGate takes a different approach: no local agent loop. It's a pure bridge that delegates all intelligence to the provider runtime. The gateway just routes messages between platforms and the agent.
This means:
- Claude Managed Agents features work out of the box (tool confirmation, custom tools, multi-agent threads, extended thinking)
- Any future agent runtime plugs in with 4 methods
- No competing agent loops, no bypassed infrastructure, no wasted abstractions
[Telegram] [Discord] [Slack] [WhatsApp] [Teams] [Web UI]
| | | | | |
+----+----+----+---+-------+----------+------+
| |
PlatformAdapter ABC (per platform)
| |
+----+----+
|
Bridge (orchestrator)
SessionStore + StreamManager
|
Provider ABC
|
+----------+----------+
| Claude | Custom |
| Managed | (your |
| Agents | class) |
+----------+----------+
Features
- Provider-agnostic — Claude Managed Agents or bring your own
- 6 platform adapters — Telegram, Discord, Slack, WhatsApp, Teams, Web UI
- Multi-app — run multiple bot instances per platform, each mapped to a different agent
- Session management — automatic session creation, in-memory persistence, multi-turn conversations
- Buffer-then-send — accumulates agent responses, sends as one message per turn
- Auto-split — respects per-platform message length limits
- Fully async — built on asyncio with
async/awaitthroughout
Quick Start
pip install harnessgate
import asyncio
from harnessgate import Bridge, BridgeConfig
from harnessgate.providers import ClaudeProvider
from harnessgate.platforms import TelegramAdapter
async def main():
provider = ClaudeProvider(api_key="sk-ant-...")
bridge = Bridge(
provider=provider,
config=BridgeConfig(platforms={"telegram": {"enabled": True}}),
)
# Route users to agents
async def resolve_user(sender, platform, message):
return {
"user_id": sender.id,
"agent_id": "agent_01XXXX",
"environment_id": "env_01XXXX",
}
bridge.set_user_resolver(resolve_user)
bridge.add_platform(TelegramAdapter())
await bridge.connect("telegram", {"bot_token": "123:ABC..."})
await bridge.start()
asyncio.run(main())
Platform Adapters
| Platform | Library | Max text | Markdown | Threads | Typing | Attachments |
|---|---|---|---|---|---|---|
| Telegram | aiogram 3.x | 4096 | Yes | Yes | Yes | Yes |
| Discord | discord.py | 2000 | Yes | Yes | Yes | Yes |
| Slack | slack-bolt | 4000 | Yes | Yes | No | Yes |
| Cloud API (aiohttp) | 4096 | No | No | No | Yes | |
| Teams | Bot Framework SDK | 28000 | Yes | Yes | Yes | Yes |
| Web | Built-in (aiohttp) | 100000 | Yes | No | Yes | No |
Platform Setup Guides
Detailed setup instructions for each platform, including SaaS multi-tenant distribution:
- Telegram Setup — BotFather, privacy settings, multi-instance
- Discord Setup — Developer Portal, intents, OAuth2 invite links
- Slack Setup — Socket Mode, scopes, App Directory distribution
- WhatsApp Setup — Meta Business, webhook config, Embedded Signup
- Teams Setup — Azure Bot, manifest, Teams App Store
- Web Setup — HTTP endpoints, SSE streaming
Provider Setup
Claude Managed Agents
from harnessgate.providers import ClaudeProvider
provider = ClaudeProvider(api_key="sk-ant-...")
Connects to Claude Managed Agents. Full support for streaming, tool confirmation, custom tools, extended thinking, and multi-agent threads.
For Claude, agent_id and environment_id come from your UserResolver, not static provider config:
async def resolve_user(sender, platform, message):
return {
"user_id": sender.id,
"agent_id": "agent_01XXXX",
"environment_id": "env_01XXXX",
}
Custom provider
Implement the Provider ABC:
from harnessgate import Provider
class MyProvider(Provider):
id = "my-provider"
capabilities = ProviderCapabilities(
interrupt=False,
tool_confirmation=False,
custom_tools=False,
thinking=False,
)
async def create_session(self, opts): ...
async def send_message(self, session_id, message): ...
async def stream(self, session_id): ... # AsyncIterator[ProviderEvent]
async def destroy_session(self, session_id): ...
Multi-Bot / appId
Every platform adapter supports running multiple app instances simultaneously. Each app connects to the platform and receives a platform-assigned appId.
# Add multiple Telegram bots at runtime
support_id = await bridge.connect("telegram", {"bot_token": SUPPORT_TOKEN})
sales_id = await bridge.connect("telegram", {"bot_token": SALES_TOKEN})
# Route based on which bot received the message
async def resolve_user(sender, platform, message):
agent_id = await db.get_agent_for_bot(message.app_id)
environment_id = await db.get_environment_for_bot(message.app_id)
return {"user_id": sender.id, "agent_id": agent_id, "environment_id": environment_id}
appId per platform
| Platform | Source | Example value |
|---|---|---|
| Telegram | bot.id |
"123456789" |
| Discord | client.application_id |
"1098765432101234567" |
| Slack | auth_test().bot_id |
"A0123456789" |
| WABA phone number ID | "106540352267890" |
|
| Teams | activity.recipient.id |
"28:abc123..." |
| Web | N/A (single instance) | -- |
Session Management
Each conversation context gets its own provider session:
| Context | Session scope | Example key |
|---|---|---|
| DM | Per user | telegram:direct:123:u:user99 |
| Group/Channel | Shared (all users) | slack:group:ch1 |
| Thread | Per thread | discord:thread:ch1:t:thread99 |
Project Structure
harnessgate-py/
├── src/harnessgate/
│ ├── __init__.py # Public API exports
│ ├── bridge.py # Orchestrator
│ ├── messages.py # InboundMessage, OutboundMessage, Sender, Attachment
│ ├── platform.py # PlatformAdapter ABC
│ ├── provider.py # Provider ABC + ProviderEvent types
│ ├── session.py # SessionStore, MemorySessionStore
│ ├── stream.py # StreamManager
│ ├── platforms/
│ │ ├── telegram.py # aiogram 3.x
│ │ ├── discord.py # discord.py
│ │ ├── slack.py # slack-bolt
│ │ ├── whatsapp.py # Cloud API (aiohttp)
│ │ ├── teams.py # Bot Framework SDK
│ │ └── web.py # Built-in HTTP + SSE
│ └── providers/
│ └── claude.py # Claude Managed Agents
├── tests/ # pytest test suite
├── docs/ # Platform setup guides
├── examples/ # Starter projects
└── pyproject.toml
Requirements
- Python >= 3.11
- uv (recommended) or pip
Development
uv sync
uv run pytest
uv run pyright # type checking
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file harnessgate-0.1.0.tar.gz.
File metadata
- Download URL: harnessgate-0.1.0.tar.gz
- Upload date:
- Size: 134.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.17
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
38fc0c310609c561e5380e7cdbedb85704824d63dff86ceeb57ad5688da73121
|
|
| MD5 |
c2717a7bf00ddb896ab33c6bd0143e84
|
|
| BLAKE2b-256 |
a4f796a149338e0951629d7858bdaab33c4a296ae675b1332408d7ad972e8751
|
File details
Details for the file harnessgate-0.1.0-py3-none-any.whl.
File metadata
- Download URL: harnessgate-0.1.0-py3-none-any.whl
- Upload date:
- Size: 31.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.17
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8cda31f738877caf49bf89c44d53d67aaeb756cf51f812e8bd7acb69a211a95c
|
|
| MD5 |
8753ab99cad07fa6c1b59d42f5ffa21c
|
|
| BLAKE2b-256 |
d4aa85e56cadae424a4ce851a0c3bd828b37a1c4b0089e54c7e7b40215829cef
|