Tauri shell (app/src-tauri/)
June 5, 2026 · View on GitHub
The desktop host for OpenHuman: Tauri v2 + WebView, IPC commands, window management, and bridging to the embedded openhuman-core Rust runtime (core JSON-RPC). It does not duplicate the full domain stack; that lives in the repo-root Rust crate (openhuman_core, src/main.rs).
Responsibilities
- Web UI. Load the Vite build from
app/dist(or dev server on port 1420). - IPC. Expose a small, explicit set of Tauri commands (see Commands).
- Core lifecycle. Start the in-process core server and proxy JSON-RPC via
core_rpc_relay. - AI prompts on disk. Resolve bundled
src/openhuman/agent/promptsfrom resources / dev cwd forai_get_config/write_ai_config_file. - Window + tray. Desktop window behavior and system tray (see
lib.rs).
Core process model
app/package.json core:stage is intentionally a no-op kept for script compatibility. The desktop app links the core in-process, so local builds no longer need a staged openhuman-core-* sidecar under app/src-tauri/binaries/.
Stuck process recovery
Normal app quit runs teardown from RunEvent::ExitRequested: child webviews are closed before CEF shutdown, the embedded core's cancellation token is triggered, and the final process sweep sends SIGTERM to direct children before escalating holdouts with SIGKILL after a short grace period. Sweep summaries are logged as [app] sweep: term=N kill=M total=K; any nonzero kill count is a warning and means a child ignored graceful shutdown.
On macOS, hard exits (Force Quit, SIGKILL, renderer crash) can skip normal teardown. The next launch runs startup recovery before CEF cache preflight: it lists OpenHuman processes whose executable path belongs to the launching .app/Contents, skips the current process, sends SIGTERM, waits briefly, then SIGKILLs stragglers that still match the same pid+command. Logs use the [startup-recovery] prefix.
Startup recovery skips when OPENHUMAN_CORE_REUSE_EXISTING=1 is set (so manual CLI-core reuse still works) and when the CEF SingletonLock is held by a live process (so the normal second-instance path can fail without killing the already-running app). The Tauri command process_diagnostics_list_owned returns the currently owned process list; the macOS implementation is bundle-scoped, Linux/Windows currently return empty.
Tauri shell architecture (app/src-tauri/)
Overview
The app/src-tauri crate (Rust package OpenHuman, binary OpenHuman) is a desktop-only host. It embeds the React UI, registers plugins (deep link, opener, OS, notifications, autostart, updater), manages the main window and tray, and relays JSON-RPC to the embedded core server.
Non-desktop targets fail at compile time (compile_error! in lib.rs).
Directory layout (actual)
app/src-tauri/src/
├── lib.rs # `run()`, tray/menu actions, plugins, `generate_handler!`, core startup
├── main.rs # Binary entry
├── core_process.rs # CoreProcessHandle, embedded core server task
├── core_rpc.rs # HTTP client to core JSON-RPC
├── commands/
│ ├── mod.rs # Re-exports
│ ├── core_relay.rs # `core_rpc_relay`, service-managed core bootstrap
│ ├── openhuman.rs # Daemon host config, systemd-style service helpers
│ └── window.rs # show/hide/minimize/close window
└── utils/
├── mod.rs
└── dev_paths.rs # Resolve bundled AI prompts paths
There is no src-tauri/src/services/session_service.rs in this tree; session semantics are handled in the web layer + backend + core as applicable.
Data flow: UI → core
React (invoke)
→ core_rpc_relay { method, params, serviceManaged? }
→ core_rpc::call HTTP POST to OPENHUMAN_CORE_RPC_URL
→ embedded openhuman core server
CoreProcessHandle in core_process.rs owns the embedded server task; commands/core_relay.rs optionally ensures a service-managed core is running before relaying.
Window and tray behavior
- The shell creates a tray icon at startup and wires actions to open the main window or quit.
- In daemon mode (
daemon/--daemon), the main window is hidden on launch and can be reopened from tray actions. - On macOS
RunEvent::Reopenalso restores and focuses the main window. - Windows and Linux use the same tray actions (
Open OpenHuman,Quit), with desktop-environment-specific tray rendering differences on some Linux setups.
Bundled resources
tauri.conf.json bundles ../../skills/skills and ../../src/openhuman/agent/prompts so skills and prompt markdown ship with the app.
Related
- IPC surface: see the Commands section below
- HTTP bridge: see the Core bridge & helpers section below
- Rust domains (implementation): repo root
src/openhuman/,src/core_server/
Tauri IPC commands (app/src-tauri)
All commands are registered in app/src-tauri/src/lib.rs inside tauri::generate_handler![...] (desktop build). Names below are the Rust command names (camelCase in JS via serde where applicable).
Demo / diagnostics
| Command | Purpose |
|---|---|
greet | Demo string (safe to remove in production) |
AI configuration (bundled prompts)
| Command | Purpose |
|---|---|
ai_get_config | Build AIPreview from resolved SOUL.md / TOOLS.md under bundled or dev src/openhuman/agent/prompts |
ai_refresh_config | Same read path as ai_get_config (refresh hook) |
write_ai_config_file | Write a single .md under repo src/openhuman/agent/prompts (dev / safe filename checks) |
Core JSON-RPC relay
| Command | Purpose |
|---|---|
core_rpc_relay | Body: { method, params?, serviceManaged? } → forwards to local openhuman-core HTTP JSON-RPC (core_rpc.rs) |
Use app/src/services/coreRpcClient.ts (callCoreRpc) from the frontend.
Window management
From commands/window.rs (names may vary slightly; see lib.rs):
| Command | Purpose |
|---|---|
show_window | Show main window |
hide_window | Hide main window |
toggle_window | Toggle visibility |
is_window_visible | Query visibility |
minimize_window | Minimize |
maximize_window | Maximize |
close_window | Close |
set_window_title | Set title string |
OpenHuman daemon / service helpers
From commands/openhuman.rs (see source for exact payloads):
| Command | Purpose |
|---|---|
openhuman_get_daemon_host_config | Read daemon host preferences (e.g. tray) |
openhuman_set_daemon_host_config | Persist daemon host preferences |
openhuman_service_install | Install background service (platform-specific) |
openhuman_service_start | Start service |
openhuman_service_stop | Stop service |
openhuman_service_status | Query status |
openhuman_service_uninstall | Uninstall service |
Screen share picker (CEF / macOS)
From screen_capture/mod.rs. Backs the in-page getDisplayMedia shim in webview_accounts/runtime.js. Session-gated: the shim must open a session with a live user gesture before enumeration / thumbnail captures succeed. See issue #713 (picker UX) + #812 (session gating).
| Command | Purpose |
|---|---|
screen_share_begin_session | Open a 30s session from an account webview, after a navigator.userActivation.isActive gesture. Returns { token, sources }. Rate-limited to 10/minute per account. |
screen_share_thumbnail | Capture a single source's thumbnail as base64 PNG. Requires a live token and an id that the session was issued for. macOS only; other platforms return an error. |
screen_share_finalize_session | Close the session. Called by the shim on Share or Cancel; safe to call with an unknown/expired token (no-op). |
Workspace file links
From workspace_paths.rs (closes #1402). These commands accept workspace-relative paths only. The shell resolves each path against the active OpenHuman workspace, canonicalizes the target, and rejects traversal, absolute paths, URI-like prefixes, and symlink escapes before opening or reading anything.
| Command | Purpose |
|---|---|
open_workspace_path | Open an existing workspace file or directory with the OS default app. |
reveal_workspace_path | Reveal an existing workspace file or directory in the OS file manager. |
preview_workspace_text | Read a capped UTF-8 text preview from an existing workspace file. |
Push-to-talk (PTT) hotkey + overlay
Registered in lib.rs (ptt_hotkeys.rs + ptt_overlay.rs). These commands manage the global push-to-talk shortcut and the floating overlay window.
| Command | Signature | Purpose |
|---|---|---|
register_ptt_hotkey | (shortcut: String) -> Result<(), String> | Register (or re-register) a global hotkey for push-to-talk. Emits Tauri events ptt://start { session_id } (key pressed) and ptt://stop { session_id } (key released). Returns an error string if the shortcut conflicts with dictation or if the OS rejects it (e.g. Wayland, Accessibility permission required on macOS). |
unregister_ptt_hotkey | () -> Result<(), String> | Unregister the current PTT hotkey and tear down the overlay window. |
show_ptt_overlay | (active: bool, session_id: u64) -> () | Show (active: true) or hide (active: false) the floating PTT overlay window. The window is focus-stealing-free (focus: false). Called by PttHotkeyManager.tsx via app/src/utils/tauriCommands/ptt.ts. |
Event flow: register_ptt_hotkey wires the OS hotkey to fire ptt://start / ptt://stop Tauri events that PttHotkeyManager.tsx subscribes to via @tauri-apps/api/event. The manager forwards them into the pttService state machine which drives the audio capture → transcribe → chat-send pipeline.
Conflict detection: register_ptt_hotkey checks for overlap with the active dictation shortcuts before registering. If a conflict is detected it returns "ConflictsWithDictation(<shortcut>)" without registering anything, and the settings panel surfaces this as pttSettings.errorConflictsWithDictation.
Synthetic input main-thread executor (native registry, not invoke)
Registered in lib.rs at startup under the event-bus native-request method
computer.input_on_main_thread (INPUT_ON_MAIN_THREAD_METHOD, defined in
openhuman_core::openhuman::tools::computer::main_thread). This is not a
@tauri-apps/api invoke command — it is an in-process native request the
core dispatches to the shell so synthetic input runs on the real app
main thread.
Why: enigo's macOS keyboard-layout lookup (TSMGetInputSourceProperty) traps
(_dispatch_assert_queue_fail / EXC_BREAKPOINT) and crashes the CEF host when
called off the main thread. The mouse / keyboard tools therefore never call
enigo on their tokio worker; they build a closure and dispatch it here, where
the shell runs it via AppHandle::run_on_main_thread.
| Field | Shape |
|---|---|
| Method | computer.input_on_main_thread |
| Request | MainThreadInputOp { run: Box<dyn FnOnce() -> Result<String, String> + Send> } (passed by value) |
| Response | Result<String, String> — Ok(message) on success, Err(reason) on failure |
| Availability | Desktop only. Headless / CLI builds register no executor; the core call then returns a clean Err. |
Removed / not present
The following do not exist in the current generate_handler! list: exchange_token, get_auth_state, socket_connect, start_telegram_login. Authentication and sockets are handled in the React app and core process, not via these IPC names.
Example: core RPC
import { invoke } from "@tauri-apps/api/core";
const result = await invoke("core_rpc_relay", {
request: {
method: "your.rpc.method",
params: { foo: "bar" },
serviceManaged: false,
},
});
See app/src-tauri/src/lib.rs for the authoritative list.
Core bridge & helpers (app/src-tauri)
This document replaces the old “SessionService / SocketService” split. The Tauri crate does not embed a duplicate Socket.io server or Telegram client; instead it focuses on process management and HTTP JSON-RPC to the openhuman-core binary.
CoreProcessHandle (core_process.rs)
- Resolves the
openhuman-coreexecutable (staged underbinaries/orPATH/ dev layout). - Starts or attaches to the core process and exposes its RPC URL (
OPENHUMAN_CORE_RPC_URL). - Used during app setup in
lib.rs(app.manage(core_handle)).
core_rpc (core_rpc.rs)
- HTTP client for the core’s JSON-RPC surface (localhost).
- Used by
core_rpc_relayto forwardmethod+paramsfrom the frontend.
commands/core_relay.rs
core_rpc_relay. ensures the core is running (in-process handle or service-managed path), then callscore_rpc.ensure_service_managed_core_running. bootstraps systemd/launchd-style service when RPC is down (platform-specific behavior inside core CLI).
commands/openhuman.rs
- Daemon host JSON config (e.g. tray visibility) under the app data directory.
- Install/start/stop/status/uninstall helpers for the openhuman background service.
utils/dev_paths.rs
- Resolves
src/openhuman/agent/promptsfor development and bundled resource paths for AI preview.
utils/tauriSocket.ts (frontend)
Not in src-tauri, but pairs with the shell: the React app listens for Tauri events that mirror socket activity when using the Rust-side client. See app/src/utils/tauriSocket.ts and the Frontend Services chapter.