Two-process model and IPC

The split between React and Rust is a security boundary, not only an implementation detail.

Frontend responsibilities

React owns:

  • rendering and user interaction;
  • tab, pane and space state;
  • CodeMirror and xterm instances;
  • provider configuration UI and AI session presentation;
  • diff review and approval cards;
  • shortcut routing and command-palette presentation.

The frontend can request a native operation through a typed invoke() bridge or subscribe to a Tauri event/channel. It cannot open a file, spawn a process or call a provider directly.

Rust responsibilities

Rust owns:

  • PTY and shell lifecycle;
  • filesystem reads, writes, search and watches;
  • Git command execution and repository resolution;
  • workspace authorization;
  • AI HTTP proxying and SSRF protection;
  • OS keychain access;
  • LSP process hosts and JSON-RPC framing;
  • serial, SSH and WSL native integrations.

Command flow

user action
  -> React module validates display state
  -> typed invoke() bridge
  -> Rust command validates path, cwd, ids and authorization
  -> native operation
  -> serialized result or Channel/event stream
  -> React store updates the view

Frontend validation improves UX but never replaces native validation. Rust must treat every webview argument as untrusted.

Registration checklist

When adding a command:

  1. Add a focused implementation in the owning Rust module.
  2. Register it in src-tauri/src/lib.rs.
  3. Add plugin and capability configuration when required.
  4. Add a typed bridge under the matching frontend module.
  5. Check workspace and secret-path authorization.
  6. Add tests for success, malformed input and denied input.

Streaming

Long-lived PTY output uses a Tauri Channel<PtyEvent> rather than repeated JSON polling. AI streams use the native network proxy and are surfaced through the AI SDK transport. Background process logs use bounded ring buffers so a process cannot grow memory without limit.

Capability allowlist

Tauri plugin APIs are allowlisted in src-tauri/capabilities/default.json. A plugin addition normally needs a Cargo dependency, a .plugin(...) registration and a capability entry. Do not grant a broad capability to make a narrow feature work.