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-coredefines pure data types and configuration schemas without I/O dependencies.- Hardware access is isolated in
openlogi-hid,openlogi-hidpp, andopenlogi-agent. - Platform-specific input code lives in
openlogi-hook(capture) andopenlogi-inject(synthesis) behindcfggates. - The GUI tier (
**openlogi-desktop**, **openlogi-overlay**) communicates viaopenlogi-ipcusing tarpc over local sockets. - Build tooling resides in the
xtaskcrate, 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →