Tauri Desktop Shell vs Core Rust Crate Separation in OpenHuman

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

Core Process Spawning

The shell starts the core via the start_core_process command defined in app/src-tauri/src/lib.rs:

// 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:

// 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 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

JSON-RPC Server Implementation

The core exposes its functionality through a typed JSON-RPC server in src/core/jsonrpc.rs:

// 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:

// 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
  • 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 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 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →