# PI-Desktop Architecture: How the Hybrid Rust-Electron Stack Is Structured

> Explore the PI-Desktop architecture structured with a Rust core for security, Electron for plugin sandboxing, and React for the UI. Learn about this hybrid stack.

- Repository: [Lan/PI-Desktop](https://github.com/vastsa/PI-Desktop)
- Tags: architecture
- Published: 2026-09-11

---

**PI-Desktop uses a three-layer hybrid architecture combining a Rust core host for workspace security, an Electron main process for plugin sandboxing, and a React renderer for the user interface.**

PI-Desktop is an open-source desktop application developed by vastsa that merges Rust’s systems-level performance with Electron’s cross-platform UI capabilities. The PI-Desktop architecture separates concerns into distinct layers—the Rust-based core host, the Electron main process, and the React-based renderer—to enforce strict security boundaries while enabling extensible plugin functionality. This design ensures that file operations remain contained within approved workspaces and that third-party plugins operate with limited, permission-based access to system resources.

## Core Host Layer (Rust)

The foundational layer of PI-Desktop resides in the Rust crate `crates/host-core`, which handles all workspace tracking, permission enforcement, and RPC routing. This layer exposes a stable API that the Electron side trusts implicitly, making it the authoritative source for file system operations and security checks.

### Workspace State and Containment

The Rust core maintains workspace integrity through the `WorkspaceState` struct, which stores the current project path and name. Critical helper functions such as `resolve_in_workspace`, `resolve_tool_path`, and `lexically_inside` ensure that any file operation remains confined to the user’s designated workspace or explicitly approved scratch areas.

In [`crates/host-core/src/workspace.rs`](https://github.com/vastsa/PI-Desktop/blob/main/crates/host-core/src/workspace.rs), these containment checks run before any plugin-exposed API is invoked. For example, when a plugin requests file access, the permission gateway validates the path using lexical analysis to prevent directory traversal attacks.

### Shared IPC Protocol

Version consistency between Rust and TypeScript is enforced through [`Cargo.toml`](https://github.com/vastsa/PI-Desktop/blob/main/Cargo.toml) (currently declaring version `0.14.6`) and the shared TypeScript definitions in [`packages/shared/src/protocol.ts`](https://github.com/vastsa/PI-Desktop/blob/main/packages/shared/src/protocol.ts). This file enumerates every IPC channel—such as `pi-desktop/fs/read` and `pi-desktop/plugin/openPanel`—ensuring compile-time safety across the boundary between Rust and Electron.

## Electron Main Process Layer

The Electron main process serves as the intermediary between the secure Rust core and the user-facing renderer. Located in `apps/desktop/electron/main/`, with its entry point at [`index.ts`](https://github.com/vastsa/PI-Desktop/blob/main/index.ts), this layer launches the UI, creates sandboxed plugin environments, and brokers all inter-process communication.

### Plugin Runtime and Isolation

Each installed plugin executes within its own Node.js utility process defined in [`electron/main/plugin-runtime.ts`](https://github.com/vastsa/PI-Desktop/blob/main/electron/main/plugin-runtime.ts). These processes are isolated from the main UI thread and communicate via a JSON-RPC broker that enforces the whitelist defined in [`protocol.ts`](https://github.com/vastsa/PI-Desktop/blob/main/protocol.ts). This architecture prevents plugins from directly accessing Electron internals or the Node.js `require` namespace outside the approved `pi.*` API surface.

### Permission Gateway

Before forwarding any request to the Rust core, the Electron main process validates the calling plugin’s permissions against its manifest declarations. Permissions such as `fs.read`, `fs.write`, or `net.fetch` are checked at the gateway level, ensuring that unauthorized operations never reach the host core.

### Window and Panel Management

The main process creates frameless `BrowserWindow` instances for plugin panels through [`electron/main/plugin-panel.ts`](https://github.com/vastsa/PI-Desktop/blob/main/electron/main/plugin-panel.ts). Each panel receives a 46-pixel drag band for window management and a preload script that exposes a limited `window.pluginBridge` object, restricting the panel to approved IPC methods.

## Renderer and UI Layer

The front-end of PI-Desktop is a React application located in `apps/desktop/src/`, responsible for all user-facing interactions including the command palette, workspace browser, and Extensions marketplace.

### React Components and State Management

The renderer loads workspace data through modules like [`work-panel-presentation.ts`](https://github.com/vastsa/PI-Desktop/blob/main/work-panel-presentation.ts), which coordinates the display of project files and plugin-contributed panels. Session and project state are managed in [`apps/desktop/src/lib/session-projects.ts`](https://github.com/vastsa/PI-Desktop/blob/main/apps/desktop/src/lib/session-projects.ts), maintaining synchronization with the Rust core via typed IPC calls.

### IPC Client Integration

All UI actions communicate with the host through the `IPC.invoke` namespace, utilizing TypeScript constants that guarantee compile-time channel safety. For example, fetching the plugin list calls `ipcRenderer.invoke(IPC.invoke.pluginList)`, with responses flowing back through the same typed protocol.

### Agent Integration

The UI drives PI-Desktop’s large language model assistant through specific API calls including `agentPrompt`, `agentComplete`, and `agentQueuePush`. The renderer can also request registration of plugin-provided tools via `agent.tool.register`, displaying results within the chat interface while the permission gateway validates each tool execution.

## Plugin System and Security Model

PI-Desktop’s extensibility relies on a manifest-driven plugin system documented in [`docs/spec/07-plugins/01-plugin-system.md`](https://github.com/vastsa/PI-Desktop/blob/main/docs/spec/07-plugins/01-plugin-system.md). Each plugin supplies a [`manifest.json`](https://github.com/vastsa/PI-Desktop/blob/main/manifest.json) declaring commands, panels, Agent tools, and required permissions.

### Three-Layer Isolation Model

The architecture implements defense in depth through three isolation boundaries:

1. **Host Main**: Validates manifests, manages installation, and routes RPC calls through the permission gateway.
2. **Plugin Runtime**: A restricted utility process exposing only the whitelisted `pi.*` namespace, blocking direct file system or network access unless explicitly granted.
3. **Plugin Panel UI**: Sandboxed `BrowserWindow` instances that communicate exclusively through `window.pluginBridge`, with no direct access to Node.js APIs.

### Permission Enforcement and Agent Tools

Permissions are declared in the plugin manifest and granted by the user at install time or runtime. The UI surfaces current permission grants on the Extensions page, while the host enforces them before any call reaches the core. Plugins can extend the Agent’s capabilities by registering tools via `pi.agent.registerTool`, with the system validating JSON schemas, applying execution timeouts, and logging audit data for security review.

## Data Flow Across the Architecture

A typical plugin command execution demonstrates how these layers interact:

1. The user clicks a command contributed by a plugin in the React UI.
2. The renderer invokes `pi.commands.register` via the IPC channel `pi-desktop/commands/run`.
3. The Electron main process checks the plugin’s `ui.panel` permission, then spawns the plugin’s utility process if not already running.
4. The panel’s preload script calls `window.pluginBridge.invoke('ui.showToast', ...)`.
5. The bridge forwards the request to the main process, which routes it through the permission gateway to the Rust core for any workspace file operations.
6. Results traverse back through the same path to update the UI.

### Code Examples

Registering a command from within a plugin runtime:

```typescript
await pi.commands.register({
  id: "my-plugin.open",
  title: "Open My Panel",
  run: async () => {
    await pi.ui.openPanel({ title: "My Plugin" });
    await pi.ui.showToast("Panel opened!");
  },
});

```

Reading a text file with required permissions:

```typescript
const content = await pi.fs.readText("src/config.json");

```

Registering an Agent tool with high-risk permissions:

```typescript
await pi.agent.registerTool({
  name: "summarize",
  description: "Summarise given text",
  schema: { type: "object", properties: { text: { type: "string" } }, required: ["text"] },
  execute: async ({ text }) => ({ summary: text.slice(0, 200) }),
});

```

## Summary

- **Rust Core Host**: Located in [`crates/host-core/src/workspace.rs`](https://github.com/vastsa/PI-Desktop/blob/main/crates/host-core/src/workspace.rs), manages workspace containment through `WorkspaceState` and functions like `lexically_inside`, serving as the trusted security boundary.
- **Electron Main Process**: Orchestrates plugin sandboxing via utility processes in [`plugin-runtime.ts`](https://github.com/vastsa/PI-Desktop/blob/main/plugin-runtime.ts), enforces permissions at the gateway level, and manages window creation through [`index.ts`](https://github.com/vastsa/PI-Desktop/blob/main/index.ts).
- **React Renderer**: Implements the UI in `apps/desktop/src/`, communicating through typed IPC channels defined in [`packages/shared/src/protocol.ts`](https://github.com/vastsa/PI-Desktop/blob/main/packages/shared/src/protocol.ts) and driving Agent interactions.
- **Plugin Isolation**: Uses a three-layer model (Host, Runtime, Panel) with manifest-driven permissions documented in the plugin system specification.
- **Version Consistency**: Maintained across the stack via [`Cargo.toml`](https://github.com/vastsa/PI-Desktop/blob/main/Cargo.toml), [`package.json`](https://github.com/vastsa/PI-Desktop/blob/main/package.json) files, and release scripts like `scripts/release.mjs`.

## Frequently Asked Questions

### What makes PI-Desktop a hybrid architecture?

PI-Desktop combines a Rust-based core host for performance-critical security operations with an Electron shell for cross-platform UI development. The Rust layer handles workspace containment and permission enforcement, while Electron manages windowing, plugin isolation, and the React renderer, creating a hybrid stack that leverages Rust’s memory safety alongside Electron’s web technology ecosystem.

### How does PI-Desktop prevent plugins from accessing unauthorized files?

The system enforces workspace containment through multiple checks. The Rust core in [`workspace.rs`](https://github.com/vastsa/PI-Desktop/blob/main/workspace.rs) uses `resolve_in_workspace` and `lexically_inside` to validate all file paths before operations execute. Additionally, the Electron permission gateway verifies the plugin’s declared permissions—such as `fs.read` or `fs.write`—before forwarding requests to the core, ensuring plugins cannot escape their designated sandbox.

### What role does the shared protocol file play in the architecture?

The [`packages/shared/src/protocol.ts`](https://github.com/vastsa/PI-Desktop/blob/main/packages/shared/src/protocol.ts) file serves as the single source of truth for IPC communication between Rust, Electron, and the React renderer. It enumerates all valid channel names like `pi-desktop/fs/read` and `pi-desktop/plugin/openPanel`, providing TypeScript compile-time safety and ensuring the Rust core registers matching string handlers. This prevents channel mismatches and type errors across the language boundary.

### How are Agent tools from plugins secured?

When a plugin registers an Agent tool via `pi.agent.registerTool`, the system validates the JSON schema, applies execution timeouts, and logs audit data. The tool executes within the restricted plugin runtime, subject to the same permission gateway checks as other plugin operations. The UI displays these capabilities only after the user grants specific high-risk permissions, maintaining the architecture’s security boundaries even when extending LLM functionality.