# How to Integrate OpenLogi with Other Systems: A Complete IPC and RPC Guide

> Integrate OpenLogi with other systems using the openlogi-ipc crate for seamless RPC calls. Connect Rust binaries, scripts, and services via Tarpc client for efficient inter-process communication.

- Repository: [Xuan Zhang/OpenLogi](https://github.com/AprilNEA/OpenLogi)
- Tags: how-to-guide
- Published: 2026-08-28

---

**Integrate OpenLogi with external systems by using the `openlogi-ipc` crate to establish a Tarpc client connection over local sockets, enabling direct RPC calls to the agent from Rust binaries, scripts, or external services.**

OpenLogi organizes its codebase as a clean three-tier architecture where the GUI, agent, and shared IPC layer remain strictly separated. This design allows any external tool or service to communicate with running OpenLogi instances without embedding the full desktop application. By leveraging the IPC contract defined in `crates/openlogi-ipc`, developers can build headless automations, custom overlays, or bridge services that control Logitech devices programmatically.

## Understanding OpenLogi's Three-Tier Architecture

The repository splits functionality into three distinct crates that communicate via local sockets. Understanding these boundaries is essential for stable integrations.

- **IPC Contract (`crates/openlogi-ipc`):** Defines the `AgentClient` trait and Tarpc service methods in [`crates/openlogi-ipc/src/ipc.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-ipc/src/ipc.rs). This crate handles the transport layer and protocol versioning.
- **Agent Core (`crates/openlogi-agent-core`):** Implements the server side of the IPC contract, managing device I/O, hook runtime, and DPI state. The agent exposes all functionality through the RPC surface.
- **User Interfaces (`crates/openlogi-cli` and `crates/openlogi-desktop`):** Provide thin clients that invoke the same RPC methods available to your custom code.

Because the IPC layer is independent of any UI, you can run the agent headless and drive it entirely through the programmatic API.

## Setting Up the IPC Client Connection

To begin integrating, add the IPC crate to your [`Cargo.toml`](https://github.com/AprilNEA/OpenLogi/blob/main/Cargo.toml) and establish an asynchronous connection to the running agent.

Add the dependency referencing the local workspace:

```toml
openlogi-ipc = { path = "../openlogi/crates/openlogi-ipc" }

```

The `connect()` function in [`crates/openlogi-ipc/src/client.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-ipc/src/client.rs) handles the local socket transport initialization and mandatory protocol handshake. Implement the connection as follows:

```rust
use openlogi_ipc::client::connect;
use tarpc::context;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Establish the IPC connection and retrieve the protocol version.
    let conn = connect().await?;
    println!("Connected to agent version {}", conn.version);

    // Example: query the list of paired devices.
    let devices = conn.client.list_devices(context::current()).await?;
    for d in devices {
        println!("{} – {} ({})", d.slot, d.codename, d.kind);
    }
    Ok(())
}

```

The `connect()` function returns a `Connection { client, version }` struct. Under the hood, it creates a local-socket stream via `transport::connect()`, wraps it for Tarpc, spawns the client, and performs the `protocol_version` handshake defined in [`crates/openlogi-ipc/src/client.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-ipc/src/client.rs) at lines 47-58.

## Calling RPC Methods

Once connected, you invoke any method defined in the `AgentClient` trait. The full API surface lives in [`crates/openlogi-ipc/src/ipc.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-ipc/src/ipc.rs) and includes device enumeration, DPI adjustment, and lighting control.

Query available devices:

```rust
let devices = conn.client.list_devices(context::current()).await?;

```

Modify device settings programmatically:

```rust
// Change DPI on a specific device
conn.client.set_dpi(context::current(), device_id, 800, 1600).await?;

```

Other available methods include `toggle_smartshift`, `set_lighting`, and `run_custom_action`. The trait is re-exported through [`crates/openlogi-ipc/src/lib.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-ipc/src/lib.rs) at lines 13-18, ensuring your integration stays synchronized with the agent's capabilities.

## Handling Protocol Versioning

OpenLogi uses a hardcoded `PROTOCOL_VERSION` constant to track RPC compatibility. The client connection exposes the agent's reported version through `conn.version`, but does not automatically validate compatibility.

Compare the connected version against your crate's constant:

```rust
if conn.version != openlogi_ipc::PROTOCOL_VERSION {
    eprintln!("Version mismatch: agent {}, client {}", 
              conn.version, openlogi_ipc::PROTOCOL_VERSION);
    // Handle upgrade logic here
}

```

This check prevents subtle bugs when the agent binary and your integration code drift out of sync across updates.

## Common Integration Patterns

### Scripted CLI Invocation

The `openlogi` binary in `crates/openlogi-cli` provides commands like `list`, `assets`, and `diag`. Shell scripts can invoke these directly for automation tasks that do not require custom logic:

```bash
openlogi diag dpi  # Performs a read/write/read-back DPI cycle

```

### Embedded RPC Client

Compile a custom Rust binary linking against `openlogi-ipc` to embed OpenLogi control directly into your application. This pattern works for game launchers, productivity tools, or system tray utilities that need fine-grained device manipulation without spawning external processes.

### External Service Bridge

Wrap the IPC client in a REST or WebSocket endpoint to expose OpenLogi functionality to non-Rust systems. A minimal `actix-web` service can accept JSON payloads and forward them to `set_lighting` or `set_dpi` methods, enabling home automation hubs to trigger Logitech device actions.

### Overlay Extensions

The `crates/openlogi-overlay` crate demonstrates an advanced integration pattern: it acts as an IPC client while rendering a GUI overlay. Fork this entry point (located at [`crates/openlogi-overlay/src/main.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-overlay/src/main.rs)) to add custom macro playback or contextual actions while reusing the existing transport implementation.

## Summary

- **Add `openlogi-ipc`** to your [`Cargo.toml`](https://github.com/AprilNEA/OpenLogi/blob/main/Cargo.toml) to access the RPC client and transport layers.
- **Use `connect()`** to establish a local socket connection and retrieve the protocol version from [`crates/openlogi-ipc/src/client.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-ipc/src/client.rs).
- **Call methods** like `list_devices`, `set_dpi`, and `set_lighting` defined in [`crates/openlogi-ipc/src/ipc.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-ipc/src/ipc.rs) through the returned client.
- **Check `PROTOCOL_VERSION`** against `conn.version` to ensure compatibility between your integration and the running agent.
- **Run headless** by communicating directly with the agent core without launching the GUI, enabling server-side automation and bridge services.

## Frequently Asked Questions

### Can I control OpenLogi devices without running the desktop GUI?

Yes. The agent process (`crates/openlogi-agent`) runs independently of the GUI. By connecting via the IPC client, you can send RPC commands to a headless agent instance, making OpenLogi suitable for servers or automation hosts that never load the desktop interface.

### What RPC methods are available for device control?

The `AgentClient` trait in [`crates/openlogi-ipc/src/ipc.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-ipc/src/ipc.rs) exposes methods including `list_devices`, `set_dpi`, `toggle_smartshift`, `set_lighting`, and `run_custom_action`. Consult this file for the complete API surface, as it represents the authoritative contract between clients and the agent.

### How does the IPC transport work across operating systems?

The transport layer in [`crates/openlogi-ipc/src/transport.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-ipc/src/transport.rs) abstracts platform-specific local sockets (Unix domain sockets on Linux/macOS, named pipes on Windows). The `connect()` function handles these details automatically, providing a unified async interface regardless of the host OS.

### What should I do if the protocol version changes?

Compare `conn.version` (returned by the connection) with the `PROTOCOL_VERSION` constant exported by the `openlogi-ipc` crate. If they differ, upgrade either the agent binary or your client dependency to matching versions. The IPC contract remains stable within major versions, but explicit version checks prevent serialization errors.