What Are the Core Components of OpenLogi? A Deep Dive into the Rust Workspace Architecture

OpenLogi is organized as a multi-crate Rust workspace with three distinct runtime tiers—GUI, agent, and overlay—comprising 16 specialized crates that separate concerns from device I/O to UI rendering.

OpenLogi is an open-source Logitech device manager built in Rust that uses a workspace architecture to isolate hardware interaction from interface logic. Understanding the core components of OpenLogi is essential for developers looking to extend its functionality or integrate with its IPC system. The project splits responsibilities across distinct crates ranging from low-level HID++ protocol handling to high-level GPUI desktop applications.

The Three-Tier Runtime Architecture

OpenLogi operates through three coordinated runtime tiers that communicate via tarpc IPC. This design ensures that device I/O happens in a privileged background process while UI layers remain unprivileged and cross-platform.

Agent Tier

The agent tier handles all hardware interaction and system-level input capture. At its center is crates/openlogi-agent, the background server binary that manages the lifecycle of hooks, device connections, and IPC sockets. According to the source in crates/openlogi-agent/src/main.rs, this binary runs continuously as a daemon, exposing an API over a local socket defined in crates/openlogi-ipc/src/ipc.rs.

Supporting this is crates/openlogi-agent-core, which provides shared orchestration logic including the hook runtime, HID++ write operations, DPI cycling, and the Actions Ring state machine.

GUI Tier

The GUI tier consists of two distinct interface layers that act as pure IPC clients. crates/openlogi-desktop implements the full GPUI desktop application using gpui-component, polling the agent for device state but never performing direct device I/O. The desktop app entry point lives in crates/openlogi-desktop/src/main.rs.

Complementing this is crates/openlogi-overlay, a minimal client that displays only the cursor-centered Actions Ring without the full application chrome.

Shared Infrastructure

Connecting these tiers is crates/openlogi-ipc, which defines the versioned, append-only wire format for tarpc communication. The IPC contract in crates/openlogi-ipc/src/ipc.rs ensures backward compatibility between different versions of the agent and UI clients.

Device Stack and Protocol Implementation

The hardware abstraction layer follows a clean separation between protocol logic, transport mechanisms, and device enumeration.

HID++ Protocol Handling

crates/openlogi-hidpp contains a vendored implementation of the Logitech HID++ protocol (library name hidpp). This crate provides the raw protocol definitions in crates/openlogi-hidpp/src/lib.rs, handling the binary packet format used to communicate with Logitech peripherals.

Device Abstraction

crates/openlogi-device sits atop the protocol layer, providing device-level HID++ functionality including enumeration, probing, writes, sessions, and pairing. Crucially, this crate is host-agnostic and expresses all operations against a HidBackend trait, allowing the same logic to run on different operating systems.

The actual transport implementation resides in crates/openlogi-hid, which provides the host-specific async HID++ transport (async-hid), macOS input monitoring, and probe-cache handling.

Hardware Registry

crates/openlogi-device-registry maintains a registry of hardware identities, receiver protocols, and driver metadata. This crate allows OpenLogi to identify connected Logitech devices and load appropriate profiles without hardcoding device IDs in the core logic.

Input Capture and Injection

OpenLogi intercepts and synthesizes input events through OS-specific mechanisms isolated in dedicated crates.

Input Hook Implementation

crates/openlogi-hook implements OS-level input capture using platform-specific APIs:

  • macOS: CGEventTap
  • Linux: evdev + uinput
  • Windows: WH_MOUSE_LL

Input Synthesis

crates/openlogi-inject handles the reverse operation—injecting synthesized events back into the OS:

  • macOS: CGEvent
  • Linux: uinput + MPRIS
  • Windows: SendInput

User Interface and Assets

The presentation layer separates rendering logic from asset management.

Shared UI Components

crates/openlogi-ui contains the UI layer shared by both the desktop app and the overlay. This includes ring geometry calculations, icon rendering systems, GPUI asset sources, and locale catalogs.

Asset Management

crates/openlogi-assets manages the asset registry that maps devices to render data and fetches cached assets from mirror servers. This allows OpenLogi to download device-specific icons and configurations on demand rather than bundling everything in the binary.

Command-Line and System Integration

CLI Interface

crates/openlogi-cli provides a clap-driven command-line interface exposing commands such as list, assets, and diag. The CLI forwards commands to the openlogi-agent binary over IPC rather than interacting with hardware directly. The entry point is crates/openlogi-cli/src/main.rs.

System Permissions

crates/openlogi-permissions reads privacy-permission status and provides deep links to system settings (macOS TCC, Linux device-file probes). This crate helps users diagnose why input capture might fail due to missing accessibility permissions.

Working with the Core Components

Listing Connected Devices

To list connected Logitech devices from the command line:

openlogi list

The list sub-command lives in crates/openlogi-cli, which forwards the request to the running agent over the IPC socket.

Running the Desktop GUI

To launch the full desktop application:

cargo run -p openlogi-desktop

This builds the GPUI binary and automatically starts the agent if it isn't already running. The desktop process connects to the agent via the IPC transport defined in crates/openlogi-ipc/src/ipc.rs.

Using the Overlay

To run the lightweight overlay ring:

cargo run -p openlogi-overlay

The overlay binary reads the same UI assets as the desktop app but contains no device-I/O code; it only draws the ring based on the agent's state broadcast.

Programmatic IPC Access

Query the agent programmatically from Rust:

use openlogi_ipc::client::OpenLogiClient;
use openlogi_ipc::types::DeviceInfo;

#[tokio::main]
async fn main() {
    // Connect to the local socket used by the agent
    let mut client = OpenLogiClient::connect().await.unwrap();

    // Ask the agent for the current device list
    let devices: Vec<DeviceInfo> = client.list_devices().await.unwrap();

    for d in devices {
        println!("{} – {}", d.id, d.name);
    }
}

The client implementation lives in crates/openlogi-ipc/src/client.rs.

Summary

  • OpenLogi uses 16 specialized crates organized into a Rust workspace to separate device I/O, protocol handling, UI rendering, and system integration.
  • The three-tier architecture (agent, desktop GUI, overlay) ensures that privileged hardware access runs in a background daemon while UI layers remain unprivileged IPC clients.
  • HID++ communication flows through openlogi-hidpp → openlogi-device → openlogi-hid, creating a host-agnostic abstraction over the Logitech protocol.
  • Input handling is split between openlogi-hook (capture) and openlogi-inject (synthesis), using native OS APIs on each platform.
  • All UI clients communicate with the agent via the tarpc-based IPC system defined in crates/openlogi-ipc, allowing multiple interfaces to share a single device connection.

Frequently Asked Questions

What is the relationship between openlogi-agent and openlogi-desktop?

openlogi-agent is the privileged background daemon that owns all device I/O and input hooks, while openlogi-desktop is an unprivileged GPUI application that acts as a pure IPC client. The desktop app polls the agent for device state and sends configuration commands, but never touches hardware directly. This separation allows the desktop app to run without elevated permissions while the agent handles sensitive operations.

How does OpenLogi handle cross-platform input capture?

Input capture is implemented in crates/openlogi-hook using platform-specific native APIs: CGEventTap on macOS, evdev with uinput on Linux, and WH_MOUSE_LL on Windows. Similarly, crates/openlogi-inject handles input synthesis using CGEvent, uinput + MPRIS, and SendInput respectively. These crates abstract the OS differences behind a common Rust interface.

Can I use OpenLogi programmatically without the GUI?

Yes. You can interact with the agent directly via the IPC API defined in crates/openlogi-ipc/src/ipc.rs. Import the openlogi_ipc crate and use OpenLogiClient::connect() to establish a connection to the agent's local socket. This allows you to list devices, query status, and send commands from your own Rust applications without launching the desktop or overlay interfaces.

What is the HID++ protocol and why does it need a dedicated crate?

HID++ is Logitech's proprietary protocol for communicating with their advanced input devices over USB HID. The crates/openlogi-hidpp crate provides a vendored implementation (library name hidpp) that handles the binary packet format, feature sets, and protocol versioning. Isolating this in its own crate allows other projects to use the protocol implementation independently while keeping OpenLogi's higher-level device logic separate from protocol minutiae.

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 →