Overview
FERAL uses two WebSocket endpoints:| Endpoint | Port | Purpose |
|---|---|---|
/v1/session | 9090 | Client connections (dashboard, desktop, mobile) |
/v1/node | 9091 | Hardware node connections (wristband, glasses, robots) |
FeralMessage frames.
FeralMessage Format
Every message over either WebSocket follows this envelope:| Field | Type | Description |
|---|---|---|
id | string | Unique message ID (UUID or prefixed) |
type | string | Message type (see tables below) |
timestamp | ISO 8601 | When the message was created |
source | string | Sender identifier (dashboard, brain, wristband_a3f2, etc.) |
target | string | Intended recipient (brain, dashboard, * for broadcast) |
payload | object | Type-specific data |
metadata | object | Optional context (session ID, trace ID, etc.) |
Client Protocol (/v1/session)
Connection Lifecycle
Client → Brain Message Types
| Type | Description | Payload |
|---|---|---|
text_command | Text input from the user | { "text": "..." } |
audio_chunk | Streamed audio bytes (base64) | { "data": "...", "format": "pcm_16k" } |
audio_end | End of audio stream | {} |
sdui_action | User clicked an SDUI button/form | { "component_id": "...", "action": "...", "value": "..." } |
approval_response | User approved/denied an action | { "request_id": "...", "approved": true } |
context_update | Client sends ambient context (screen, location) | { "screen": "...", "location": {...} } |
Brain → Client Message Types
| Type | Description | Payload |
|---|---|---|
text_response | Text reply from the brain | { "text": "...", "sources": [...] } |
text_delta | Streaming text token | { "delta": "..." } |
audio_chunk | Streamed audio response (base64) | { "data": "...", "format": "pcm_16k" } |
audio_end | End of audio response | {} |
sdui | Server-driven UI component | { "component": "chart", "props": {...} } |
approval_request | Action needs user approval | { "request_id": "...", "action": "...", "risk": "medium" } |
status_update | Brain state change | { "event": "...", "data": {...} } |
error | Error message | { "code": "...", "message": "..." } |
Hardware Protocol (/v1/node)
Connection Lifecycle
Node → Brain Message Types
| Type | Description |
|---|---|
node_register | Device manifest on connect |
sensor_data | Periodic sensor readings |
command_result | Response to a brain command |
node_status | Battery, connectivity, error states |
Brain → Node Message Types
| Type | Description |
|---|---|
node_accepted | Registration acknowledged |
device_command | Command to execute (move, grip, set_light, etc.) |
config_update | Push new settings to the device |
ping | Keep-alive (node must respond with pong) |
Example: Full Client Conversation
Keep-Alive
Both protocols use ping/pong frames. The brain sends aping every 30 seconds. Nodes and clients must respond within 10 seconds or the connection is considered dead.