Interfaces
Interfaces provide the communication layer between synth and external platforms. Like plugins and Cortex engines, interfaces are completely modular and automatically discovered at runtime. This ensures that platform integrations are decoupled from the core system and can be developed independently.
Interface Architecture
All interfaces follow a consistent architecture:
Auto-Discovery: Interfaces are automatically found in the
interface/directoryStandard Interface: Interfaces extend
AIPluginBaseor implement compatible methodsAction Providers: Interfaces can provide actions (sending messages, media, etc.)
Security Integration: Built-in trainer ID validation and rate limiting
Platform Abstraction: Unified message format across different platforms
Available Interfaces
Stable Interfaces (in interface/ directory):
discord_interface– Discord bot integration. RequiresDISCORD_BOT_TOKEN.fluxer_interface– Fluxer bot integration (self-hostable, Discord-compatible chat) via a native aiohttp REST + WebSocket gateway client. RequiresFLUXER_TOKEN. See Fluxer Interface.matrix_interface– Matrix chat bridge powered bymatrix-nio. Requires homeserver credentials and tokenizer (password or access token).openai_api_server– OpenAI-compatible REST bridge that lets external clients talk to SyntH as if it were an OpenAI endpoint. It also implements the legacy/api/generate·/api/chat·/api/tagsroutes, so tools written for a local Ollama daemon work unchanged.telegram_bot– Telegram bot interface with media support. RequiresBOTFATHER_TOKENand trainer ID.
Development Interfaces (in interface_dev/ directory):
cli– Local command-line interface for direct interaction (no configuration).reddit_interface– Asynchronous Reddit client for posts, comments, and DMs. Requires Reddit API credentials.telethon_userbot– Advanced Telegram userbot using Telethon. RequiresAPI_ID,API_HASH, and session.webui– FastAPI-based web interface for browser access. Configurable host/port.x_interface– Experimental X (Twitter) integration with timeline features. RequiresX_USERNAME.
Discord Interface
The Discord interface provides full bot integration:
Setup Steps:
Create an application at Discord Developer Portal
Add a bot user and copy the token
Enable required intents (Message Content Intent, etc.)
Generate invite URL with bot scope and permissions
Set
DISCORD_BOT_TOKENin environment variablesStart synth - the interface loads automatically
Features:
Real-time message handling
Media upload/download support
Thread and channel management
Role and permission integration
Fluxer Interface
Fluxer is a self-hostable, Discord-compatible chat platform. The interface ships
a native Python client (aiohttp REST + WebSocket gateway) — no .NET runtime or
discord.py dependency — so it runs inside the slim container image.
Setup Steps:
Create a bot account on your Fluxer server and copy its token
Set
FLUXER_TOKEN(the ``Bot `` prefix is added automatically if omitted)(Self-host only) override
FLUXER_API_BASE_URL/FLUXER_GATEWAY_URL/FLUXER_API_VERSIONto point at your deploymentStart synth — the interface loads automatically
Features:
Real-time message handling over the gateway WebSocket with heartbeat, automatic reconnect, and session resume
Text messages in/out and generic file sending (
send_file_fluxer_bot)Fully configurable endpoints for self-hosted instances
Hot reload on token/endpoint changes (no restart)
See Fluxer Interface for the full configuration reference.
Telegram Bot Interface
The Telegram bot interface offers comprehensive Telegram integration:
Configuration:
BOTFATHER_TOKEN=your_bot_token
TRAINER_IDS=telegram_bot:123456789
Features:
Message threading support
Media handling (photos, documents, voice)
Inline keyboard and callback support
Group and private chat handling
Trainer ID security validation
- Wake/Sleep attention mode (commands
/wake/awake/sleep/status) Default: awake (listens to all messages in the chat)
/sleep: switches to mention/reply-only handling for that chat/wake//awake: restores awake behavior/status: shows the current modeCHAT_SLEEP_COMMANDS/CHAT_WAKE_COMMANDS: configurable comma-separated phrases that can act as chat-level sleep/wake triggers (set via WebUI).
- Wake/Sleep attention mode (commands
Reddit Interface
The Reddit interface enables social media integration:
Required Credentials:
REDDIT_CLIENT_ID=your_client_id
REDDIT_CLIENT_SECRET=your_client_secret
REDDIT_USERNAME=your_username
REDDIT_PASSWORD=your_password
REDDIT_USER_AGENT=synthFreedomProject/1.0
Capabilities:
Post creation and commenting
Direct message handling
Subreddit monitoring
User interaction tracking
Web UI Interface
The web interface provides browser-based access:
Configuration:
SYNTH_WEBUI_HOST=0.0.0.0
SYNTH_WEBUI_HTTP_PORT=8001
SYNTH_WEBUI_HTTPS_PORT=8000
See also: Compose / Environment Variables for a complete list of Compose variables, defaults and recommendations.
Features:
Modern web interface
Real-time chat updates
File upload support
Responsive design
Extended API Endpoints
The Web UI exposes additional endpoints used by external integrations such as Mate-Engine:
GET /api/animation_state– Current centralized animation statePOST /api/animation_state– Request a centralized animation state change. Body:{state, session_id?, loop?, context_id?, source?}POST /api/animations/upload– Temporary animation upload (FBX/VRMA)GET /api/animations/uploads– List temporary animation uploadsDELETE /api/animations/uploads/{upload_id}– Remove a temporary uploadPOST /api/animations/promote– Promote a temporary upload into a skinGET /api/about– About summary payload (uptime, sessions, system info)GET /api/prompt_override– Interface prompt injection/override hintsPOST /api/integrations/messages– Generic integration message endpoint. Body:{source, type, payload, metadata}.type=chatis forwarded to the message chain; other types are stored for retrieval.GET /api/integrations/outbox?source=<source>– Retrieve queued messages for a given integration source (clears the queue on read). Usesource=matefor Mate Engine clients.
Plugins
A convenience plugin, plugins/mate_engine.py, is provided as an optional integration helper. It exposes actions that LLMs can call and implements policy-sensitive behaviour such as promotion of temporary uploads:
send_mate_message– Enqueue a message to the Mate outbox (source=”mate”).promote_upload– Promote a temporary upload into a skin (requiresSYNTH_MATEENGINE_PROMOTE_ENABLED=1to permit promotion).
Set SYNTH_MATEENGINE_PROMOTE_ENABLED=1 to enable promotion from uploads into person skins (default: disabled).
Mate Engine Flags
SYNTH_MATEENGINE_UPLOAD_TTL_DAYS– Days before temporary uploads are removed (default: 7)SYNTH_MATEENGINE_UPLOAD_CLEANUP_INTERVAL_S– Cleanup interval in seconds (default: 3600)SYNTH_MATEENGINE_PROMOTE_ENABLED– Set to1to allow promotion of uploads
OpenAI-Compatible Server
The OpenAI-compatible API server exposes Synthetic Heart through a standard OpenAI-style HTTP surface. For backward compatibility it also mirrors the legacy REST API used by ollama, so any tool that can talk to an OpenAI endpoint—or to a local Ollama daemon—can point at SyntH and receive the responses generated by your active persona.
What it does
Implements
/api/generateand/api/chatwith streaming NDJSON output.Mirrors the legacy
/api/tagsendpoint so discovery requests return a synthetic model catalogue.Translates incoming prompts into the synth message chain, letting the currently loaded Cortex engine drive the reply.
Configuration
OLLAMA_HOST=0.0.0.0 # Bind address for the compatibility server
OPENAI_API_SERVER_PORT=11435 # Default Ollama port; update if you already run a native instance
OLLAMA_DEFAULT_MODEL=SyntH # Name reported to clients when no model is specified
OLLAMA_DEFAULT_MODEL_DISPLAY="Synthetic Heart" # Friendly label in /api/tags
OLLAMA_MAX_HISTORY=20 # Conversation turns preserved between requests
OLLAMA_STREAM_TIMEOUT=10.0 # Seconds to wait between streamed chunks before timing out
OLLAMA_COMPLETION_TIMEOUT=0 # Optional deadline for non-streaming calls (0 disables)
Usage
Start SyntH with the interface enabled (it registers automatically when the
interface/openai_api_server/package is present).Point an OpenAI-compatible (or Ollama) client at your synth instance:
export OLLAMA_HOST=http://<synth-host>:11435 # any OpenAI-compatible or Ollama client can now list and chat with SyntH
Any third-party application that supports the OpenAI REST API (or the legacy Ollama REST API) can reuse the same base URL. This makes it simple to integrate synth with dashboards, IDEs, or automation frameworks.
Because the server streams responses as soon as the persona produces them, end users get the familiar chat experience while benefiting from SyntH’s plugin ecosystem, persona memory, and dispatcher logic.
Interface Registration System
Interfaces are automatically discovered and integrated:
Directory Scanning: Core scans
interface/for Python modulesClass Discovery: Files checked for
INTERFACE_CLASSorPLUGIN_CLASSRegistration: Interfaces register with the interface registry
Capability Indexing: Supported actions and features are cataloged
Security Setup: Trainer IDs configured from environment variables
Developing Interfaces
Creating a new interface requires implementing the interface contract:
from core.ai_plugin_base import AIPluginBase
from core.core_initializer import register_interface
from core.interfaces_registry import get_interface_registry
class MyInterface(AIPluginBase):
# Declarative "must-have" configuration. The loader checks these keys
# before activating the interface (see "Required Configuration" below).
required_config_vars = ["MYINTERFACE_TOKEN"]
@staticmethod
def get_interface_id() -> str:
"""Return unique interface identifier."""
return "myinterface"
@staticmethod
def get_supported_action_types() -> list[str]:
"""Return action types this interface supports."""
return ["message"]
@staticmethod
def get_supported_actions() -> dict:
"""Return action schemas using the optimized format."""
return {
"message_myinterface": {
"schema": {
"type": "object",
"properties": {
"text": {
"type": "string",
"description": "Message content to send"
},
"interface_path": {
"type": "string",
"description": "Hierarchical interface path (e.g., 'telegram_bot/chat_id/thread_id')"
},
"media": {
"type": "string",
"description": "Optional media attachment URL"
}
},
"required": ["text", "target"]
},
"brief": "Send a message via MyInterface",
"examples": {
"description": "Send a message through MyInterface with optional media attachment.",
"instructions": {
"when_to_use": "Use to communicate through MyInterface channels or direct messages.",
"common_pitfalls": [
"Ensure target exists and is accessible",
"Media URLs must be publicly accessible"
]
},
"examples": [
{
"scenario": "Send text message",
"payload": {
"text": "Hello world!",
"interface_path": "myinterface/channel1"
}
},
{
"scenario": "Send message with media",
"payload": {
"text": "Check this out",
"interface_path": "myinterface/user123",
"media": "https://example.com/image.jpg"
}
}
]
}
}
}
def get_prompt_instructions(self, action_name: str) -> dict:
"""Provide LLM instructions for interface actions."""
if action_name == "message_myinterface":
return {
"description": "Send a message through MyInterface.",
"payload": {
"text": {"type": "string", "description": "Message content"},
"interface_path": {"type": "string", "description": "Hierarchical interface path (e.g., 'myinterface/channel1')"},
"media": {"type": "string", "description": "Optional media URL"}
}
}
return {}
def validate_payload(self, action_type: str, payload: dict) -> list[str]:
"""Validate action payloads."""
errors = []
if action_type == "message_myinterface":
if "text" not in payload:
errors.append("payload.text is required")
if "interface_path" not in payload:
errors.append("payload.interface_path is required")
return errors
async def start(self):
"""Initialize the interface."""
# Register with core systems
register_interface("myinterface", self)
core_initializer.register_interface("myinterface")
# Start your platform connection here
await self.connect_to_platform()
async def connect_to_platform(self):
"""Platform-specific connection logic."""
# Implement platform connection
pass
async def handle_incoming_message(self, bot, message, prompt):
"""Handle incoming messages (if this interface also acts as LLM)."""
# Optional: if interface can also generate responses
pass
# Required: Export the interface class
INTERFACE_CLASS = MyInterface
Required Configuration (required_config_vars)
Most interfaces are useless without at least one secret (a bot token, an access token, credentials, …). Rather than letting an interface half-start and flood the LLM prompt with actions it can never actually perform, an interface simply declares which config keys are indispensable and lets the loader enforce them. The interface performs no gating itself — it only declares intent.
How to declare
Add a required_config_vars class attribute — an iterable of config-registry
keys. Each entry can be one of two forms:
a plain string — that key must be present (AND semantics), or
a tuple / list — an OR group: at least one member must be present.
class MyInterface(AIPluginBase):
# AND: every plain-string key is mandatory.
# OR: the tuple is satisfied if *any* of its members is set.
required_config_vars = [
"MYINTERFACE_USER", # required outright
("MYINTERFACE_PASSWORD", "MYINTERFACE_TOKEN"), # need one of the two
]
How the loader enforces it
At registration time core_initializer calls
_missing_required_config_vars(interface_instance), which resolves every
declared key through config_registry.get_value(...). A value that is
None or an empty/whitespace string counts as missing. Then:
All present → the interface is loaded normally and its actions become available to the LLM.
Something missing → the interface is not loaded: it is not added to
active_interfacesand none of its actions are registered, so they never reach the prompt. The component is still tracked and markedFAILEDwith a reason likeMissing required configuration: MYINTERFACE_USER, MYINTERFACE_PASSWORD or MYINTERFACE_TOKEN— this shows up as a red LED in the WebUI Interfaces section (the interface stays visible, it is not hidden).
Because the gate runs in the loader, the interface constructor is free to behave
as usual (for example is_enabled may still default to True) — the
must-have check is orthogonal to the interface’s own enable/disable logic. The
action parser additionally filters both action-collection passes by
core_initializer.active_interfaces, so an interface that failed the gate can
never leak schemas into the prompt.
Real examples in the tree
Interface |
|
|---|---|
Telegram ( |
|
Discord ( |
|
Fluxer ( |
|
Matrix ( |
|
Matrix shows the mixed AND + OR case: it needs its MXID (MATRIX_USER) and
either a password or an access token to log in. The homeserver key is not
listed because it ships with a non-empty default and is therefore always
“present”.
Guidelines
Declare only what is genuinely indispensable to operate — do not over-gate. Keys that have a sensible non-empty default do not belong here (they always resolve as present).
Prefer an OR group over duplicating logic when a platform accepts alternative credentials (password or token).
Omit the attribute entirely (or set it to an empty list) for interfaces that need no secrets — e.g. the local CLI. Such interfaces are never gated.
Interface Actions
Interfaces can provide actions that LLMs can invoke:
Message Sending:
{
"type": "message_telegram_bot",
"payload": {
"text": "Hello from synth!",
"interface_path": "telegram_bot/123456789/2"
}
}
Media Handling:
{
"type": "send_media_discord",
"payload": {
"file_url": "https://example.com/image.png",
"interface_path": "discord_interface/987654321/123"
}
}
Security and Validation
Trainer ID Validation:
Interfaces validate that sensitive operations come from authorized users:
TRAINER_IDS=telegram_bot:123456789,discord_interface:987654321
Rate Limiting:
Built-in rate limiting prevents abuse:
Per-user rate limits
Burst protection
Platform-specific constraints
Input Validation:
All inputs are validated before processing:
Payload schema validation
Type checking
Content filtering
Best Practices
- Action Schema Design
Use the new three-tier action format for optimal prompt efficiency. See Action Schema Format for details.
- Error Handling
Implement comprehensive error handling with user feedback.
- Async Operations
Use async methods for all I/O operations.
- Security First
Always validate trainer permissions for sensitive actions.
- Platform Limits
Respect platform rate limits and content policies.
- Documentation
Provide clear action schemas and examples in the
examplestier.
For complete implementations, examine interface/telegram_bot.py or interface/discord_interface.py in the repository.