How OpenLogi's Multi-Process Architecture Works for Developers: A Complete Guide

OpenLogi separates runtime responsibilities into three independent processes—the Desktop GUI, the Agent, and the Overlay—that communicate exclusively through a local-socket IPC layer, with all hardware access isolated to a single background process.

This multi-process architecture powers OpenLogi, an open-source Rust application for managing Logitech HID++ devices. By splitting concerns across process boundaries, the codebase achieves crash isolation, flexible UI layering, and clean extension points for developers building custom integrations or alternative interfaces.


The Three Process Roles

OpenLogi's architecture assigns each critical responsibility to its own binary. These processes launch as a coordinated bundle but maintain independent lifecycles.

Desktop GUI (crates/openlogi-desktop)

The Desktop is the primary GPUI-based user interface. Its sole responsibilities are rendering UI elements, reading configuration files, and polling the Agent for current device state. Per the source code, it performs no HID or input handling whatsoever—it is a pure IPC client.

In [crates/openlogi-desktop/src/main.rs](https://github.com/AprilNEA/OpenLogi/blob/master/crates/openlogi-desktop/src/main.rs), the desktop attempts to connect to the agent's socket on startup. If the Agent is not running, it spawns a fresh Agent process and blocks until the socket becomes available.

Agent (crates/openlogi-agent)

The Agent is the long-running background process that owns all hardware interaction. It manages:

  • The global input hook
  • HID++ read/write operations
  • DPI cycling and per-profile settings
  • SmartShift state
  • The Actions Ring session state

All device communication is confined to this crate. The Agent exposes a tarpc service defined in crates/openlogi-ipc, making it the single source of truth for device state. Other processes merely observe and request changes through this API.

The entry point in [crates/openlogi-agent/src/main.rs](https://github.com/AprilNEA/OpenLogi/blob/master/crates/openlogi-agent/src/main.rs) creates the IPC server and initializes the HID hook.

Overlay (crates/openlogi-overlay)

The Overlay is a lightweight IPC client that draws the cursor-centered Actions Ring. It shares openlogi-ui with the Desktop but runs as a separate binary—specifically so it can position itself above any window without dragging the heavy Desktop process into that layering context.

Critically, the Overlay is a sibling of the GUI, not a child process. This independence prevents the Overlay's lifecycle from being tied to the Desktop window, as documented in AGENTS.md lines 46-53.


IPC Layer: tarpc + bincode over Local Sockets

Communication between all three processes uses tarpc with bincode serialization over interprocess local sockets.

Wire Protocol and Versioning

The IPC contract lives in [crates/openlogi-ipc/AGENTS.md](https://github.com/AprilNEA/OpenLogi/blob/master/crates/openlogi-ipc/AGENTS.md). The wire format is:

  • Versioned — changes are tracked across releases
  • Append-only — new fields extend without breaking existing clients

This design allows the Desktop and Overlay to evolve independently of the Agent, provided they respect the versioned contract.

Socket Path and Connection Pattern

All clients connect to the same socket path (default: /tmp/openlogi_socket). The Desktop and Overlay follow identical connection logic:

  1. Attempt to connect to existing socket
  2. If connection fails, spawn the Agent binary
  3. Poll until the socket appears, then proceed

Because the socket is the single source of truth, both UI processes see consistent device state, DPI settings, SmartShift status, and profile information.


Extending the Architecture: Three Developer Paths

Developers can leverage OpenLogi's multi-process architecture through well-defined extension points.

1. Implement New IPC Methods

Add functionality that propagates to all clients automatically:

Since Desktop, Agent, and Overlay all import the same openlogi-ipc crate, changes propagate without manual synchronization across crates.

2. Run the Mock Agent for UI-Only Development

For frontend work without physical hardware, use the mock binary:

cargo run -p openlogi-agent --bin openlogi-agent-mock &
cargo run -p openlogi-desktop

The mock serves a scripted inventory over the socket, as noted in AGENTS.md lines 30-33. This enables rapid iteration on GPUI components without requiring an attached Logitech device.

3. Embed a Custom IPC Client

Any third-party tool can become a peer by linking against openlogi-ipc:

use openlogi_ipc::ipc::{AgentServiceClient, AgentService};
use tarpc::client::Config;
use interprocess::local_socket::LocalSocketStream;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // Connect to the agent's socket (same path the desktop uses)
    let stream = LocalSocketStream::connect("/tmp/openlogi_socket")?;
    let client = AgentServiceClient::new(Config::default(), stream).await?;

    // List all attached devices
    let devices = client.list_devices().await?;
    println!("Devices: {:#?}", devices);

    // Set DPI for device 0
    client.set_dpi(0, 1200).await?;
    Ok(())
}

This pattern lets external scripts query or modify profiles, DPI, or SmartShift while the Agent remains the sole hardware authority.


Development Workflow Examples

Auto-Starting the Agent with the Desktop


# GUI spawns agent automatically if not running

cargo run -p openlogi-desktop

# Verify socket creation

ls -l /tmp/openlogi_socket

Running Desktop Against Mock Agent


# Terminal 1: Start mock

cargo run -p openlogi-agent --bin openlogi-agent-mock &

# Terminal 2: Launch desktop (connects to mock)

cargo run -p openlogi-desktop

Key Source Files

Component File Purpose
Architecture overview [AGENTS.md](https://github.com/AprilNEA/OpenLogi/blob/master/AGENTS.md#L15-L23) Three-process design and lifecycle rules
IPC contract [crates/openlogi-ipc/AGENTS.md](https://github.com/AprilNEA/OpenLogi/blob/master/crates/openlogi-ipc/AGENTS.md) tarpc service definition and versioning policy
Agent entry point [crates/openlogi-agent/src/main.rs](https://github.com/AprilNEA/OpenLogi/blob/master/crates/openlogi-agent/src/main.rs) IPC server and HID hook initialization
Desktop entry point [crates/openlogi-desktop/src/main.rs](https://github.com/AprilNEA/OpenLogi/blob/master/crates/openlogi-desktop/src/main.rs) GPUI app startup and Agent spawning
Overlay client [crates/openlogi-overlay/src/main.rs](https://github.com/AprilNEA/OpenLogi/blob/master/crates/openlogi-overlay/src/main.rs) Minimal IPC client for Actions Ring
Mock agent [crates/openlogi-agent/src/bin/openlogi-agent-mock.rs](https://github.com/AprilNEA/OpenLogi/blob/master/crates/openlogi-agent/src/bin/openlogi-agent-mock.rs) Scripted inventory for UI testing
HID++ writes [crates/openlogi-device/src/write.rs](https://github.com/AprilNEA/OpenLogi/blob/master/crates/openlogi-device/src/write.rs) Hardware access (Agent-only)

Summary

  • Three processes: Desktop (UI), Agent (hardware), Overlay (floating UI)—each with isolated responsibilities
  • Single IPC layer: tarpc + bincode over interprocess local sockets, with versioned, append-only wire format
  • Crash isolation: UI panics cannot corrupt device state; the Agent continues serving other clients
  • Extension points: new IPC methods, mock agent for testing, custom clients via openlogi-ipc crate

Frequently Asked Questions

Why split the Overlay into a separate process instead of a Desktop window?

The Overlay must render above all other windows, including full-screen applications. Running it as a sibling process decouples its layering from the Desktop's window hierarchy. Per AGENTS.md, this keeps the Overlay lightweight and independent—if the Desktop restarts, the Actions Ring remains visible.

How does the Agent prevent multiple clients from conflicting?

The Agent serializes requests through a single tarpc service instance. All state mutations (DPI changes, profile switches) flow through this centralized handler, which owns the exclusive HID++ connection. The socket acts as a natural serialization point—clients cannot bypass the Agent's internal consistency checks.

Can I write a client in a language other than Rust?

Yes, though you must implement the tarpc + bincode protocol. The openlogi-ipc crate serves as the reference implementation. Alternative clients should replicate:

  1. The socket path discovery (default /tmp/openlogi_socket)
  2. The bincode serialization format
  3. The service version handshake

Consider generating stubs from the tarpc definition in crates/openlogi-ipc/src/ipc.rs rather than reverse-engineering the wire format.

What happens if the Agent crashes while the Desktop is running?

The Desktop detects the broken connection and automatically respawns the Agent, then reconnects. The Overlay follows the same recovery pattern. Device state is reconstructed from persistent storage in the Agent's startup sequence, though any in-flight Actions Ring session is interrupted.

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 →