API Reference

Wactorz exposes three interfaces: a REST API, a WebSocket bridge, and MQTT pub/sub.


REST API (/api/)

Base URL: http://host/api/ (proxied by nginx from :8080)

Actors

GET /api/actors

List all registered actors.

Response

[
  {
    "id":        "01JQND5X-a1b2c3d4",
    "name":      "main-actor",
    "state":     "running",
    "protected": true,
    "agentType": "orchestrator"
  }
]

GET /api/actors/:id

Get a single actor by ID.

Response — same shape as a single entry from GET /api/actors


POST /api/actors/:id/pause

Pause a running actor.

Response 200 OK on success, 404 if not found, 403 if protected.


POST /api/actors/:id/resume

Resume a paused actor.

Response 200 OK on success.


DELETE /api/actors/:id

Stop and remove an actor.

Response 200 OK on success, 404 if not found, 403 if protected.


Chat

POST /api/chat

Send a message to an actor.

Request body

{
  "to":      "main-actor",
  "content": "What is the weather in Paris?"
}

Response 202 Accepted — message queued. The reply arrives asynchronously via MQTT agents/{id}/chat.


Home Assistant Map

GET /ha-map

Return the latest cached Home Assistant device map snapshot from HomeAssistantMapAgent.

Response 200 OK

{
  "type": "home_assistant_map_update",
  "event_type": "entity_registry_updated",
  "timestamp": 1234567890.0,
  "event": {},
  "devices": []
}

Response 404 Not Found

{
  "error": "Home Assistant map snapshot not available"
}

WebSocket Bridge (/ws)

Connect: ws://host/ws

After connection the server streams every MQTT message as a JSON object:

{
  "topic":   "agents/01JQND5X-a1b2c3d4/heartbeat",
  "payload": {
    "agentId":   "01JQND5X-a1b2c3d4",
    "agentName": "main-actor",
    "state":     "running",
    "timestampMs": 1709500000000
  }
}

MQTT

Broker: mosquitto:1883 (TCP, internal) / ws://host/mqtt (WebSocket via nginx)

All payloads are camelCase JSON.

Topic reference

agents/{id}/spawn

Published by each agent in on_start().

{
  "agentId":     "01JQND5X-a1b2c3d4",
  "agentName":   "main-actor",
  "agentType":   "orchestrator",
  "timestampMs": 1709500000000
}

agents/{id}/heartbeat

Published every heartbeat_interval_secs (default 10 s).

{
  "agentId":     "01JQND5X-a1b2c3d4",
  "agentName":   "main-actor",
  "state":       "running",
  "timestampMs": 1709500000000
}

agents/{id}/status

Published on state changes.

{
  "agentId":     "01JQND5X-a1b2c3d4",
  "state":       "paused",
  "timestampMs": 1709500000000
}

agents/{id}/alert

Published by MonitorAgent (stale actor) or QAAgent (policy violation).

{
  "agentId":     "01JQND5X-a1b2c3d4",
  "severity":    "error",
  "message":     "Agent has not sent a heartbeat in 60s",
  "timestampMs": 1709500000000
}

severity values: info | warning | error | critical


agents/{id}/chat

Chat message to or from an agent.

{
  "id":          "WID-abc123",
  "from":        "main-actor",
  "to":          "user",
  "content":     "Here is the weather forecast…",
  "timestampMs": 1709500000000
}

system/health

Published by MonitorAgent on every heartbeat tick.

{
  "agentCount":  6,
  "staleAgents": [],
  "timestampMs": 1709500000000
}

system/spawn

Published when a DynamicAgent is created (alias for agents/{id}/spawn on the system/ prefix).


io/chat ← inbound from browser

The fixed topic the frontend IO bar publishes to.

{
  "from":        "user",
  "content":     "@nautilus-agent ping deploy@myserver.com",
  "timestampMs": 1709500000000
}

The MQTT event loop routes this to IOAgent's mailbox, which parses the @mention and forwards the message body to the target actor.


Error handling

HTTP status Meaning
200 Success
202 Accepted (async, e.g. chat)
404 Actor not found
403 Actor is protected
500 Internal server error

MQTT errors are published as agents/{id}/alert with severity: error.