Understanding the Crate Organization in OpenLogi: A Modular Rust Workspace Architecture

OpenLogi splits its functionality into 16 focused crates within a Rust workspace, implementing a three-tier architecture that isolates GUI rendering, background agent logic, and shared infrastructure to enable cross-platform Logitech device management.

OpenLogi is a Rust-based application for configuring and automating Logitech input devices via the HID++ protocol. According to the source code in AprilNEA/OpenLogi, the project uses a workspace-based crate organization defined in the root Cargo.toml to enforce strict boundaries between device I/O, input capture, and interface rendering. This modular structure allows components to evolve independently while maintaining type safety through the openlogi-core contract.

The Three-Tier Architecture

The crate organization follows a clear separation of concerns across three architectural layers. This design ensures that UI processes never perform direct device I/O, while the agent maintains exclusive control over hardware communication.

GUI Tier – Pure IPC clients that render interfaces but never touch hardware. The openlogi-desktop crate provides the main GPUI application, while openlogi-overlay renders a cursor-centered Actions Ring. Both communicate with the agent via the openlogi-ipc contract.

Agent Tier – The openlogi-agent crate runs as a background server, owning the input hook, device I/O, and IPC endpoints. This crate orchestrates openlogi-hook for capture, openlogi-inject for synthesis, and openlogi-hid for device communication.

Shared Infrastructure – Common types and protocols live in openlogi-core (configuration structs), openlogi-ipc (tarpc definitions), and openlogi-ui (GPUI components). These crates enable communication between tiers without circular dependencies.

Core Infrastructure and Types

The foundation of the workspace rests on crates that define data structures and communication contracts, ensuring type safety across process boundaries.

openlogi-core

Located at crates/openlogi-core, this crate holds pure data types including configuration structs, device model definitions, and action catalogs. The source at crates/openlogi-core/src/lib.rs defines the Profile and Action types deserialized from TOML configuration files. Importantly, this crate contains no I/O or async code, making it safe to import into any tier without dragging in platform-specific dependencies.

openlogi-ipc

The crates/openlogi-ipc crate defines the tarpc-based IPC protocol in src/ipc.rs, establishing the contract between the GUI, agent, and overlay processes. It handles transport over local sockets, enabling the desktop application to poll device state without blocking the rendering thread.

openlogi-assets

Device-rendered assets and remote fetching logic reside in crates/openlogi-assets. This crate maintains a registry of device-specific resources and caches remote fetches from OpenLogi mirrors, decoupling the UI from network operations.

Device Communication Layer

Hardware interaction is isolated into specialized crates that handle protocol translation and permission introspection.

openlogi-hid and openlogi-hidpp

The crates/openlogi-hid crate uses async-hid to discover Logitech devices and perform HID++ command writes, while crates/openlogi-hidpp contains a vendored fork of the upstream hidpp library. This separation allows the protocol implementation to evolve independently from the async runtime wrapping it.

openlogi-permissions

Platform-specific permission status lives in crates/openlogi-permissions, which reads macOS TCC status and Linux device-file probes. Unlike other automation tools, this crate never prompts the user; it only introspects system state for the agent to consume.

Input Handling and Synthesis

Capturing and generating input events requires platform-native code gated behind conditional compilation.

openlogi-hook

The crates/openlogi-hook crate implements platform-specific input capture: CGEventTap on macOS, evdev plus uinput on Linux, and WH_MOUSE_LL on Windows. The implementation at src/lib.rs abstracts these behind a unified API that feeds into the agent's event loop.

openlogi-inject

Synthetic input generation lives in crates/openlogi-inject, translating high-level Action types from openlogi-core into platform-specific events. It generates CGEvents on macOS, uinput plus MPRIS on Linux, and SendInput calls on Windows.

openlogi-agent-core

Shared orchestration logic for the agent process resides in crates/openlogi-agent-core. This crate manages the hook runtime, DPI cycling, HID++ write queues, and the state of the Actions Ring session, providing the business logic that openlogi-agent exposes via IPC.

User Interface Crates

The GUI tier separates shared components from specific application entry points.

openlogi-ui

The crates/openlogi-ui crate supplies GPUI-based ring geometry, icon loading, and locale negotiation. Used by both the desktop app and overlay, this crate renders the visual components that display device status and action rings.

openlogi-desktop and openlogi-overlay

crates/openlogi-desktop contains the main GPUI application entry point at src/main.rs, polling the agent but never performing device I/O. In contrast, crates/openlogi-overlay provides a minimal IPC client that renders only the cursor-centered Actions Ring, linking exclusively against openlogi-ui to minimize binary size.

Command-Line Interface and Tooling

openlogi and openlogi-cli

The crates/openlogi crate serves as the thin CLI entry point, forwarding commands to openlogi-cli, which implements the clap command tree including list, assets, and diag subcommands for headless operation.

xtask

Build automation lives in the xtask crate at the workspace root, providing cargo xtask scripts for bundling, packaging, and CI orchestration as defined in xtask/src/main.rs.

Working with the Crate Organization

To launch the desktop GUI during development:

cargo run -p openlogi-desktop

This compiles only the GUI tier and its dependencies, connecting automatically to a running agent via the IPC socket defined in openlogi-ipc.

To query devices from the command line:

cargo run -p openlogi -- list

The openlogi-cli crate parses arguments and communicates with the agent to enumerate connected Logitech hardware.

Creating a custom action requires editing a TOML profile that openlogi-core deserializes:


# ~/.config/openlogi/profile.toml

[[profile.actions]]
name = "Launch Terminal"
kind = "run"
command = "gnome-terminal"

The agent loads this configuration and translates the action into an injection request when triggered.

Summary

  • OpenLogi uses a Rust workspace with 16 crates organized into GUI, Agent, and Shared Infrastructure tiers.
  • openlogi-core defines pure data types and configuration schemas without I/O dependencies.
  • Hardware access is isolated in openlogi-hid, openlogi-hidpp, and openlogi-agent.
  • Platform-specific input code lives in openlogi-hook (capture) and openlogi-inject (synthesis) behind cfg gates.
  • The GUI tier (**openlogi-desktop**, **openlogi-overlay**) communicates via openlogi-ipc using tarpc over local sockets.
  • Build tooling resides in the xtask crate, following Rust workspace conventions.

Frequently Asked Questions

What is the role of the openlogi-agent crate?

The openlogi-agent crate runs as a background server process that owns all hardware interaction, including input hooks and HID++ device communication. It exposes IPC endpoints defined in openlogi-ipc/src/ipc.rs for the GUI to query state and trigger actions, ensuring the desktop application never blocks on device I/O.

How does OpenLogi handle cross-platform input capture?

Input capture logic resides in crates/openlogi-hook/src/lib.rs, which uses conditional compilation to select CGEventTap on macOS, evdev and uinput on Linux, and WH_MOUSE_LL hooks on Windows. This platform abstraction allows the same high-level API to function across operating systems without changing the agent's orchestration logic.

What distinguishes openlogi-desktop from openlogi-overlay?

openlogi-desktop is a full GPUI application providing device management and configuration interfaces, while openlink-overlay is a minimal, cursor-centered Actions Ring that links only to openlogi-ui. The overlay runs as a separate binary to reduce resource usage when only quick action selection is needed.

Why is the HID++ protocol vendored in a separate crate?

The openlogi-hidpp crate contains a fork of the upstream hidpp library, isolating protocol definitions from the async runtime and platform-specific HID implementations. This separation allows the protocol to be tested independently and updated without affecting the device discovery logic in openlogi-hid.

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 →