# How OpenLogi Implements Inter-Process Communication (IPC) with tarpc and Local Sockets

> Discover how OpenLogi implements inter-process communication using tarpc and local sockets. Learn about its typed RPC layer for crash-isolated client interactions.

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

---

**OpenLogi implements inter-process communication through a typed RPC layer built with tarpc, using bincode serialization over local sockets provided by the interprocess crate, enabling version-aware, crash-isolated interactions between the background agent and GUI/CLI clients.**

OpenLogi coordinates its desktop GUI, overlay helpers, and command-line tools with a persistent background agent using a robust inter-process communication (IPC) architecture. According to the AprilNEA/OpenLogi source code, all cross-process messages flow through the `openlogi-ipc` crate, which defines a type-safe contract generated from a single `#[tarpc::service]` trait named `Agent`.

## Typed RPC Foundation with tarpc

The IPC layer relies on **tarpc** to generate client and server stubs from the `Agent` trait defined in [`crates/openlogi-ipc/src/ipc.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-ipc/src/ipc.rs). This approach eliminates manual message parsing and ensures compile-time type safety across process boundaries.

**Wire protocol details:**
- **Serialization** – All RPC calls use **bincode** for compact, fast binary encoding.
- **Transport** – The `interprocess` crate provides local-socket abstractions (Unix domain sockets on macOS/Linux, named pipes on Windows). The transport initialization logic resides in [`crates/openlogi-ipc/src/transport.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-ipc/src/transport.rs) and is reused by both endpoints.
- **Server entry** – The agent binary starts the IPC server in [`openlogi-agent/src/server.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/openlogi-agent/src/server.rs), binding the transport endpoint and running the generated `AgentServer` event loop.

Clients obtain connections through `AgentClient::connect` implemented in [`crates/openlogi-ipc/src/client.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-ipc/src/client.rs), creating a strongly-typed handle to the agent API.

## Protocol Versioning and Compatibility

OpenLogi enforces strict versioning to prevent client-server mismatches. The first method in the `Agent` trait, `protocol_version`, returns a constant `PROTOCOL_VERSION` (currently set to **29**) defined in the IPC crate.

Because tarpc encodes the *order* of trait methods as the variant index in the generated protocol, new RPC methods are **always appended** to the trait definition to preserve backward compatibility. The complete method list spans lines 38-64 of [`crates/openlogi-ipc/src/ipc.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-ipc/src/ipc.rs). Historic methods like `next_pairing` and `next_action_ring` (lines 85-96) remain in the trait even after being superseded by versioned state fields, ensuring the wire format remains stable for older clients.

## State Observation Pattern

Rather than using pub-sub channels or replay buffers, the GUI receives live state updates through a **level-triggered `observe` method** (lines 50-55 of [`crates/openlogi-ipc/src/ipc.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-ipc/src/ipc.rs)). This design implements a generation-based long-polling mechanism:

1. The client passes the last seen **generation** number (a monotonic `u64`).
2. The agent blocks internally until the observable state changes or a hold timeout expires.
3. The agent returns a complete `Observation` struct containing the full `AgentSnapshot` and the new generation.

This pattern eliminates the complexity of managing subscription handles or ring buffers. The state structs—including `AgentSnapshot`, `Observation`, and `RingObservation`—are defined in lines 26-55 of the IPC contract.

## Client Identification and Connection Management

The agent distinguishes between connection types using the `declare_client` RPC (lines 58-64). GUI, overlay, and CLI clients each call this method immediately after connecting to identify themselves, allowing the agent to arm specific features or remain dormant accordingly.

The connection flow is type-safe from end to end: `AgentClient::connect` returns a future that resolves to a client handle capable of calling any method defined in the `Agent` trait, with all parameters and return values validated at compile time.

## Implementation Examples

To obtain the protocol version from the GUI process:

```rust
// In the GUI (openlogi-desktop)
let client = openlogi_ipc::client::AgentClient::connect().await?;
let version = client.protocol_version().await?;
assert_eq!(version, openlogi_ipc::PROTOCOL_VERSION);

```

To observe agent state changes using the generation-based long-poll:

```rust
let mut gen = 0u64;
loop {
    let obs = client.observe(gen).await?;
    // `obs` contains a complete `AgentSnapshot` – handle UI updates here
    gen = obs.generation;  // Next request waits for a state change
}

```

To start the IPC server in the agent binary:

```rust
// In openlogi-agent/src/server.rs (simplified)
use openlogi_ipc::transport::LocalSocket;
let listener = LocalSocket::bind("/tmp/openlogi.ipc")?;
let server = openlogi_ipc::AgentServer::new(AgentImpl::default());
tarpc::server::new(server).incoming(listener).await?;

```

## Summary

- **Transport layer** – Uses `interprocess` local sockets (Unix domain sockets or named pipes) configured in [`crates/openlogi-ipc/src/transport.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-ipc/src/transport.rs).
- **Serialization** – Bincode provides compact binary encoding for all RPC messages.
- **Version safety** – Protocol version 29 is enforced via the `protocol_version` method, with new methods appended to the trait to maintain compatibility.
- **State sync** – The `observe` method implements level-triggered, generation-based long-polling defined at lines 50-55 of [`crates/openlogi-ipc/src/ipc.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-ipc/src/ipc.rs).
- **Type safety** – The tarpc-generated `AgentClient` and `AgentServer` ensure compile-time validation of all inter-process calls.

## Frequently Asked Questions

### How does OpenLogi handle IPC between the agent and GUI?

OpenLogi uses a tarpc-based RPC layer where the agent runs a server from [`openlogi-agent/src/server.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/openlogi-agent/src/server.rs) and the GUI obtains a typed client via `AgentClient::connect` in [`crates/openlogi-ipc/src/client.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-ipc/src/client.rs). All communication occurs over local sockets provided by the `interprocess` crate, ensuring low-latency, platform-native IPC.

### What serialization format does OpenLogi use for RPC messages?

OpenLogi serializes all RPC calls using **bincode**, a compact binary format. This is configured as the codec for the tarpc transport, providing efficient encoding for structs like `AgentSnapshot` and `Observation` defined in [`crates/openlogi-ipc/src/ipc.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-ipc/src/ipc.rs).

### How does the GUI receive real-time state updates without polling?

The GUI uses the `observe` method (lines 50-55), which accepts a generation number and blocks until the agent state changes. This level-triggered approach returns the full `AgentSnapshot` in a single response, eliminating the need for separate subscription management or replay buffers.

### Why does the order of methods in the IPC trait matter?

Because tarpc encodes trait methods as ordered variants in the wire protocol, changing the order would break binary compatibility. OpenLogi maintains protocol stability by appending new methods to the end of the `Agent` trait defined in [`crates/openlogi-ipc/src/ipc.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-ipc/src/ipc.rs) and preserving obsolete methods to support older clients.