# Purpose of the HTTP and Socket.IO Transport Layer in OpenHuman Core

> Understand the HTTP and Socket.IO transport layer in OpenHuman Core. It uses dual sockets for RPC commands via HTTP and real-time events via WebSocket, enhancing frontend performance.

- Repository: [Tiny Humans/openhuman](https://github.com/tinyhumansai/openhuman)
- Tags: internals
- Published: 2026-08-26

---

**The HTTP and Socket.IO transport layer in OpenHuman implements a dual-socket architecture that separates synchronous command execution from real-time event streaming, allowing the React/Tauri frontend to invoke RPC methods over HTTP while receiving asynchronous state updates via WebSocket.**

The `tinyhumansai/openhuman` repository implements a Rust-based core process that must communicate bidirectionally with a React and Tauri desktop interface. To handle both request-response commands and continuous data streams without blocking, the core exposes two complementary transport mechanisms: an **HTTP JSON-RPC** endpoint for control operations and a **Socket.IO** channel for real-time events.

## Dual-Socket Architecture Overview

OpenHuman’s transport layer follows a **control plane / data plane** separation. The HTTP transport serves as the control plane, handling isolated, stateless RPC calls that return immediate responses. The Socket.IO transport functions as the data plane, pushing high-frequency updates—including chat turns, tool-result deltas, and approval requests—to connected clients without polling.

This design prevents long-running streams from blocking command execution. When the core processes a tool invocation, the HTTP request returns immediately while the actual progress streams through the Socket.IO connection.

## HTTP JSON-RPC Transport for Synchronous Commands

The HTTP transport exposes the core’s RPC methods at the `/rpc` endpoint using the JSON-RPC 2.0 protocol. This provides a simple request-response API that the Tauri frontend consumes through the `relay_http_rpc` command, which forwards browser-side requests to the Rust core.

The endpoint handles actions such as fetching configuration, starting conversation turns, and invoking tools. Each call is dispatched through the core’s internal JSON-RPC handler implemented in [`src/core/jsonrpc.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/core/jsonrpc.rs), returning structured responses to the caller.

### Implementation Details

In [`src/core/jsonrpc.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/core/jsonrpc.rs), the core initializes an HTTP listener that routes incoming POST requests to the appropriate internal controllers. The React frontend accesses this through [`coreRpcClient.ts`](https://github.com/tinyhumansai/openhuman/blob/main/coreRpcClient.ts), which packages method calls and parameters into JSON-RPC payloads.

For example, initiating a conversation turn requires a single HTTP request:

```typescript
// coreRpcClient.ts – invokes the start_turn RPC method
await coreRpcClient.call('openhuman.turns_start', { 
  thread_id: conversationId, 
  prompt: userMessage 
});

```

The core processes this synchronously and returns the new turn ID, while the actual message streaming occurs over the Socket.IO transport.

## Socket.IO Transport for Real-Time Event Streaming

The Socket.IO transport opens a persistent WebSocket connection at `/socket.io`, enabling the core to broadcast asynchronous events to all connected clients. This mechanism delivers incremental updates for chat messages, tool execution progress, artifact status changes, and security approval requests.

All real-time domain events originate on the core’s internal event bus and bridge to Socket.IO in [`src/core/socketio.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/core/socketio.rs). The central event type, `WebChannelEvent`, defined at line 138, standardizes the payload structure emitted to frontends.

### WebChannelEvent Structure and Broadcasting

The `WebChannelEvent` struct encapsulates events with a namespace, name, and JSON payload. When the core publishes an event, the `socketio` module translates it into a Socket.IO emission. For instance, when a tool requires user approval, the security gate emits an event that propagates to the UI:

```rust
// src/openhuman/security/approval/gate.rs
crate::core::socketio::emit_web_channel_event(WebChannelEvent {
    namespace: "approval".into(),
    name: "request".into(),
    payload: serde_json::json!({ 
        "request_id": request_id, 
        "agent": agent_name 
    }),
});

```

This event flows from the internal bus to the socket bridge at line 34 of [`src/core/socketio.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/core/socketio.rs), which broadcasts it to all connected clients immediately.

## Frontend Integration Patterns

The React frontend consumes both transports through dedicated services. The `coreRpcClient` manages HTTP JSON-RPC calls, while [`services/socketService.ts`](https://github.com/tinyhumansai/openhuman/blob/main/services/socketService.ts) maintains a singleton Socket.IO client that maps incoming `WebChannelEvent` objects to Redux state updates.

When the core emits a tool result delta, the socket service dispatches it to the appropriate slice:

```typescript
// services/socketService.ts
socket.on('tool:result', (event: WebChannelEvent) => {
  // event contains the incremental tool output
  dispatch(updateToolResult(event.payload));
});

```

This architecture ensures the UI remains synchronized with the core’s internal state without blocking the main thread on long-running operations.

## Summary

- OpenHuman uses **HTTP JSON-RPC** at `/rpc` for synchronous command execution (control plane) and **Socket.IO** at `/socket.io` for asynchronous event streaming (data plane).
- The `WebChannelEvent` type in [`src/core/socketio.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/core/socketio.rs) (line 138) standardizes real-time payloads broadcast to the React/Tauri frontend.
- HTTP requests are handled by [`src/core/jsonrpc.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/core/jsonrpc.rs) and consumed via `relay_http_rpc` in Tauri, while Socket.IO events bridge the core’s internal bus to the frontend through [`services/socketService.ts`](https://github.com/tinyhumansai/openhuman/blob/main/services/socketService.ts).
- This dual-socket design prevents blocking: commands return immediately via HTTP while progress streams continuously via WebSocket.

## Frequently Asked Questions

### Why does OpenHuman use two transports instead of a single WebSocket?

Using separate transports decouples command execution from event streaming. HTTP JSON-RPC provides a simple, stateless interface for actions that require immediate confirmation, while Socket.IO handles high-frequency, push-style updates without blocking the request-response cycle. This separation keeps the core responsive when processing long-running tool invocations.

### What is WebChannelEvent in OpenHuman?

`WebChannelEvent` is the core event struct defined at line 138 of [`src/core/socketio.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/core/socketio.rs) that encapsulates all real-time communications between the Rust core and the frontend. It contains a namespace, event name, and JSON payload, standardizing how chat turns, tool results, and approval requests transmit over the Socket.IO connection.

### How does the Tauri frontend communicate with the OpenHuman core?

The Tauri frontend uses two mechanisms: it invokes `relay_http_rpc` to forward JSON-RPC calls to the HTTP endpoint at `/rpc`, and it connects to [`services/socketService.ts`](https://github.com/tinyhumansai/openhuman/blob/main/services/socketService.ts) to receive WebSocket events from `/socket.io`. This dual approach allows the React UI to both command the core and subscribe to its internal event bus.

### Can remote clients connect to OpenHuman's transport layer?

Yes, according to the architecture documentation, remote frontends can connect through the same endpoints used by the local Tauri UI. The HTTP JSON-RPC endpoint and Socket.IO server accept connections from any client that can reach the core’s network interface, enabling remote monitoring and control through the TunnelTransport relay.