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

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. 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 and establish an asynchronous connection to the running agent.

Add the dependency referencing the local workspace:

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

The connect() function in crates/openlogi-ipc/src/client.rs handles the local socket transport initialization and mandatory protocol handshake. Implement the connection as follows:

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 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 and includes device enumeration, DPI adjustment, and lighting control.

Query available devices:

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

Modify device settings programmatically:

// 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 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:

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:

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) to add custom macro playback or contextual actions while reusing the existing transport implementation.

Summary

  • Add openlogi-ipc to your 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.
  • Call methods like list_devices, set_dpi, and set_lighting defined in 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 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 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.

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 →