# How the Tauri Desktop Shell Communicates with the Rust Core in OpenHuman

> Discover how OpenHuman's Tauri desktop shell uses a hybrid IPC architecture with native commands, JSON-RPC, and Socket.IO to communicate with its Rust core.

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

---

**The Tauri desktop shell communicates with the Rust core in OpenHuman through a hybrid IPC architecture that combines native Tauri commands for OS-level operations, an embedded HTTP JSON-RPC server for business logic, and a Socket.IO bridge for real-time events.**

The `tinyhumansai/openhuman` repository implements a modern desktop architecture using **Tauri v2** to host a React frontend alongside the `openhuman-core` Rust engine. Understanding how the Tauri desktop shell communicates with the Rust core is essential for developers extending the platform, as the architecture cleanly separates platform-specific shell duties from core business logic execution through multiple specialized channels.

## The Communication Architecture

OpenHuman employs four distinct communication channels between the TypeScript frontend and Rust backend, each optimized for specific interaction patterns. This design allows the core to run headless while enabling rich desktop integration when the Tauri shell is present.

### Native Tauri Commands for OS Integration

The Tauri host exposes platform capabilities through Rust functions decorated with `#[tauri::command]` in [`app/src-tauri/src/lib.rs`](https://github.com/tinyhumansai/openhuman/blob/main/app/src-tauri/src/lib.rs). These commands handle window management, hotkey registration, deep-link processing, and secure credential retrieval. The frontend invokes these via the `invoke()` API wrapped in `app/src/services/tauriCommands`.

Key commands include `core_rpc_url` and `core_rpc_token`, which return the local endpoint address and bearer token required for JSON-RPC authentication. This pattern ensures sensitive credentials never transit through the JavaScript context unprotected.

### Embedded JSON-RPC Server Process

The core business logic runs inside an embedded Tokio task spawned by `CoreProcessHandle::start()` in [`app/src-tauri/src/core_process.rs`](https://github.com/tinyhumansai/openhuman/blob/main/app/src-tauri/src/core_process.rs). This function initializes the OpenHuman core and calls `run_server_embedded_with_ready()` from [`src/core/jsonrpc.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/core/jsonrpc.rs), binding a JSON-RPC server to localhost port 7788 by default.

Unlike traditional multi-process desktop applications, the core runs within the same OS process as the Tauri shell but on a separate async runtime, minimizing memory overhead while maintaining logical separation. The server accepts standard JSON-RPC 2.0 requests over HTTP, enabling the frontend to execute methods like `chat.sendTurn` or `tools.list` via standard `fetch()` calls.

### HTTP Relay for Untrusted Origins

When connecting to external core instances—such as LAN-hosted servers or remote headless deployments—the application uses the `relay_http_rpc` Tauri command implemented in [`app/src-tauri/src/lib.rs`](https://github.com/tinyhumansai/openhuman/blob/main/app/src-tauri/src/lib.rs). This command receives JSON-RPC payloads from the renderer, forwards them via `reqwest` from the trusted host context, and returns raw responses.

This relay pattern prevents the web-based frontend from directly contacting potentially untrusted origins, allowing the Rust shell to enforce CORS policies, certificate validation, and additional request filtering before forwarding.

### Socket.IO Event Bridge

For push-style notifications and asynchronous state updates, the core publishes events through an internal bus defined in [`src/core/socketio.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/core/socketio.rs). The Tauri host subscribes to these events and forwards them to the renderer through the Socket.IO client connection managed in [`app/src/services/socketService.ts`](https://github.com/tinyhumansai/openhuman/blob/main/app/src/services/socketService.ts).

This enables real-time features such as overlay attention signals, tool completion notifications, and memory state updates without requiring the frontend to poll the JSON-RPC endpoint.

## Implementation Examples

The following code examples demonstrate the concrete implementations of these communication patterns according to the OpenHuman source code.

### Starting the Embedded Core

The Tauri side initiates the core process using the builder pattern and embedded server runner:

```rust
// app/src-tauri/src/core_process.rs
pub async fn start_core_process(app_handle: tauri::AppHandle) -> Result<(), tauri::Error> {
    let core_handle = openhuman_core::CoreBuilder::new()
        .workspace(openhuman_core::Workspace::Ephemeral)
        .access(openhuman_core::Access::full())
        .build()
        .await?;

    openhuman_core::core::jsonrpc::run_server_embedded_with_ready(
        core_handle,
        |_| {} // ready callback
    )
    .await?;
    Ok(())
}

```

### Retrieving RPC Credentials

The frontend obtains the endpoint URL and authentication token through typed Tauri command wrappers:

```typescript
// app/src/services/coreRpcClient.ts
export async function getRpcEndpoint() {
  const [url, token] = await Promise.all([
    invoke<string>('core_rpc_url'),   // Tauri command in lib.rs
    invoke<string>('core_rpc_token'), // Tauri command in lib.rs
  ]);
  return { url, token };
}

```

### Executing JSON-RPC Methods

Standard business logic calls use the HTTP client with bearer token authentication:

```typescript
// app/src/services/coreRpcClient.ts
export async function callRpcMethod<T>(method: string, params: unknown) {
  const { url, token } = await getRpcEndpoint();
  const resp = await fetch(`${url}/${method}`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${token}`,
    },
    body: JSON.stringify({ jsonrpc: '2.0', id: 1, method, params }),
  });
  const json = await resp.json();
  return json.result as T;
}

// Example usage: sending a chat turn
export const sendTurn = (message: string) =>
  callRpcMethod<{ reply: string }>('chat.sendTurn', { message });

```

### Secure Relay for External Cores

For untrusted origins, the frontend delegates the HTTP request to the Rust host:

```typescript
// Fallback for external core instances
if (!isTrustedOrigin(rpcUrl)) {
  const result = await invoke('relay_http_rpc', {
    method: 'chat.sendTurn',
    params: { message },
    url: rpcUrl,
    token,
  });
  return result;
}

```

### Handling Real-Time Events

The Socket.IO client subscribes to core-emitted events for reactive UI updates:

```typescript
// app/src/services/socketService.ts
import { io } from 'socket.io-client';

const socket = io('http://127.0.0.1:7788');

socket.on('runtime:socket-state-changed', (data) => {
  console.log('Core state update:', data);
});

```

## Summary

- **Tauri commands** in [`app/src-tauri/src/lib.rs`](https://github.com/tinyhumansai/openhuman/blob/main/app/src-tauri/src/lib.rs) handle OS-level operations and secure credential retrieval, invoked via the frontend's `invoke()` API.
- **CoreProcessHandle** in [`app/src-tauri/src/core_process.rs`](https://github.com/tinyhumansai/openhuman/blob/main/app/src-tauri/src/core_process.rs) spawns the Rust core as an embedded Tokio task, exposing business logic via JSON-RPC on a local port.
- **HTTP JSON-RPC** serves as the primary data exchange protocol, authenticated via bearer tokens retrieved through Tauri commands, as implemented in [`app/src/services/coreRpcClient.ts`](https://github.com/tinyhumansai/openhuman/blob/main/app/src/services/coreRpcClient.ts).
- **Relay commands** provide a secure proxy mechanism for connecting to remote core instances without exposing the frontend to untrusted origins, utilizing the `relay_http_rpc` command.
- **Socket.IO** enables bidirectional event streaming for real-time updates from [`src/core/socketio.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/core/socketio.rs) to the React frontend via [`app/src/services/socketService.ts`](https://github.com/tinyhumansai/openhuman/blob/main/app/src/services/socketService.ts).

## Frequently Asked Questions

### Why does OpenHuman use HTTP instead of Tauri's native IPC for core communication?

OpenHuman uses HTTP JSON-RPC for core communication to enable **headless deployment scenarios** where the core runs without the Tauri shell, such as in CI environments or remote servers. The embedded server approach in [`src/core/jsonrpc.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/core/jsonrpc.rs) allows the same business logic to serve both desktop and headless clients while maintaining compatibility with standard JSON-RPC tooling and debugging proxies.

### How does the application maintain security when calling external core instances?

When the RPC URL points to an external origin, the application invokes the `relay_http_rpc` Tauri command instead of direct `fetch()` calls. This command executes the HTTP request from the Rust host context using `reqwest`, preventing the webview from contacting untrusted servers directly and allowing the shell to enforce certificate validation and request filtering before forwarding payloads.

### What triggers the Socket.IO connection between the core and the frontend?

The Socket.IO connection initializes when the frontend loads and connects to the port exposed by the core's internal event bus defined in [`src/core/socketio.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/core/socketio.rs). The core publishes lifecycle events, tool execution updates, and notification signals on this bus, which the Tauri host forwards to the renderer, enabling reactive UI updates without polling the JSON-RPC endpoint.

### Can the core run independently of the Tauri desktop shell?

Yes, the core can run independently because the JSON-RPC server implementation in [`src/core/jsonrpc.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/core/jsonrpc.rs) supports standalone execution via `run_server_embedded_with_ready()` or equivalent standalone runners. This architecture allows the `openhuman-core` crate to function as a headless server while the Tauri shell remains optional for desktop GUI interactions, facilitating server-side automation and remote deployments.