Host Control WebSocket API Guide
The Host Control WebSocket API is the browser and outside-runtime integration boundary exposed by the control backend.
Use it for dashboards, package frontends, monitoring tools, and other clients that should not join native Librux transport directly. Native subsystems should use the Subsystem SDK API.
This is the supported integration path for browser clients, packaged frontends, Windows/macOS tools, cloud services, and other non-Librux clients. Those clients connect to a Librux host through the control backend instead of opening native runtime transport.
This page explains the WebSocket flow. For the table-oriented endpoint and message catalog, see Host Control WebSocket Messages.
Endpoints
| Path | Direction | Purpose |
|---|---|---|
/api/v1/ws/events |
server stream with client subscription commands | Observe Event channels |
/api/v1/ws/control |
request/response messages | Invoke Procedure and Operation calls through the host control backend |
The same endpoints are available under the stable product-facing prefix.
/api/v1/ws/events and /api/v1/ws/control.
Both endpoints are protected by the same security policy as REST routes. Browser clients use the Web Console session cookie. External clients should use an API key header during the WebSocket handshake.
When security is enabled, /api/v1/ws/events is available to authenticated clients and
/api/v1/ws/control requires an operator or admin role.
/api/v1/ws/events
/api/v1/ws/events is subscribe-only. It observes native Event channels and streams
matching messages to the browser-facing client.
Subscribe
{
"kind": "subscribe",
"topic": "example/status"
}
or.
{
"kind": "subscribe",
"topics": ["example/status", "example/state"]
}
Response example.
{
"kind": "subscribed",
"ok": true,
"topics": ["example/status"]
}
For all Event socket message kinds, see Host Control WebSocket Messages.
Unsubscribe
{
"kind": "unsubscribe",
"topic": "example/status"
}
Response example.
{
"kind": "unsubscribed",
"ok": true,
"topics": ["example/status"]
}
Clear
{
"kind": "clear"
}
Response example.
{
"kind": "cleared",
"ok": true
}
Event Message
{
"kind": "event",
"topic": "example/status",
"publisher": "controller",
"ts": 1234567890,
"payload_b64": "...",
"data": "...",
"payload_text": "{\"state\":\"running\"}",
"payload_json": {"state": "running"}
}
data is currently the same base64 payload as payload_b64 for browser
compatibility. Prefer payload_b64 for new clients.
There is no WebSocket Event publish path. Browser clients observe Event traffic; they do not inject native Event samples into the runtime through this endpoint.
/api/v1/ws/control
/api/v1/ws/control is a request/response facade over the native control path.
The browser does not call the timed exchange runtime directly. The control backend resolves the target subsystem and invokes Procedure or Operation through the native runtime boundary.
Ping
{
"kind": "ping",
"request_id": "client-1"
}
Response example.
{
"kind": "pong",
"ok": true,
"request_id": "client-1"
}
Procedure Call
{
"kind": "procedure.call",
"request_id": "req-1",
"target": "io_gateway",
"procedure": "set_output",
"params": {"index": 1, "value": true},
"timeout_ms": 1000
}
Response example.
{
"kind": "procedure.response",
"request_id": "req-1",
"target": "io_gateway",
"procedure": "set_output",
"ok": true,
"result": {"value": true},
"error_code": null,
"error_message": null
}
Operation Start
{
"kind": "operation.start",
"request_id": "op-1",
"target": "arm",
"operation": "move_j",
"params": {"positions": [0.0, 0.1, 0.2]},
"timeout_ms": 1000
}
Response example.
{
"kind": "operation.start.response",
"request_id": "op-1",
"target": "arm",
"operation": "move_j",
"ok": true,
"accepted": true,
"operation_id": "runtime-operation-id",
"state": "accepted",
"error_code": null,
"error_message": null
}
Operation Query
{
"kind": "operation.query",
"request_id": "op-query-1",
"target": "arm",
"operation_id": "runtime-operation-id",
"timeout_ms": 1000
}
Response example.
{
"kind": "operation.query.response",
"request_id": "op-query-1",
"target": "arm",
"ok": true,
"operation_id": "runtime-operation-id",
"operation": "move_j",
"state": "running",
"cancel_requested": false,
"feedback_count": 3,
"result": null,
"state_payload": {"progress": 0.3},
"created_ts": 1234567890,
"updated_ts": 1234567999,
"error_code": null,
"error_message": null
}
Operation Cancel
{
"kind": "operation.cancel",
"request_id": "op-cancel-1",
"target": "arm",
"operation_id": "runtime-operation-id",
"timeout_ms": 1000
}
The response shape matches operation.query.response with
kind="operation.cancel.response".
For all Control socket request and response kinds, see Host Control WebSocket Messages.
Error Response
Unsupported or invalid requests return an error response.
{
"kind": "error",
"request_id": "req-1",
"ok": false,
"error": "unsupported kind: example"
}
Boundary Rule
This WebSocket API is an outside-runtime facade.
/api/v1/ws/eventsobserves Event traffic/api/v1/ws/controlinvokes ordinary Procedure and Operation calls- timed execution is not exposed as a direct WebSocket control feature
- native hot-path communication remains under Event, Control, Procedure, and Operation in the SDK
- clients that need native timed exchange should be implemented as Librux subsystems on a supported Linux runtime host
- clients that stay outside the native runtime should use this API rather than reimplementing native transport
For architecture context, see WebSocket Facade.