Interfaces
Wactorz supports multiple user-facing interfaces simultaneously. All of them funnel messages into the same MainActor.process_user_input() pipeline — switching interface only changes how you reach the system, not how it behaves.
Overview
| Interface | Flag | Extra dep | Notes |
|---|---|---|---|
| CLI | --interface cli |
— | Default. Interactive terminal with streaming. |
| REST | --interface rest |
— | HTTP API, suitable for programmatic access. |
| MCP | separate wactorz-mcp process |
wactorz[mcp] |
Model Context Protocol tools for MCP clients. |
| Discord | --interface discord |
wactorz[discord] |
Bot responds in channels and DMs. |
--interface whatsapp |
wactorz[whatsapp] |
Via Twilio Messaging. | |
| Telegram | --interface telegram |
— | Bot API, polling mode. |
| Web UI | (always on) | — | Dashboard at localhost:8888. Disable with --no-monitor. |
💡 Multiple interfaces — Only one chat interface can be active at a time (set via
--interface), but the Web UI dashboard always runs alongside it unless disabled.
CLI [built-in]
Flag: --interface cli
| default | yes |
| streaming | yes |
| class | CLIInterface |
The default interface. Starts an interactive terminal session where you type messages and receive streamed responses. Supports all Wactorz commands and @agent-name mentions.
wactorz
wactorz --interface cli --llm gemini
Special commands
/help — list available commands
/rules — show active pipeline rules
/rules delete <id> — stop and remove a pipeline rule
/memory — show stored user facts
/memory clear — wipe memory
/webhook discord <url> — store a Discord webhook URL
@agent-name <payload> — send directly to a named agent
REST API [built-in]
Flag: --interface rest
| default port | 8000 |
| class | RESTInterface |
| auth | optional API key |
Exposes Wactorz as an HTTP API. Suitable for integrating with other services, running automated tests, or building custom frontends.
wactorz --interface rest --port 8000
Endpoints
| Method | Path | Description |
|---|---|---|
POST |
/chat |
Send a message. Body: {"message": "..."}. Returns streamed or buffered response. |
GET |
/agents |
List all registered agents with their status. |
GET |
/health |
System health check. |
Authentication
Set API_KEY in your .env to require an API key on all requests:
API_KEY=my-secret-key
curl -X POST http://localhost:8000/chat \
-H "X-API-Key: my-secret-key" \
-H "Content-Type: application/json" \
-d '{"message": "turn off the lights"}'
MCP Server [requires extra]
Command: wactorz-mcp
| dep | pip install wactorz[mcp] |
| transport | stdio |
| class | FastMCP server in wactorz.interfaces.mcp_server |
| backend | Wactorz REST API at WACTORZ_URL |
The MCP server exposes Wactorz as tools and resources for MCP-compatible clients such as Claude Desktop, Cursor, Zed, and the MCP Inspector. It is a separate process from the Wactorz runtime: start Wactorz with the REST interface first, then start the MCP server from your MCP client.
# Terminal 1: start Wactorz REST
wactorz --interface rest --port 8000
# Terminal 2: smoke-test MCP tool discovery
python -c "import asyncio, wactorz.interfaces.mcp_server as s; print([t.name for t in asyncio.run(s.mcp.list_tools())])"
If your editable install does not have a wactorz-mcp script yet, use the module form:
python -m wactorz.interfaces.mcp_server
Configuration
WACTORZ_URL=http://localhost:8000
WACTORZ_API_KEY= # optional; sent as X-API-Key to Wactorz REST
HA_URL=http://homeassistant.local:8123
HA_TOKEN= # optional; enables direct HA tools
Tools
| Tool | Description |
|---|---|
ask_wactorz(message) |
Send a message to the main orchestrator through /chat. |
ask_agent(agent_name, message) |
Send a message to a named agent through /chat. |
list_agents() |
List currently registered agents from /agents. |
list_capabilities(keyword) |
Ask main for the running and spawnable capability catalog. |
stop_agent(agent_id) |
Stop and unregister a non-protected actor via REST. |
pause_agent(agent_id) |
Pause a non-protected actor. |
resume_agent(agent_id) |
Resume a paused actor. |
ha_list_entities(domain) |
List Home Assistant entities directly from HA REST. |
ha_get_state(entity_id) |
Read one Home Assistant entity state. |
ha_call_service(domain, service, entity_id, data_json) |
Call a Home Assistant service directly. |
Resources
| URI | Description |
|---|---|
wactorz://agents |
Current running agents as JSON. |
wactorz://capabilities |
Capability catalog from main. |
wactorz://ha-map |
Latest HA map snapshot from /ha-map. |
wactorz://config |
Sanitized MCP server configuration. |
MCP Inspector
npx @modelcontextprotocol/inspector python -m wactorz.interfaces.mcp_server
Run list_agents, ask_wactorz with /agents, and read wactorz://config first. Try ha_list_entities only after HA_URL and HA_TOKEN are configured and reachable.
Client config example
{
"mcpServers": {
"wactorz": {
"command": "python",
"args": ["-m", "wactorz.interfaces.mcp_server"],
"env": {
"WACTORZ_URL": "http://localhost:8000"
}
}
}
}
Security: Treat MCP clients as privileged. The server can route prompts into Wactorz, manage agents, and, when configured, call Home Assistant services. Do not expose the stdio MCP server directly to the internet.
Discord [requires extra]
Flag: --interface discord
| dep | pip install wactorz[discord] |
| class | DiscordInterface |
Runs Wactorz as a Discord bot. The bot responds to messages in any channel it has access to, and supports DMs. All Wactorz commands and @agent-name routing work identically to the CLI.
wactorz --interface discord --discord-token $DISCORD_BOT_TOKEN
Setup
- Go to discord.com/developers → New Application → Bot
- Enable Message Content Intent under Bot → Privileged Gateway Intents
- Copy the bot token and set it as
DISCORD_BOT_TOKENin your.env - Invite the bot to your server using the OAuth2 URL generator with
botscope andSend Messages+Read Message Historypermissions
Configuration
DISCORD_BOT_TOKEN=MTI4...
DISCORD_PREFIX=! # optional command prefix, default: none (mention or DM)
💡 Webhook notifications — Pipelines can post to Discord independently of the bot using webhook URLs. Store a webhook with
/webhook discord https://discord.com/api/webhooks/...and the planner will inject it into generated notification agents automatically.
WhatsApp [requires extra]
Flag: --interface whatsapp
| dep | pip install wactorz[whatsapp] |
| class | WhatsAppInterface |
| provider | Twilio |
Connects Wactorz to WhatsApp via the Twilio Messaging API. Incoming WhatsApp messages are forwarded to MainActor and replies are sent back to the user's number.
wactorz --interface whatsapp
Setup
- Create a Twilio account and enable the WhatsApp sandbox (or a production number)
- Set the webhook URL in the Twilio console to your public endpoint (e.g. via ngrok during development):
https://your-host/whatsapp/incoming - Add credentials to
.env
Configuration
TWILIO_ACCOUNT_SID=ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
TWILIO_AUTH_TOKEN=your_auth_token
TWILIO_WHATSAPP_NUMBER=whatsapp:+14155238886
Telegram [built-in]
Flag: --interface telegram
| class | TelegramInterface |
| mode | long polling |
Runs Wactorz as a Telegram bot using the Bot API in long-polling mode — no public webhook endpoint required. Works behind NAT and firewalls out of the box.
wactorz --interface telegram --telegram-token $TELEGRAM_BOT_TOKEN
Setup
- Message @BotFather on Telegram →
/newbot - Copy the token and set it as
TELEGRAM_BOT_TOKENin your.env - Start Wactorz — the bot is immediately reachable in any chat or group it's added to
Configuration
TELEGRAM_BOT_TOKEN=1234567890:AAF...
TELEGRAM_ALLOWED_USERS=123456789,987654321 # optional: restrict to user IDs
Web UI Dashboard [built-in]
URL: http://localhost:8888
| default port | 8888 |
| server | aiohttp (monitor_server.py) |
The web dashboard starts automatically alongside whichever chat interface is active. It provides a real-time view of the running system and a chat interface accessible from any browser — no CLI needed.
Features
- Agent status — live heartbeat grid showing every registered actor, its state, and last-seen time
- Log stream — real-time log output from all agents via WebSocket
- Chat — full conversation interface, equivalent to the CLI
- Docs — this documentation, served at
/docs/
# Change dashboard port
wactorz --monitor-port 9000
# Disable dashboard entirely
wactorz --no-monitor
Adding a custom interface
All interfaces implement the same minimal pattern — call process_user_input() and stream or return the result. The simplest possible interface:
class MyInterface:
def __init__(self, main_actor):
self.main = main_actor
async def run(self):
async for message in self._receive_messages():
# Streaming response
async for chunk in self.main.process_user_input_stream(message):
await self._send(chunk)
# Register in cli.py alongside the other interfaces
elif interface == "my-interface":
iface = MyInterface(main_actor)
await asyncio.gather(iface.run(), system.run_forever())
Both process_user_input(text) (returns full reply string) and process_user_input_stream(text) (async generator of chunks) are available on MainActor.