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

> Explore the crate organization in OpenLogi's Rust workspace. Discover how 16 focused crates and a three-tier architecture enable efficient cross-platform Logitech device management.

- Repository: [Xuan Zhang/OpenLogi](https://github.com/AprilNEA/OpenLogi)
- Tags: internals
- Published: 2026-08-22

---

**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`](https://github.com/AprilNEA/OpenLogi/blob/main/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`](https://github.com/AprilNEA/OpenLogi/blob/main/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`](https://github.com/AprilNEA/OpenLogi/blob/main/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`](https://github.com/AprilNEA/OpenLogi/blob/main/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`](https://github.com/AprilNEA/OpenLogi/blob/main/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`](https://github.com/AprilNEA/OpenLogi/blob/main/xtask/src/main.rs).

## Working with the Crate Organization

To launch the desktop GUI during development:

```bash
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:

```bash
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:

```toml

# ~/.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`](https://github.com/AprilNEA/OpenLogi/blob/main/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`](https://github.com/AprilNEA/OpenLogi/blob/main/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`.