# Tauri Desktop Shell vs Core Rust Crate Separation in OpenHuman

> Discover how OpenHuman separates its Tauri desktop shell from its core Rust crate using a JSON-RPC bridge. Learn how this enables a thin UI host and headless business logic implementation.

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

---

**OpenHuman splits its Tauri desktop shell from its core Rust crate using a JSON-RPC bridge, allowing the UI to run as a thin host while the core implements all business logic headlessly.**

The OpenHuman project by TinyHumansAI follows a clean architectural pattern common in modern Rust applications: the user-facing desktop interface and the application logic live in entirely separate layers. This separation enables headless deployments, independent updates, and strict security boundaries.

---

## Architectural Overview

OpenHuman divides responsibilities between two distinct layers:

| Layer | Responsibility |
|-------|----------------|
| **Tauri Desktop Shell** | Hosts React UI, manages window lifecycle, spawns and monitors core process, provides RPC bridge |
| **Core Rust Crate** | Implements all domains (agents, memory, tools, security), exposes JSON-RPC server, runs headless |

The Tauri shell in `app/src-tauri/` never directly accesses core internals. Instead, it launches the core as a subprocess and communicates exclusively through a JSON-RPC channel.

---

## The Tauri Desktop Shell Layer

The shell's primary job is to provide a native desktop window for the React frontend while acting as a dumb pipe to the core.

### Key Source Files

- [`app/src-tauri/tauri.conf.json`](https://github.com/tinyhumansai/openhuman/blob/main/app/src-tauri/tauri.conf.json) – Tauri configuration and build settings
- [`app/src-tauri/src/lib.rs`](https://github.com/tinyhumansai/openhuman/blob/main/app/src-tauri/src/lib.rs) – Tauri command definitions exposed to the frontend
- [`app/src-tauri/src/core_process.rs`](https://github.com/tinyhumansai/openhuman/blob/main/app/src-tauri/src/core_process.rs) – Core process spawning and lifecycle management

### Core Process Spawning

The shell starts the core via the `start_core_process` command defined in [`app/src-tauri/src/lib.rs`](https://github.com/tinyhumansai/openhuman/blob/main/app/src-tauri/src/lib.rs):

```rust
// app/src-tauri/src/lib.rs
#[tauri::command]
pub async fn start_core_process(state: State<'_, AppState>) -> Result<(), String> {
    // Spawn the core as an async task
    let core_handle = core_process::CoreProcessHandle::spawn().await?;
    state.set_core_handle(core_handle);
    Ok(())
}

```

This async command creates a `CoreProcessHandle` that runs the core binary as a managed subprocess. The shell then reads a bearer token from a temporary file (via `core_rpc_token`) to authenticate subsequent RPC calls.

### RPC Bridging

The shell exposes a thin JSON-RPC relay to the UI:

```typescript
// app/src/lib/coreRpcClient.ts
export async function coreRpc<T>(method: string, params: any): Promise<T> {
  // Tauri-provided invoke bridges to the Rust command
  return invoke('core_rpc', { method, params });
}

```

The corresponding Rust implementation in [`app/src-tauri/src/core_rpc.rs`](https://github.com/tinyhumansai/openhuman/blob/main/app/src-tauri/src/core_rpc.rs) forwards these calls to the running core process over HTTP.

---

## The Core Rust Crate Layer

The core crate at the repository root contains all business logic in pure Rust, with no Tauri dependencies. It can run headlessly via CLI, Docker, or cloud deployment.

### Key Source Files

- [`src/lib.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/lib.rs) – Crate entry point; builds `CoreBuilder` and publishes RPC server
- [`src/core/mod.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/core/mod.rs) – Core runtime, dispatcher, and subsystem registration
- [`src/core/jsonrpc.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/core/jsonrpc.rs) – JSON-RPC request handling
- [`src/embed/mod.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/embed/mod.rs) – Public `Harness::builder` API for host configuration

### JSON-RPC Server Implementation

The core exposes its functionality through a typed JSON-RPC server in [`src/core/jsonrpc.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/core/jsonrpc.rs):

```rust
// src/core/jsonrpc.rs
pub async fn handle_rpc(req: RpcRequest) -> Result<RpcResponse, RpcError> {
    match req.method.as_str() {
        "tools.run_tool" => tools::run_tool(req.params).await,
        // … other methods
        _ => Err(RpcError::MethodNotFound),
    }
}

```

The core implements domains including agents, memory, tools, and security. The **Harness** runs conversation turns, the **Embed** layer exposes typed APIs, and the **Runtime** manages background services.

### Event Broadcasting Back to UI

Core-generated events flow back to the desktop UI through Socket.IO bridging:

```rust
// src/core/socketio.rs
pub fn broadcast_attention(event: AttentionEvent) {
    // The Tauri shell subscribes to this event name
    emit_to_all("runtime:attention", serde_json::to_value(event).unwrap());
}

```

The shell listens for these events through Tauri's event system (`window.emit`) and forwards them to the React frontend.

---

## How the Layers Communicate

The Tauri desktop shell and core Rust crate establish communication through a multi-step handshake:

1. **Process Launch** – Shell calls `start_core_process`, which spawns the core binary
2. **Authentication** – Core writes bearer token to temp file; shell reads via `core_rpc_token`
3. **Request Flow** – UI → `core_rpc` Tauri command → `relay_http_rpc` → core's `/rpc` endpoint
4. **Event Flow** – Core emits via Socket.IO → Tauri event system → React frontend

This HTTP-over-localhost approach keeps boundaries explicit. The shell's `core_rpc` implementation maintains an allow-list of safe methods (primarily `tools.*` namespaced calls), preventing untrusted UI code from accessing sensitive core internals.

---

## Benefits of the Separation

This Tauri shell and core crate split delivers concrete engineering advantages:

- **Isolation** – React/TypeScript UI code never directly touches core internals; only RPC methods are exposed
- **Modularity** – Same core runs headless without any UI dependencies
- **Security** – Shell controls RPC surface area through explicit method allow-listing
- **Upgradability** – Core binary updates independently; shell simply reloads new binary
- **Testability** – Core logic tested without heavy desktop automation

---

## Summary

- OpenHuman's **Tauri desktop shell** in `app/src-tauri/` hosts the React UI and manages the core lifecycle without containing business logic
- The **core Rust crate** at the repository root implements all domains and exposes a JSON-RPC server via [`src/core/jsonrpc.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/core/jsonrpc.rs)
- Communication uses HTTP JSON-RPC with bearer token authentication, not shared memory or direct linking
- The `core_rpc` bridge in the shell filters exposed methods for security
- Core events return to the UI through Socket.IO bridging to Tauri's event system
- This architecture enables headless deployments and independent versioning of shell and core

---

## Frequently Asked Questions

### Can the OpenHuman core run without the Tauri desktop shell?

Yes. The core Rust crate is designed for headless operation. It exposes a public API through [`src/embed/mod.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/embed/mod.rs) with `Harness::builder()` that any host can use. The core runs in CLI mode, Docker containers, or cloud environments without any Tauri or desktop dependencies.

### How does the Tauri shell authenticate with the core process?

The core writes a bearer token to a temporary file upon startup. The Tauri shell reads this token through the `core_rpc_token` command before making any JSON-RPC calls. This prevents unauthorized processes from accessing the core's RPC endpoint even on localhost.

### What prevents malicious UI code from accessing dangerous core methods?

The shell's `core_rpc` implementation in [`app/src-tauri/src/core_rpc.rs`](https://github.com/tinyhumansai/openhuman/blob/main/app/src-tauri/src/core_rpc.rs) maintains an explicit allow-list of permitted RPC methods, primarily restricted to the `tools.*` namespace. The shell rejects any method calls outside this whitelist before they reach the core, enforcing security at the boundary layer.

### Why use JSON-RPC over HTTP instead of Tauri's native IPC?

HTTP JSON-RPC provides language-agnostic access and enables the core to run as a separate process (or even on a remote host). This decouples the core's internal architecture from Tauri's IPC mechanisms, allowing the same communication pattern to work for CLI, Docker, and cloud deployments without code changes.